diff options
author | Alexander Pinzon <apinzonf@gmail.com> | 2013-10-08 23:08:21 +0400 |
---|---|---|
committer | Alexander Pinzon <apinzonf@gmail.com> | 2013-10-08 23:08:21 +0400 |
commit | 6b3a34d2c96c9b10e3a28bdfcb07518302c07ff2 (patch) | |
tree | dac72c7563008479dd213626d3047afdf10eaa4b /source | |
parent | d57f58cfc6c373da71ab071e4313096373e67cf7 (diff) | |
parent | 0973270fbf43c8ab85423a0dd0dcab39d434e644 (diff) |
svn merge ^/trunk/blender 59138:60616
Diffstat (limited to 'source')
987 files changed, 33084 insertions, 21923 deletions
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 529aaac4923..391fdf42d28 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -28,9 +28,5 @@ add_subdirectory(blender) if(WITH_GAMEENGINE) add_subdirectory(gameengine) endif() - -if(WINDOWS) - add_subdirectory(icons) -endif() add_subdirectory(tests) diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 15098d50531..d46df829295 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -50,6 +50,7 @@ #include "BLI_string_utf8.h" #include "BLI_threads.h" #include "BLI_linklist.h" /* linknode */ +#include "BLI_strict_flags.h" #include "BIF_gl.h" #include "BLF_api.h" @@ -59,10 +60,6 @@ #include "blf_internal_types.h" #include "blf_internal.h" -#ifdef __GNUC__ -# pragma GCC diagnostic error "-Wsign-conversion" -#endif - /* freetype2 handle ONLY for this file!. */ static FT_Library ft_lib; static SpinLock ft_lib_mutex; @@ -163,7 +160,7 @@ static void blf_font_ensure_ascii_table(FontBLF *font) _kern_mode, \ &(_delta)) == 0) \ { \ - _pen_x += _delta.x >> 6; \ + _pen_x += (int)_delta.x >> 6; \ } \ } \ } (void)0 @@ -194,7 +191,7 @@ void blf_font_draw(FontBLF *font, const char *str, size_t len) /* do not return this loop if clipped, we want every character tested */ blf_glyph_render(font, g, (float)pen_x, (float)pen_y); - pen_x += g->advance; + pen_x += (int)g->advance; g_prev = g; } } @@ -221,7 +218,7 @@ void blf_font_draw_ascii(FontBLF *font, const char *str, size_t len) /* do not return this loop if clipped, we want every character tested */ blf_glyph_render(font, g, (float)pen_x, (float)pen_y); - pen_x += g->advance; + pen_x += (int)g->advance; g_prev = g; } } @@ -273,10 +270,11 @@ void blf_font_buffer(FontBLF *font, const char *str) /* buffer specific vars */ FontBufInfoBLF *buf_info = &font->buf_info; float b_col_float[4]; - const unsigned char b_col_char[4] = {buf_info->col[0] * 255, - buf_info->col[1] * 255, - buf_info->col[2] * 255, - buf_info->col[3] * 255}; + const unsigned char b_col_char[4] = { + (unsigned char)(buf_info->col[0] * 255), + (unsigned char)(buf_info->col[1] * 255), + (unsigned char)(buf_info->col[2] * 255), + (unsigned char)(buf_info->col[3] * 255)}; unsigned char *cbuf; int chx, chy; @@ -378,14 +376,27 @@ void blf_font_buffer(FontBLF *font, const char *str) cbuf[0] = b_col_char[0]; cbuf[1] = b_col_char[1]; cbuf[2] = b_col_char[2]; - cbuf[3] = (alphatest = ((int)cbuf[3] + (int)b_col_char[3])) < 255 ? alphatest : 255; + + alphatest = (int)cbuf[3] + (int)b_col_char[3]; + if (alphatest < 255) { + cbuf[3] = (unsigned char)(alphatest); + } + else { + cbuf[3] = 255; + } } else { - cbuf[0] = (b_col_char[0] * a) + (cbuf[0] * (1.0f - a)); - cbuf[1] = (b_col_char[1] * a) + (cbuf[1] * (1.0f - a)); - cbuf[2] = (b_col_char[2] * a) + (cbuf[2] * (1.0f - a)); - cbuf[3] = (alphatest = ((int)cbuf[3] + (int)((b_col_float[3] * a) * 255.0f))) < - 255 ? alphatest : 255; + cbuf[0] = (unsigned char)((b_col_char[0] * a) + (cbuf[0] * (1.0f - a))); + cbuf[1] = (unsigned char)((b_col_char[1] * a) + (cbuf[1] * (1.0f - a))); + cbuf[2] = (unsigned char)((b_col_char[2] * a) + (cbuf[2] * (1.0f - a))); + + alphatest = ((int)cbuf[3] + (int)((b_col_float[3] * a) * 255.0f)); + if (alphatest < 255) { + cbuf[3] = (unsigned char)(alphatest); + } + else { + cbuf[3] = 255; + } } } } @@ -398,7 +409,7 @@ void blf_font_buffer(FontBLF *font, const char *str) } } - pen_x += g->advance; + pen_x += (int)g->advance; g_prev = g; } } @@ -433,10 +444,10 @@ void blf_font_boundbox(FontBLF *font, const char *str, rctf *box) if (has_kerning) BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); - gbox.xmin = pen_x; - gbox.xmax = pen_x + g->advance; - gbox.ymin = g->box.ymin + pen_y; - gbox.ymax = g->box.ymax + pen_y; + gbox.xmin = (float)pen_x; + gbox.xmax = (float)pen_x + g->advance; + gbox.ymin = g->box.ymin + (float)pen_y; + gbox.ymax = g->box.ymax + (float)pen_y; if (gbox.xmin < box->xmin) box->xmin = gbox.xmin; if (gbox.ymin < box->ymin) box->ymin = gbox.ymin; @@ -444,7 +455,7 @@ void blf_font_boundbox(FontBLF *font, const char *str, rctf *box) if (gbox.xmax > box->xmax) box->xmax = gbox.xmax; if (gbox.ymax > box->ymax) box->ymax = gbox.ymax; - pen_x += g->advance; + pen_x += (int)g->advance; g_prev = g; } @@ -524,9 +535,7 @@ void blf_font_free(FontBLF *font) GlyphCacheBLF *gc; font->glyph_cache = NULL; - while (font->cache.first) { - gc = font->cache.first; - BLI_remlink(&font->cache, gc); + while ((gc = BLI_pophead(&font->cache))) { blf_glyph_cache_free(gc); } diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 37e874fa396..2a8e91299b4 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -56,9 +56,7 @@ #include "blf_internal_types.h" #include "blf_internal.h" -#ifdef __GNUC__ -# pragma GCC diagnostic error "-Wsign-conversion" -#endif +#include "BLI_strict_flags.h" GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, unsigned int size, unsigned int dpi) { @@ -89,28 +87,28 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) gc->textures = (GLuint *)MEM_mallocN(sizeof(GLuint) * 256, __func__); gc->ntex = 256; - gc->cur_tex = -1; + gc->cur_tex = BLF_CURTEX_UNSET; gc->x_offs = 0; gc->y_offs = 0; gc->pad = 3; - gc->num_glyphs = font->face->num_glyphs; - gc->rem_glyphs = font->face->num_glyphs; + gc->num_glyphs = (int)font->face->num_glyphs; + gc->rem_glyphs = (int)font->face->num_glyphs; gc->ascender = ((float)font->face->size->metrics.ascender) / 64.0f; gc->descender = ((float)font->face->size->metrics.descender) / 64.0f; if (FT_IS_SCALABLE(font->face)) { - gc->max_glyph_width = (float)((font->face->bbox.xMax - font->face->bbox.xMin) * - (((float)font->face->size->metrics.x_ppem) / - ((float)font->face->units_per_EM))); + gc->max_glyph_width = (int)((float)(font->face->bbox.xMax - font->face->bbox.xMin) * + (((float)font->face->size->metrics.x_ppem) / + ((float)font->face->units_per_EM))); - gc->max_glyph_height = (float)((font->face->bbox.yMax - font->face->bbox.yMin) * - (((float)font->face->size->metrics.y_ppem) / - ((float)font->face->units_per_EM))); + gc->max_glyph_height = (int)((float)(font->face->bbox.yMax - font->face->bbox.yMin) * + (((float)font->face->size->metrics.y_ppem) / + ((float)font->face->units_per_EM))); } else { - gc->max_glyph_width = ((float)font->face->size->metrics.max_advance) / 64.0f; - gc->max_glyph_height = ((float)font->face->size->metrics.height) / 64.0f; + gc->max_glyph_width = (int)(((float)font->face->size->metrics.max_advance) / 64.0f); + gc->max_glyph_height = (int)(((float)font->face->size->metrics.height) / 64.0f); } gc->p2_width = 0; @@ -128,9 +126,7 @@ void blf_glyph_cache_clear(FontBLF *font) for (gc = font->cache.first; gc; gc = gc->next) { for (i = 0; i < 257; i++) { - while (gc->bucket[i].first) { - g = gc->bucket[i].first; - BLI_remlink(&(gc->bucket[i]), g); + while ((g = BLI_pophead(&gc->bucket[i]))) { blf_glyph_free(g); } } @@ -145,15 +141,13 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc) int i; for (i = 0; i < 257; i++) { - while (gc->bucket[i].first) { - g = gc->bucket[i].first; - BLI_remlink(&(gc->bucket[i]), g); + while ((g = BLI_pophead(&gc->bucket[i]))) { blf_glyph_free(g); } } - if (gc->cur_tex > -1) - glDeleteTextures(gc->cur_tex + 1, gc->textures); + if (gc->cur_tex != BLF_CURTEX_UNSET) + glDeleteTextures((int)gc->cur_tex + 1, gc->textures); MEM_freeN((void *)gc->textures); MEM_freeN(gc); } @@ -287,7 +281,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c) /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */ int i; for (i = 0; i < (g->width * g->height); i++) { - bitmap.buffer[i] = 255 * bitmap.buffer[i]; + bitmap.buffer[i] = bitmap.buffer[i] ? 255 : 0; } } @@ -296,8 +290,8 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c) } g->advance = ((float)slot->advance.x) / 64.0f; - g->pos_x = slot->bitmap_left; - g->pos_y = slot->bitmap_top; + g->pos_x = (float)slot->bitmap_left; + g->pos_y = (float)slot->bitmap_top; g->pitch = slot->bitmap.pitch; FT_Outline_Get_CBox(&(slot->outline), &bbox); @@ -351,7 +345,7 @@ static void blf_texture5_draw(const float shadow_col[4], float uv[2][2], float x const float *fp = soft; float color[4]; - int dx, dy; + float dx, dy; color[0] = shadow_col[0]; color[1] = shadow_col[1]; @@ -376,7 +370,7 @@ static void blf_texture3_draw(const float shadow_col[4], float uv[2][2], float x const float *fp = soft; float color[4]; - int dx, dy; + float dx, dy; color[0] = shadow_col[0]; color[1] = shadow_col[1]; @@ -395,10 +389,10 @@ static void blf_texture3_draw(const float shadow_col[4], float uv[2][2], float x static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y) { - rect->xmin = floor(x + g->pos_x); - rect->xmax = rect->xmin + g->width; + rect->xmin = (float)floor(x + g->pos_x); + rect->xmax = rect->xmin + (float)g->width; rect->ymin = y + g->pos_y; - rect->ymax = y + g->pos_y - g->height; + rect->ymax = y + g->pos_y - (float)g->height; } void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) @@ -414,7 +408,7 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) if (font->max_tex_size == -1) glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&font->max_tex_size); - if (gc->cur_tex == -1) { + if (gc->cur_tex == BLF_CURTEX_UNSET) { blf_glyph_cache_texture(font, gc); gc->x_offs = gc->pad; gc->y_offs = 0; @@ -462,7 +456,7 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) g->uv[1][1] = ((float)(g->yoff + g->height)) / ((float)gc->p2_height); /* update the x offset for the next glyph. */ - gc->x_offs += (int)(BLI_rctf_size_x(&g->box) + gc->pad); + gc->x_offs += (int)BLI_rctf_size_x(&g->box) + gc->pad; gc->rem_glyphs--; g->build_tex = 1; @@ -486,7 +480,9 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) if (font->flags & BLF_SHADOW) { rctf rect_ofs; - blf_glyph_calc_rect(&rect_ofs, g, x + font->shadow_x, y + font->shadow_y); + blf_glyph_calc_rect(&rect_ofs, g, + x + (float)font->shadow_x, + y + (float)font->shadow_y); switch (font->shadow) { case 3: diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 096ff50a3ca..c64b7e974e7 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -54,7 +54,7 @@ typedef struct GlyphCacheBLF { unsigned int ntex; /* and the last texture, aka. the current texture. */ - int cur_tex; + unsigned int cur_tex; /* like bftgl, we draw every glyph in a big texture, so this is the * current position inside the texture. @@ -235,4 +235,6 @@ typedef struct DirBLF { char *path; } DirBLF; +#define BLF_CURTEX_UNSET ((unsigned int)-1) + #endif /* __BLF_INTERNAL_TYPES_H__ */ diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 8396380fd06..2bba968e03b 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -28,7 +28,9 @@ #ifndef __BKE_DERIVEDMESH_H__ #define __BKE_DERIVEDMESH_H__ -/** +/** \file BKE_DerivedMesh.h + * \ingroup bke + * * Basic design of the DerivedMesh system: * * DerivedMesh is a common set of interfaces for mesh systems. @@ -72,6 +74,8 @@ #include "DNA_customdata_types.h" #include "DNA_meshdata_types.h" +#include "BLI_compiler_attrs.h" + #include "BKE_customdata.h" #include "BKE_bvhutils.h" @@ -95,8 +99,6 @@ struct BMEditMesh; struct ListBase; struct PBVH; -#define DM_OMP_LIMIT 10000 /* setting zero so we can catch bugs in OpenMP/BMesh */ - /* number of sub-elements each mesh element has (for interpolation) */ #define SUB_ELEMS_VERT 0 #define SUB_ELEMS_EDGE 2 @@ -733,14 +735,12 @@ void DM_init_origspace(DerivedMesh *dm); char *DM_debug_info(DerivedMesh *dm); void DM_debug_print(DerivedMesh *dm); void DM_debug_print_cdlayers(CustomData *cdata); -#endif -#ifdef __GNUC__ -BLI_INLINE int DM_origindex_mface_mpoly(const int *index_mf_to_mpoly, const int *index_mp_to_orig, const int i) - __attribute__((nonnull(1))) -; +bool DM_is_valid(DerivedMesh *dm); #endif +BLI_INLINE int DM_origindex_mface_mpoly(const int *index_mf_to_mpoly, const int *index_mp_to_orig, const int i) ATTR_NONNULL(1); + BLI_INLINE int DM_origindex_mface_mpoly(const int *index_mf_to_mpoly, const int *index_mp_to_orig, const int i) { const int j = index_mf_to_mpoly[i]; diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 12c9f6b449f..698098d28c3 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -188,6 +188,10 @@ struct bPoseChannel *BKE_pose_channel_active(struct Object *ob); */ struct bPoseChannel *BKE_pose_channel_verify(struct bPose *pose, const char *name); +#ifndef NDEBUG +bool BKE_pose_channels_is_valid(const struct bPose *pose); +#endif + /* Copy the data from the action-pose (src) into the pose */ void extract_pose_from_pose(struct bPose *pose, const struct bPose *src); @@ -203,6 +207,9 @@ void BKE_pose_ikparam_init(struct bPose *pose); /* initialize a bItasc structure with default value */ void BKE_pose_itasc_init(struct bItasc *itasc); +/* Checks if a bone is part of an IK chain or not */ +bool BKE_pose_channel_in_IK_chain(struct Object *ob, struct bPoseChannel *pchan); + /* clears BONE_UNKEYED flags for frame changing */ // XXX to be deprecated for a more general solution in animsys... void framechange_poses_clear_unkeyed(void); diff --git a/source/blender/blenkernel/BKE_addon.h b/source/blender/blenkernel/BKE_addon.h index eafaec3e605..739a4e3eee6 100644 --- a/source/blender/blenkernel/BKE_addon.h +++ b/source/blender/blenkernel/BKE_addon.h @@ -22,6 +22,10 @@ #ifndef __BKE_ADDON_H__ #define __BKE_ADDON_H__ +/** \file BKE_addon.h + * \ingroup bke + */ + #include "RNA_types.h" typedef struct bAddonPrefType { diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h index 539c5780cd5..7de7a745ed6 100644 --- a/source/blender/blenkernel/BKE_anim.h +++ b/source/blender/blenkernel/BKE_anim.h @@ -59,7 +59,7 @@ void animviz_calc_motionpaths(struct Scene *scene, ListBase *targets); /* Curve Paths */ void free_path(struct Path *path); -void calc_curvepath(struct Object *ob); +void calc_curvepath(struct Object *ob, struct ListBase *nurbs); int where_on_path(struct Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius, float *weight); /* ---------------------------------------------------- */ diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index dd150ba6a63..f0f6b5a2319 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -112,6 +112,9 @@ void BKE_animdata_fix_paths_rename(struct ID *owner_id, struct AnimData *adt, st /* Fix all the paths for the entire database... */ void BKE_all_animdata_fix_paths_rename(ID *ref_id, const char *prefix, const char *oldName, const char *newName); +/* Fix the path after removing elements that are not ID (e.g., node) */ +void BKE_animdata_fix_paths_remove(struct ID *id, const char *path); + /* -------------------------------------- */ /* Move animation data from src to destination if it's paths are based on basepaths */ diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index fb9e9f4e691..60e03af5077 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -124,16 +124,18 @@ void BKE_pchan_to_pose_mat(struct bPoseChannel *pchan, float rotscale_mat[4][4], void BKE_rotMode_change_values(float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode); /* B-Bone support */ +#define MAX_BBONE_SUBDIV 32 + typedef struct Mat4 { float mat[4][4]; } Mat4; -Mat4 *b_bone_spline_setup(struct bPoseChannel *pchan, int rest); +void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV]); /* like EBONE_VISIBLE */ #define PBONE_VISIBLE(arm, bone) ( \ - CHECK_TYPE_INLINE(arm, bArmature), \ - CHECK_TYPE_INLINE(bone, Bone), \ + CHECK_TYPE_INLINE(arm, bArmature *), \ + CHECK_TYPE_INLINE(bone, Bone *), \ (((bone)->layer & (arm)->layer) && !((bone)->flag & BONE_HIDDEN_P)) \ ) diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 84e24df43e5..5b32e7229d5 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -41,15 +41,15 @@ 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 268 -#define BLENDER_SUBVERSION 2 +#define BLENDER_VERSION 269 +#define BLENDER_SUBVERSION 1 /* 262 was the last editmesh release but it has compatibility code for bmesh data */ #define BLENDER_MINVERSION 262 #define BLENDER_MINSUBVERSION 0 /* used by packaging tools */ /* can be left blank, otherwise a,b,c... etc with no quotes */ -#define BLENDER_VERSION_CHAR a +#define BLENDER_VERSION_CHAR /* alpha/beta/rc/release, docs use this */ #define BLENDER_VERSION_CYCLE alpha @@ -69,8 +69,10 @@ int BKE_read_file(struct bContext *C, const char *filepath, struct ReportList *r #define BKE_READ_FILE_OK 1 /* OK */ #define BKE_READ_FILE_OK_USERPREFS 2 /* OK, and with new user settings */ -int BKE_read_file_from_memory(struct bContext *C, const void *filebuf, int filelength, struct ReportList *reports); -int BKE_read_file_from_memfile(struct bContext *C, struct MemFile *memfile, struct ReportList *reports); +int BKE_read_file_from_memory(struct bContext *C, const void *filebuf, + int filelength, struct ReportList *reports, int update_defaults); +int BKE_read_file_from_memfile(struct bContext *C, struct MemFile *memfile, + struct ReportList *reports); int BKE_read_file_userdef(const char *filepath, struct ReportList *reports); int BKE_write_file_userdef(const char *filepath, struct ReportList *reports); @@ -100,11 +102,11 @@ extern const char *BKE_undo_get_name(int nr, int *active); extern int BKE_undo_save_file(const char *filename); extern struct Main *BKE_undo_get_main(struct Scene **scene); - /* copybuffer */ +/* copybuffer */ void BKE_copybuffer_begin(void); void BKE_copybuffer_tag_ID(struct ID *id); int BKE_copybuffer_save(const char *filename, struct ReportList *reports); - int BKE_copybuffer_paste(struct bContext *C, const char *libname, struct ReportList *reports); +int BKE_copybuffer_paste(struct bContext *C, const char *libname, struct ReportList *reports); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index edf710ef7c9..b4c5f47cf25 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -76,10 +76,10 @@ float BKE_brush_sample_masktex(const Scene *scene, struct Brush *br, const float const int thread, struct ImagePool *pool); /* texture */ -unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side); +unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool use_secondary); /* radial control */ -struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br); +struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, bool secondary); /* unified strength and size */ diff --git a/source/blender/blenkernel/BKE_ccg.h b/source/blender/blenkernel/BKE_ccg.h index fb6211504ae..7d5d423282d 100644 --- a/source/blender/blenkernel/BKE_ccg.h +++ b/source/blender/blenkernel/BKE_ccg.h @@ -28,6 +28,10 @@ #ifndef __BKE_CCG_H__ #define __BKE_CCG_H__ +/** \file BKE_ccg.h + * \ingroup bke + */ + /* defines BLI_INLINE */ #include "BLI_utildefines.h" diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index 947e680d119..1b61d0a5443 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -80,7 +80,7 @@ typedef struct Cloth { struct MFace *mfaces; struct Implicit_Data *implicit; /* our implicit solver connects to this pointer */ struct Implicit_Data *implicitEM; /* our implicit solver connects to this pointer */ - struct EdgeHash *edgehash; /* used for selfcollisions */ + struct EdgeHash *edgehash; /* used for selfcollisions (currently used as a 'set', value is ignored) */ int last_frame, pad4; } Cloth; diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index baa90e7a856..07116979eab 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -42,6 +42,13 @@ struct Main; struct Nurb; struct Object; struct Scene; +struct Path; + +typedef struct CurveCache { + ListBase disp; + ListBase bev; + struct Path *path; +} CurveCache; #define KNOTSU(nu) ( (nu)->orderu + (nu)->pntsu + (((nu)->flagu & CU_NURB_CYCLIC) ? ((nu)->orderu - 1) : 0) ) #define KNOTSV(nu) ( (nu)->orderv + (nu)->pntsv + (((nu)->flagv & CU_NURB_CYCLIC) ? ((nu)->orderv - 1) : 0) ) @@ -63,7 +70,11 @@ void BKE_curve_make_local(struct Curve *cu); short BKE_curve_type_get(struct Curve *cu); void BKE_curve_type_test(struct Object *ob); void BKE_curve_curve_dimension_update(struct Curve *cu); + +void BKE_curve_boundbox_calc(struct Curve *cu, float r_loc[3], float r_size[3]); +struct BoundBox *BKE_curve_boundbox_get(struct Object *ob); void BKE_curve_texspace_calc(struct Curve *cu); +void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_rot[3], float r_size[3]); bool BKE_curve_minmax(struct Curve *cu, float min[3], float max[3]); bool BKE_curve_center_median(struct Curve *cu, float cent[3]); @@ -74,11 +85,11 @@ void BKE_curve_material_index_clear(struct Curve *cu); ListBase *BKE_curve_nurbs_get(struct Curve *cu); -float (*BKE_curve_vertexCos_get(struct Curve *cu, struct ListBase *lb, int *numVerts_r))[3]; -void BK_curve_vertexCos_apply(struct Curve *cu, struct ListBase *lb, float (*vertexCos)[3]); +float (*BKE_curve_nurbs_vertexCos_get(struct ListBase *lb, int *numVerts_r))[3]; +void BK_curve_nurbs_vertexCos_apply(struct ListBase *lb, float (*vertexCos)[3]); -float (*BKE_curve_keyVertexCos_get(struct Curve *cu, struct ListBase *lb, float *key))[3]; -void BKE_curve_keyVertexTilts_apply(struct Curve *cu, struct ListBase *lb, float *key); +float (*BKE_curve_nurbs_keyVertexCos_get(struct ListBase *lb, float *key))[3]; +void BKE_curve_nurbs_keyVertexTilts_apply(struct ListBase *lb, float *key); void BKE_curve_editNurb_keyIndex_free(struct EditNurb *editnurb); void BKE_curve_editNurb_free(struct Curve *cu); @@ -87,7 +98,7 @@ struct ListBase *BKE_curve_editNurbs_get(struct Curve *cu); float *BKE_curve_make_orco(struct Scene *scene, struct Object *ob, int *r_numVerts); float *BKE_curve_surf_make_orco(struct Object *ob); -void BKE_curve_bevelList_make(struct Object *ob); +void BKE_curve_bevelList_make(struct Object *ob, struct ListBase *nurbs, bool for_render); void BKE_curve_bevel_make(struct Scene *scene, struct Object *ob, struct ListBase *disp, int forRender, int renderResolution); void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride); @@ -104,6 +115,7 @@ void BKE_nurbList_duplicate(struct ListBase *lb1, struct ListBase *lb2); void BKE_nurbList_handles_set(struct ListBase *editnurb, short code); void BKE_nurbList_handles_autocalc(ListBase *editnurb, int flag); +void BKE_nurbList_flag_set(ListBase *editnurb, short flag); void BKE_nurb_free(struct Nurb *nu); struct Nurb *BKE_nurb_duplicate(struct Nurb *nu); @@ -139,9 +151,11 @@ void BKE_nurb_bezt_calc_normal(struct Nurb *nu, struct BezTriple *bezt, float r_ void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_plane[3]); void BKE_nurb_handle_calc(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next, int mode); +void BKE_nurb_handle_calc_simple(struct Nurb *nu, struct BezTriple *bezt); void BKE_nurb_handles_calc(struct Nurb *nu); void BKE_nurb_handles_autocalc(struct Nurb *nu, int flag); -void BKE_nurb_handles_test(struct Nurb *nu); +void BKE_nurb_bezt_handle_test(struct BezTriple *bezt, const bool use_handle); +void BKE_nurb_handles_test(struct Nurb *nu, const bool use_handles); #endif /* __BKE_CURVE_H__ */ diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 72aae1b2361..5a283922707 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -56,6 +56,7 @@ extern const CustomDataMask CD_MASK_EDITMESH; extern const CustomDataMask CD_MASK_DERIVEDMESH; extern const CustomDataMask CD_MASK_BMESH; extern const CustomDataMask CD_MASK_FACECORNERS; +extern const CustomDataMask CD_MASK_EVERYTHING; /* for ORIGINDEX layer type, indicates no original index for this element */ #define ORIGINDEX_NONE -1 @@ -191,6 +192,9 @@ void CustomData_set_only_copy(const struct CustomData *data, void CustomData_copy_data(const struct CustomData *source, struct CustomData *dest, int source_index, int dest_index, int count); +void CustomData_copy_data_named(const struct CustomData *source, + struct CustomData *dest, int source_index, + int dest_index, int count); void CustomData_copy_elements(int type, void *source, void *dest, int count); void CustomData_bmesh_copy_data(const struct CustomData *source, struct CustomData *dest, void *src_block, diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 1cf77c68345..2178f860825 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -102,4 +102,6 @@ float BKE_displist_calc_taper(struct Scene *scene, struct Object *taperobj, int /* add Orco layer to the displist object which has got derived mesh and return orco */ float *BKE_displist_make_orco(struct Scene *scene, struct Object *ob, struct DerivedMesh *derivedFinal, int forRender, int renderResolution); +void BKE_displist_minmax(struct ListBase *dispbase, float min[3], float max[3]); + #endif diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h index edfb501b590..738cd87dc39 100644 --- a/source/blender/blenkernel/BKE_editmesh.h +++ b/source/blender/blenkernel/BKE_editmesh.h @@ -23,6 +23,10 @@ #ifndef __BKE_EDITMESH_H__ #define __BKE_EDITMESH_H__ +/** \file BKE_editmesh.h + * \ingroup bke + */ + #include "BKE_customdata.h" #include "bmesh.h" diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h index 6750ee1ff3e..7b4ad4284c6 100644 --- a/source/blender/blenkernel/BKE_editmesh_bvh.h +++ b/source/blender/blenkernel/BKE_editmesh_bvh.h @@ -44,7 +44,7 @@ typedef struct BMBVHTree BMBVHTree; BMBVHTree *BKE_bmbvh_new(struct BMEditMesh *em, int flag, 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], +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]); /* 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], diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 64a6811bf51..c31dd745911 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -229,12 +229,13 @@ short calc_fcurve_bounds(struct FCurve *fcu, float *xmin, float *xmax, float *ym short fcurve_are_keyframes_usable(struct FCurve *fcu); /* Can keyframes be added to F-Curve? */ -short fcurve_is_keyframable(struct FCurve *fcu); +bool fcurve_is_keyframable(struct FCurve *fcu); +bool BKE_fcurve_is_protected(struct FCurve *fcu); /* -------- Curve Sanity -------- */ void calchandles_fcurve(struct FCurve *fcu); -void testhandles_fcurve(struct FCurve *fcu, const short use_handle); +void testhandles_fcurve(struct FCurve *fcu, const bool use_handle); void sort_time_fcurve(struct FCurve *fcu); short test_time_fcurve(struct FCurve *fcu); diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 133a0690dc6..71fd163a8ee 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -30,6 +30,8 @@ #include "DNA_ID.h" +#include "BLI_compiler_attrs.h" + struct IDProperty; struct ID; @@ -55,32 +57,14 @@ typedef union IDPropertyTemplate { /* ----------- Property Array Type ---------- */ -IDProperty *IDP_NewIDPArray(const char *name) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; -IDProperty *IDP_CopyIDPArray(IDProperty *array) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +IDProperty *IDP_NewIDPArray(const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +IDProperty *IDP_CopyIDPArray(IDProperty *array) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void IDP_FreeIDPArray(IDProperty *prop); /* shallow copies item */ -void IDP_SetIndexArray(struct IDProperty *prop, int index, struct IDProperty *item); -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -struct IDProperty *IDP_GetIndexArray(struct IDProperty *prop, int index) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +void IDP_SetIndexArray(struct IDProperty *prop, int index, struct IDProperty *item) ATTR_NONNULL(); +struct IDProperty *IDP_GetIndexArray(struct IDProperty *prop, int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void IDP_AppendArray(struct IDProperty *prop, struct IDProperty *item); void IDP_ResizeIDPArray(struct IDProperty *prop, int len); @@ -90,33 +74,11 @@ void IDP_ResizeArray(struct IDProperty *prop, int newlen); void IDP_FreeArray(struct IDProperty *prop); /* ---------- String Type ------------ */ -IDProperty *IDP_NewString(const char *st, const char *name, int maxlen) /* maxlen excludes '\0' */ -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull (2))) /* 'name' arg */ -#endif -; - -void IDP_AssignString(struct IDProperty *prop, const char *st, int maxlen) /* maxlen excludes '\0' */ -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; -void IDP_ConcatStringC(struct IDProperty *prop, const char *st) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; -void IDP_ConcatString(struct IDProperty *str1, struct IDProperty *append) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; -void IDP_FreeString(struct IDProperty *prop) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; +IDProperty *IDP_NewString(const char *st, const char *name, int maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2 /* 'name 'arg */); /* maxlen excludes '\0' */ +void IDP_AssignString(struct IDProperty *prop, const char *st, int maxlen) ATTR_NONNULL(); /* maxlen excludes '\0' */ +void IDP_ConcatStringC(struct IDProperty *prop, const char *st) ATTR_NONNULL(); +void IDP_ConcatString(struct IDProperty *str1, struct IDProperty *append) ATTR_NONNULL(); +void IDP_FreeString(struct IDProperty *prop) ATTR_NONNULL(); /*-------- ID Type -------*/ void IDP_LinkID(struct IDProperty *prop, ID *id); @@ -125,107 +87,30 @@ void IDP_UnlinkID(struct IDProperty *prop); /*-------- Group Functions -------*/ /** Sync values from one group to another, only where they match */ -void IDP_SyncGroupValues(struct IDProperty *dest, struct IDProperty *src) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; - -void IDP_ReplaceGroupInGroup(struct IDProperty *dest, struct IDProperty *src) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; -void IDP_ReplaceInGroup(struct IDProperty *group, struct IDProperty *prop) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; - -void IDP_MergeGroup(IDProperty *dest, IDProperty *src, const int do_overwrite) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; - -int IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; +void IDP_SyncGroupValues(struct IDProperty *dest, struct IDProperty *src) ATTR_NONNULL(); +void IDP_ReplaceGroupInGroup(struct IDProperty *dest, struct IDProperty *src) ATTR_NONNULL(); +void IDP_ReplaceInGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL(); +void IDP_MergeGroup(IDProperty *dest, IDProperty *src, const int do_overwrite) ATTR_NONNULL(); +int IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL(); int IDP_InsertToGroup(struct IDProperty *group, struct IDProperty *previous, - struct IDProperty *pnew) -#ifdef __GNUC__ -__attribute__((nonnull (1, 3))) /* 'group', 'pnew' */ -#endif -; -void IDP_RemFromGroup(struct IDProperty *group, struct IDProperty *prop) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; + struct IDProperty *pnew) ATTR_NONNULL(1 /* group */, 3 /* pnew */); +void IDP_RemFromGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL(); -IDProperty *IDP_GetPropertyFromGroup(struct IDProperty *prop, const char *name) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; -IDProperty *IDP_GetPropertyTypeFromGroup(struct IDProperty *prop, const char *name, const char type) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; -void *IDP_GetGroupIterator(struct IDProperty *prop) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -#endif -; -IDProperty *IDP_GroupIterNext(void *vself) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; -void IDP_FreeIterBeforeEnd(void *vself) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; +IDProperty *IDP_GetPropertyFromGroup(struct IDProperty *prop, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +IDProperty *IDP_GetPropertyTypeFromGroup(struct IDProperty *prop, const char *name, const char type) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void *IDP_GetGroupIterator(struct IDProperty *prop) ATTR_WARN_UNUSED_RESULT; +IDProperty *IDP_GroupIterNext(void *vself) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void IDP_FreeIterBeforeEnd(void *vself) ATTR_NONNULL(); /*-------- Main Functions --------*/ -struct IDProperty *IDP_GetProperties(struct ID *id, int create_if_needed) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; -struct IDProperty *IDP_CopyProperty(struct IDProperty *prop) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +struct IDProperty *IDP_GetProperties(struct ID *id, int create_if_needed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +struct IDProperty *IDP_CopyProperty(struct IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -int IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const int is_strict) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -#endif -; +int IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const int is_strict) ATTR_WARN_UNUSED_RESULT; -int IDP_EqualsProperties(struct IDProperty *prop1, struct IDProperty *prop2) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -#endif -; +int 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) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +struct IDProperty *IDP_New(const int 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_key.h b/source/blender/blenkernel/BKE_key.h index de60d316426..19264feaf48 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -41,6 +41,7 @@ struct Object; struct Scene; struct Lattice; struct Mesh; +struct WeightsArrayCache; /* Kernel prototypes */ #ifdef __cplusplus @@ -73,8 +74,17 @@ struct KeyBlock *BKE_keyblock_from_key(struct Key *key, int index); struct KeyBlock *BKE_keyblock_find_name(struct Key *key, const char name[]); void BKE_keyblock_copy_settings(struct KeyBlock *kb_dst, const struct KeyBlock *kb_src); char *BKE_keyblock_curval_rnapath_get(struct Key *key, struct KeyBlock *kb); + // needed for the GE -void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, struct Key *key, struct KeyBlock *actkb, const int mode); +typedef struct WeightsArrayCache { + int num_defgroup_weights; + float **defgroup_weights; +} WeightsArrayCache; + +float **BKE_keyblock_get_per_block_weights(struct Object *ob, struct Key *key, struct WeightsArrayCache *cache); +void BKE_keyblock_free_per_block_weights(struct Key *key, float **per_keyblock_weights, struct WeightsArrayCache *cache); +void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, struct Key *key, struct KeyBlock *actkb, + float **per_keyblock_weights, const int mode); /* conversion functions */ void BKE_key_convert_to_mesh(struct KeyBlock *kb, struct Mesh *me); diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h index 205c7c7d1e6..fb2c4da91ea 100644 --- a/source/blender/blenkernel/BKE_lamp.h +++ b/source/blender/blenkernel/BKE_lamp.h @@ -36,13 +36,15 @@ extern "C" { #endif +#include "BLI_compiler_attrs.h" + struct Lamp; struct Main; struct Scene; -struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) WARN_UNUSED; -struct Lamp *BKE_lamp_copy(struct Lamp *la) WARN_UNUSED; -struct Lamp *localize_lamp(struct Lamp *la) WARN_UNUSED; +struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT; +struct Lamp *BKE_lamp_copy(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; +struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; void BKE_lamp_make_local(struct Lamp *la); void BKE_lamp_free(struct Lamp *la); diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 9b29412675b..ba33da7729c 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -49,9 +49,14 @@ void BKE_lattice_free(struct Lattice *lt); void BKE_lattice_make_local(struct Lattice *lt); void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du); -void init_latt_deform(struct Object *oblatt, struct Object *ob); -void calc_latt_deform(struct Object *, float co[3], float weight); -void end_latt_deform(struct Object *); +struct LatticeDeformData; +struct LatticeDeformData *init_latt_deform(struct Object *oblatt, struct Object *ob) +#ifdef __GNUC__ +__attribute__((warn_unused_result)) +#endif +; +void calc_latt_deform(struct LatticeDeformData *lattice_deform_data, float co[3], float weight); +void end_latt_deform(struct LatticeDeformData *lattice_deform_data); int object_deform_mball(struct Object *ob, struct ListBase *dispbase); void outside_lattice(struct Lattice *lt); diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 3c5406c4a77..b8da5002d84 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -36,6 +36,8 @@ extern "C" { #endif +#include "BLI_compiler_attrs.h" + struct ListBase; struct ID; struct Main; @@ -45,24 +47,9 @@ struct bContext; struct PointerRNA; struct PropertyRNA; -void *BKE_libblock_alloc(struct ListBase *lb, short type, const char *name) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; -void *BKE_libblock_copy_ex(struct Main *bmain, struct ID *id) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; -void *BKE_libblock_copy(struct ID *id) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +void *BKE_libblock_alloc(struct ListBase *lb, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void *BKE_libblock_copy_ex(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void *BKE_libblock_copy(struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action); void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id); @@ -99,12 +86,7 @@ void rename_id(struct ID *id, const char *name); void name_uiprefix_id(char *name, const struct ID *id); void test_idbutton(char *name); void BKE_library_make_local(struct Main *bmain, struct Library *lib, bool untagged_only); -struct ID *BKE_libblock_find_name(const short type, const char *name) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void clear_id_newpoins(void); #if 0 diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index 92332116ba6..9e73e0662ce 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -28,6 +28,10 @@ #ifndef __BKE_MASK_H__ #define __BKE_MASK_H__ +/** \file BKE_mask.h + * \ingroup bke + */ + struct ImageUser; struct Image; struct ListBase; @@ -53,9 +57,11 @@ void BKE_mask_layer_active_set(struct Mask *mask, struct MaskLayer *masklay); void BKE_mask_layer_remove(struct Mask *mask, struct MaskLayer *masklay); void BKE_mask_layer_free_shapes(struct MaskLayer *masklay); +void BKE_mask_layer_free_deform(struct MaskLayer *mask_layer); void BKE_mask_layer_free(struct MaskLayer *masklay); void BKE_mask_layer_free_list(struct ListBase *masklayers); void BKE_mask_spline_free(struct MaskSpline *spline); +void BKE_mask_spline_free_list(struct ListBase *splines); struct MaskSpline *BKE_mask_spline_copy(struct MaskSpline *spline); void BKE_mask_point_free(struct MaskSplinePoint *point); @@ -134,6 +140,7 @@ void BKE_mask_layer_calc_handles_deform(struct MaskLayer *masklay); void BKE_mask_calc_handles(struct Mask *mask); void BKE_mask_update_deform(struct Mask *mask); void BKE_mask_spline_ensure_deform(struct MaskSpline *spline); +void BKE_mask_point_parent_matrix_get(struct MaskSplinePoint *point, float ctime, float parent_matrix[3][3]); /* animation */ int BKE_mask_layer_shape_totvert(struct MaskLayer *masklay); diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index f52dc030873..91c1715cca6 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -50,7 +50,7 @@ void init_def_material(void); void BKE_material_free(struct Material *sc); void BKE_material_free_ex(struct Material *ma, int do_id_user); void test_object_materials(struct Main *bmain, struct ID *id); -void resize_object_material(struct Object *ob, const short totcol); +void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user); void init_material(struct Material *ma); struct Material *BKE_material_add(struct Main *bmain, const char *name); struct Material *BKE_material_copy(struct Material *ma); @@ -87,6 +87,7 @@ int object_add_material_slot(struct Object *ob); int object_remove_material_slot(struct Object *ob); /* rna api */ +void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user); void BKE_material_append_id(struct ID *id, struct Material *ma); struct Material *BKE_material_pop_id(struct ID *id, int index, bool update_data); /* index is an int because of RNA */ void BKE_material_clear_id(struct ID *id, bool update_data); diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index 44459300c56..7665e1b54dc 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -47,7 +47,7 @@ void BKE_mball_make_local(struct MetaBall *mb); void BKE_mball_cubeTable_free(void); -void BKE_mball_polygonize(struct Scene *scene, struct Object *ob, struct ListBase *dispbase); +void BKE_mball_polygonize(struct Scene *scene, struct Object *ob, struct ListBase *dispbase, bool for_render); bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2); bool BKE_mball_is_basis(struct Object *ob); struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index e582af77d61..9e80a93fd63 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -31,8 +31,6 @@ * \ingroup bke */ -/***/ - struct ID; struct BoundBox; struct DispList; @@ -60,108 +58,31 @@ struct UvVertMap; struct UvMapVert; struct UvElementMap; struct UvElement; + #ifdef __cplusplus extern "C" { #endif -struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob); - -/* - * this function recreates a tessellation. - * returns number of tessellation faces. - * - * use_poly_origindex sets whether or not the tessellation faces' origindex - * layer should point to original poly indices or real poly indices. - * - * use_face_origindex sets the tessellation faces' origindex layer - * to point to the tessellation faces themselves, not the polys. - * - * if both of the above are 0, it'll use the indices of the mpolys of the MPoly - * data in pdata, and ignore the origindex layer altogether. - */ -int BKE_mesh_recalc_tessellation(struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, - struct MVert *mvert, - int totface, int totloop, int totpoly, - const bool do_face_normals); - -/* for forwards compat only quad->tri polys to mface, skip ngons. - */ -int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata, - struct CustomData *pdata, int totface, int totloop, int totpoly); - -/*calculates a face normal.*/ -void BKE_mesh_calc_poly_normal(struct MPoly *mpoly, struct MLoop *loopstart, - struct MVert *mvarray, float no[3]); - -void BKE_mesh_calc_poly_normal_coords(struct MPoly *mpoly, struct MLoop *loopstart, - const float (*vertex_coords)[3], float no[3]); - -void BKE_mesh_calc_poly_center(struct MPoly *mpoly, struct MLoop *loopstart, - struct MVert *mvarray, float cent[3]); - -float BKE_mesh_calc_poly_area(struct MPoly *mpoly, struct MLoop *loopstart, - struct MVert *mvarray, const float polynormal[3]); - -void BKE_mesh_calc_poly_angles(struct MPoly *mpoly, struct MLoop *loopstart, - struct MVert *mvarray, float angles[]); - -int *BKE_mesh_calc_smoothgroups(const struct MEdge *medge, const int totedge, - const struct MPoly *mpoly, const int totpoly, - const struct MLoop *mloop, const int totloop, - int *r_totgroup); +/* setting zero so we can catch bugs in OpenMP/BMesh */ +#ifdef DEBUG +# define BKE_MESH_OMP_LIMIT 0 +#else +# define BKE_MESH_OMP_LIMIT 10000 +#endif -void BKE_mesh_calc_relative_deform( - const struct MPoly *mpoly, const int totpoly, - const struct MLoop *mloop, const int totvert, +/* *** mesh.c *** */ - const float (*vert_cos_src)[3], - const float (*vert_cos_dst)[3], - - const float (*vert_cos_org)[3], - float (*vert_cos_new)[3]); +struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob); -/* Find the index of the loop in 'poly' which references vertex, - * returns -1 if not found */ int poly_find_loop_from_vert(const struct MPoly *poly, const struct MLoop *loopstart, unsigned vert); -/* Fill 'adj_r' with the loop indices in 'poly' adjacent to the - * vertex. Returns the index of the loop matching vertex, or -1 if the - * vertex is not in 'poly' */ int poly_get_adj_loops_from_vert(unsigned adj_r[3], const struct MPoly *poly, const struct MLoop *mloop, unsigned vert); -/* Return the index of the edge vert that is not equal to 'v'. If - * neither edge vertex is equal to 'v', returns -1. */ int BKE_mesh_edge_other_vert(const struct MEdge *e, int v); -/* update the hide flag for edges and polys from the corresponding - * flag in verts */ -void BKE_mesh_flush_hidden_from_verts_ex(const struct MVert *mvert, - const struct MLoop *mloop, - struct MEdge *medge, const int totedge, - struct MPoly *mpoly, const int totpoly); -void BKE_mesh_flush_hidden_from_verts(struct Mesh *me); - -void BKE_mesh_flush_hidden_from_polys_ex(struct MVert *mvert, - const struct MLoop *mloop, - struct MEdge *medge, const int totedge, - const struct MPoly *mpoly, const int totpoly); -void BKE_mesh_flush_hidden_from_polys(struct Mesh *me); - - -void BKE_mesh_flush_select_from_polys_ex(struct MVert *mvert, const int totvert, - const struct MLoop *mloop, - struct MEdge *medge, const int totedge, - const struct MPoly *mpoly, const int totpoly); -void BKE_mesh_flush_select_from_polys(struct Mesh *me); -void BKE_mesh_flush_select_from_verts_ex(const struct MVert *mvert, const int totvert, - const struct MLoop *mloop, - struct MEdge *medge, const int totedge, - struct MPoly *mpoly, const int totpoly); -void BKE_mesh_flush_select_from_verts(struct Mesh *me); - void BKE_mesh_unlink(struct Mesh *me); void BKE_mesh_free(struct Mesh *me, int unlink); struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name); @@ -191,64 +112,99 @@ void BKE_mesh_to_curve(struct Scene *scene, struct Object *ob); void BKE_mesh_material_index_remove(struct Mesh *me, short index); void BKE_mesh_material_index_clear(struct Mesh *me); void BKE_mesh_smooth_flag_set(struct Object *meshOb, int enableSmooth); -void BKE_mesh_convert_mfaces_to_mpolys(struct Mesh *mesh); -void BKE_mesh_do_versions_convert_mfaces_to_mpolys(struct Mesh *mesh); -void BKE_mesh_convert_mfaces_to_mpolys_ex(struct ID *id, - struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, - int totedge_i, int totface_i, int totloop_i, int totpoly_i, - struct MEdge *medge, struct MFace *mface, - int *totloop_r, int *totpoly_r, - struct MLoop **mloop_r, struct MPoly **mpoly_r); - -void BKE_mesh_calc_normals_tessface(struct MVert *mverts, int numVerts, struct MFace *mfaces, int numFaces, float (*faceNors_r)[3]); - -/* used for unit testing; compares two meshes, checking only - * differences we care about. should be usable with leaf's - * testing framework I get RNA work done, will use hackish - * testing code for now.*/ + const char *BKE_mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh); struct BoundBox *BKE_mesh_boundbox_get(struct Object *ob); void BKE_mesh_texspace_get(struct Mesh *me, float r_loc[3], float r_rot[3], float r_size[3]); void BKE_mesh_texspace_copy_from_object(struct Mesh *me, struct Object *ob); -/* if old, it converts mface->edcode to edge drawflags */ -void BKE_mesh_make_edges(struct Mesh *me, const bool use_old); +bool BKE_mesh_uv_cdlayer_rename_index(struct Mesh *me, const int poly_index, const int loop_index, const int face_index, + const char *new_name, const bool do_tessface); +bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const char *new_name, bool do_tessface); -void BKE_mesh_strip_loose_faces(struct Mesh *me); /* Needed for compatibility (some old read code). */ -void BKE_mesh_strip_loose_polysloops(struct Mesh *me); -void BKE_mesh_strip_loose_edges(struct Mesh *me); +float (*BKE_mesh_vertexCos_get(struct Mesh *me, int *r_numVerts))[3]; + +/* vertex level transformations & checks (no derived mesh) */ + +bool BKE_mesh_minmax(struct Mesh *me, float r_min[3], float r_max[3]); +void BKE_mesh_translate(struct Mesh *me, const float offset[3], const bool do_keys); + +void BKE_mesh_ensure_navmesh(struct Mesh *me); + +void BKE_mesh_tessface_calc(struct Mesh *mesh); +void BKE_mesh_tessface_ensure(struct Mesh *mesh); +void BKE_mesh_tessface_clear(struct Mesh *mesh); + +void BKE_mesh_do_versions_cd_flag_init(struct Mesh *mesh); + + +void BKE_mesh_mselect_clear(struct Mesh *me); +void BKE_mesh_mselect_validate(struct Mesh *me); +int BKE_mesh_mselect_find(struct Mesh *me, int index, int type); +int BKE_mesh_mselect_active_get(struct Mesh *me, int type); +void BKE_mesh_mselect_active_set(struct Mesh *me, int index, int type); + + + +/* *** mesh_evaluate.c *** */ -/* Calculate vertex and face normals, face normals are returned in *faceNors_r if non-NULL - * and vertex normals are stored in actual mverts. - */ void BKE_mesh_calc_normals_mapping( struct MVert *mverts, int numVerts, struct MLoop *mloop, struct MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3], struct MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3]); -/* extended version of 'BKE_mesh_calc_normals_poly' with option not to calc vertex normals */ void BKE_mesh_calc_normals_mapping_ex( struct MVert *mverts, int numVerts, struct MLoop *mloop, struct MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3], struct MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3], const bool only_face_normals); - void BKE_mesh_calc_normals_poly( struct MVert *mverts, int numVerts, struct MLoop *mloop, struct MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3], const bool only_face_normals); - void BKE_mesh_calc_normals(struct Mesh *me); +void BKE_mesh_calc_normals_tessface( + struct MVert *mverts, int numVerts, + struct MFace *mfaces, int numFaces, + float (*faceNors_r)[3]); +void BKE_mesh_normals_loop_split( + struct MVert *mverts, int numVerts, struct MEdge *medges, int numEdges, + struct MLoop *mloops, float (*r_loopnors)[3], int numLoops, + struct MPoly *mpolys, float (*polynors)[3], int numPolys, float split_angle); + +void BKE_mesh_calc_poly_normal( + struct MPoly *mpoly, struct MLoop *loopstart, + struct MVert *mvarray, float no[3]); +void BKE_mesh_calc_poly_normal_coords( + struct MPoly *mpoly, struct MLoop *loopstart, + const float (*vertex_coords)[3], float no[3]); +void BKE_mesh_calc_poly_center( + struct MPoly *mpoly, struct MLoop *loopstart, + struct MVert *mvarray, float cent[3]); +float BKE_mesh_calc_poly_area( + struct MPoly *mpoly, struct MLoop *loopstart, + struct MVert *mvarray, const float polynormal[3]); +void BKE_mesh_calc_poly_angles( + struct MPoly *mpoly, struct MLoop *loopstart, + struct MVert *mvarray, float angles[]); + +void BKE_mesh_poly_edgehash_insert( + struct EdgeHash *ehash, + const struct MPoly *mp, const struct MLoop *mloop); +void BKE_mesh_poly_edgebitmap_insert( + unsigned int *edge_bitmap, + const struct MPoly *mp, const struct MLoop *mloop); + + +bool BKE_mesh_center_median(struct Mesh *me, float cent[3]); +bool BKE_mesh_center_bounds(struct Mesh *me, float cent[3]); +bool BKE_mesh_center_centroid(struct Mesh *me, float cent[3]); -/* Return a newly MEM_malloc'd array of all the mesh vertex locations - * (_numVerts_r_ may be NULL) */ -float (*BKE_mesh_vertexCos_get(struct Mesh *me, int *r_numVerts))[3]; /* map from uv vertex to face (for select linked, stitch, uv suburf) */ /* UvVertMap */ - #define STD_UV_CONNECT_LIMIT 0.0001f typedef struct UvVertMap { @@ -302,46 +258,109 @@ typedef struct UvElementMap { * to make that many islands, he can bite me :p */ #define INVALID_ISLAND 0xFFFF -UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, - unsigned int totpoly, unsigned int totvert, int selected, float *limit); -UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v); -void BKE_mesh_uv_vert_map_free(UvVertMap *vmap); - /* Connectivity data */ typedef struct MeshElemMap { int *indices; int count; } MeshElemMap; - -typedef struct IndexNode { - struct IndexNode *next, *prev; - int index; -} IndexNode; -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); +/* mapping */ +UvVertMap *BKE_mesh_uv_vert_map_create( + struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, + unsigned int totpoly, unsigned int totvert, int selected, float *limit); +UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v); +void BKE_mesh_uv_vert_map_free(UvVertMap *vmap); -void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem, - const struct MEdge *medge, int totvert, int totedge); +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_edge_map_create( + MeshElemMap **r_map, int **r_mem, + const struct MEdge *medge, int totvert, int totedge); +void BKE_mesh_edge_poly_map_create( + MeshElemMap **r_map, int **r_mem, + const struct MEdge *medge, const int totedge, + const struct MPoly *mpoly, const int totpoly, + const struct MLoop *mloop, const int totloop); + +/* tessface */ +void BKE_mesh_loops_to_mface_corners( + struct CustomData *fdata, struct CustomData *ldata, + struct CustomData *pdata, int lindex[4], int findex, + const int polyindex, const int mf_len, + const int numTex, const int numCol, + const bool hasPCol, const bool hasOrigSpace); +int BKE_mesh_recalc_tessellation( + struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, + struct MVert *mvert, + int totface, int totloop, int totpoly, + const bool do_face_normals); +int BKE_mesh_mpoly_to_mface( + struct CustomData *fdata, struct CustomData *ldata, + struct CustomData *pdata, int totface, int totloop, int totpoly); +void BKE_mesh_convert_mfaces_to_mpolys(struct Mesh *mesh); +void BKE_mesh_do_versions_convert_mfaces_to_mpolys(struct Mesh *mesh); +void BKE_mesh_convert_mfaces_to_mpolys_ex( + struct ID *id, + struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, + int totedge_i, int totface_i, int totloop_i, int totpoly_i, + struct MEdge *medge, struct MFace *mface, + int *totloop_r, int *totpoly_r, + struct MLoop **mloop_r, struct MPoly **mpoly_r); + +/* flush flags */ +void BKE_mesh_flush_hidden_from_verts_ex( + const struct MVert *mvert, + const struct MLoop *mloop, + struct MEdge *medge, const int totedge, + struct MPoly *mpoly, const int totpoly); +void BKE_mesh_flush_hidden_from_verts(struct Mesh *me); +void BKE_mesh_flush_hidden_from_polys_ex( + struct MVert *mvert, + const struct MLoop *mloop, + struct MEdge *medge, const int totedge, + const struct MPoly *mpoly, const int totpoly); +void BKE_mesh_flush_hidden_from_polys(struct Mesh *me); +void BKE_mesh_flush_select_from_polys_ex( + struct MVert *mvert, const int totvert, + const struct MLoop *mloop, + struct MEdge *medge, const int totedge, + const struct MPoly *mpoly, const int totpoly); +void BKE_mesh_flush_select_from_polys(struct Mesh *me); +void BKE_mesh_flush_select_from_verts_ex( + const struct MVert *mvert, const int totvert, + const struct MLoop *mloop, + struct MEdge *medge, const int totedge, + struct MPoly *mpoly, const int totpoly); +void BKE_mesh_flush_select_from_verts(struct Mesh *me); -void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map, int **r_mem, - const struct MEdge *medge, const int totedge, - const struct MPoly *mpoly, const int totpoly, - const struct MLoop *mloop, const int totloop); +/* smoothgroups */ +int *BKE_mesh_calc_smoothgroups( + const struct MEdge *medge, const int totedge, + const struct MPoly *mpoly, const int totpoly, + const struct MLoop *mloop, const int totloop, + int *r_totgroup, const bool use_bitflags); -/* vertex level transformations & checks (no derived mesh) */ +/* spatial evaluation */ +void BKE_mesh_calc_relative_deform( + const struct MPoly *mpoly, const int totpoly, + const struct MLoop *mloop, const int totvert, -int BKE_mesh_minmax(struct Mesh *me, float r_min[3], float r_max[3]); -int BKE_mesh_center_median(struct Mesh *me, float cent[3]); -int BKE_mesh_center_bounds(struct Mesh *me, float cent[3]); -int BKE_mesh_center_centroid(struct Mesh *me, float cent[3]); -void BKE_mesh_translate(struct Mesh *me, const float offset[3], const bool do_keys); + const float (*vert_cos_src)[3], + const float (*vert_cos_dst)[3], + + const float (*vert_cos_org)[3], + float (*vert_cos_new)[3]); -/* mesh_validate.c */ -/* XXX Loop v/e are unsigned, so using max uint_32 value as invalid marker... */ -#define INVALID_LOOP_EDGE_MARKER 4294967295u -int BKE_mesh_validate_arrays( + + +/* *** mesh_validate.c *** */ + +int BKE_mesh_validate(struct Mesh *me, const int do_verbose); +void BKE_mesh_cd_validate(struct Mesh *me); + +bool BKE_mesh_validate_arrays( struct Mesh *me, struct MVert *mverts, unsigned int totvert, struct MEdge *medges, unsigned int totedge, @@ -349,35 +368,22 @@ int BKE_mesh_validate_arrays( struct MLoop *mloops, unsigned int totloop, struct MPoly *mpolys, unsigned int totpoly, struct MDeformVert *dverts, /* assume totvert length */ - const bool do_verbose, const bool do_fixes); -int BKE_mesh_validate(struct Mesh *me, const int do_verbose); -int BKE_mesh_validate_dm(struct DerivedMesh *dm); + const bool do_verbose, const bool do_fixes, + bool *r_change); -void BKE_mesh_calc_edges(struct Mesh *mesh, bool update, const bool select); - -void BKE_mesh_ensure_navmesh(struct Mesh *me); - -void BKE_mesh_tessface_calc(struct Mesh *mesh); -void BKE_mesh_tessface_ensure(struct Mesh *mesh); -void BKE_mesh_tessface_clear(struct Mesh *mesh); - -/* Convert a triangle or quadrangle of loop/poly data to tessface data */ -void BKE_mesh_loops_to_mface_corners(struct CustomData *fdata, struct CustomData *ldata, - struct CustomData *pdata, int lindex[4], int findex, - const int polyindex, const int mf_len, - const int numTex, const int numCol, const int hasPCol, const int hasOrigSpace); - -void BKE_mesh_poly_edgehash_insert(struct EdgeHash *ehash, const struct MPoly *mp, const struct MLoop *mloop); -void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap, const struct MPoly *mp, const struct MLoop *mloop); - -void BKE_mesh_do_versions_cd_flag_init(struct Mesh *mesh); +bool BKE_mesh_validate_all_customdata( + struct CustomData *vdata, struct CustomData *edata, + struct CustomData *ldata, struct CustomData *pdata, + const bool check_meshmask, + const bool do_verbose, const bool do_fixes, + bool *r_change); +void BKE_mesh_strip_loose_faces(struct Mesh *me); +void BKE_mesh_strip_loose_polysloops(struct Mesh *me); +void BKE_mesh_strip_loose_edges(struct Mesh *me); -void BKE_mesh_mselect_clear(struct Mesh *me); -void BKE_mesh_mselect_validate(struct Mesh *me); -int BKE_mesh_mselect_find(struct Mesh *me, int index, int type); -int BKE_mesh_mselect_active_get(struct Mesh *me, int type); -void BKE_mesh_mselect_active_set(struct Mesh *me, int index, int type); +void BKE_mesh_calc_edges_legacy(struct Mesh *me, const bool use_old); +void BKE_mesh_calc_edges(struct Mesh *mesh, bool update, const bool select); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 0727e11f397..6bf42a3e885 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -29,6 +29,7 @@ */ #include "DNA_modifier_types.h" /* needed for all enum typdefs */ +#include "BLI_compiler_attrs.h" #include "BKE_customdata.h" struct ID; @@ -304,6 +305,9 @@ typedef struct ModifierTypeInfo { TexWalkFunc walk, void *userData); } ModifierTypeInfo; +/* Initialize modifier's global data (type info and some common global storages). */ +void BKE_modifier_init(void); + ModifierTypeInfo *modifierType_getInfo(ModifierType type); /* Modifier utility calls, do call through type pointer and return @@ -322,11 +326,7 @@ bool modifier_isCorrectableDeformed(struct ModifierData *md); bool modifier_isSameTopology(ModifierData *md); bool modifier_isNonGeometrical(ModifierData *md); bool modifier_isEnabled(struct Scene *scene, struct ModifierData *md, int required_mode); -void modifier_setError(struct ModifierData *md, const char *format, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 2, 3))) -#endif -; +void modifier_setError(struct ModifierData *md, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3); bool modifier_isPreview(struct ModifierData *md); void modifiers_foreachObjectLink(struct Object *ob, @@ -354,7 +354,7 @@ struct Object *modifiers_isDeformedByArmature(struct Object *ob); struct Object *modifiers_isDeformedByLattice(struct Object *ob); struct Object *modifiers_isDeformedByCurve(struct Object *ob); bool modifiers_usesArmature(struct Object *ob, struct bArmature *arm); -bool modifiers_isCorrectableDeformed(struct Object *ob); +bool modifiers_isCorrectableDeformed(struct Scene *scene, struct Object *ob); void modifier_freeTemporaryData(struct ModifierData *md); bool modifiers_isPreview(struct Object *ob); @@ -377,7 +377,15 @@ struct CDMaskLink *modifiers_calcDataMasks(struct Scene *scene, struct ModifierData *modifiers_getLastPreview(struct Scene *scene, struct ModifierData *md, int required_mode); -struct ModifierData *modifiers_getVirtualModifierList(struct Object *ob); + +typedef struct VirtualModifierData { + ArmatureModifierData amd; + CurveModifierData cmd; + LatticeModifierData lmd; + ShapeKeyModifierData smd; +} VirtualModifierData; + +struct ModifierData *modifiers_getVirtualModifierList(struct Object *ob, struct VirtualModifierData *data); /* ensure modifier correctness when changing ob->data */ void test_object_modifiers(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_navmesh_conversion.h b/source/blender/blenkernel/BKE_navmesh_conversion.h index cc9c18c764d..3be363f4d7b 100644 --- a/source/blender/blenkernel/BKE_navmesh_conversion.h +++ b/source/blender/blenkernel/BKE_navmesh_conversion.h @@ -28,6 +28,10 @@ #ifndef __BKE_NAVMESH_CONVERSION_H__ #define __BKE_NAVMESH_CONVERSION_H__ +/** \file BKE_navmesh_conversion.h + * \ingroup bke + */ + struct DerivedMesh; /* navmesh_conversion.c */ diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 4e9e18d43e3..7f19a867093 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -32,8 +32,8 @@ * \ingroup bke */ -#include "BLI_ghash.h" #include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "DNA_listBase.h" @@ -337,7 +337,7 @@ struct GHashIterator *ntreeTypeGetIterator(void); #define NODE_TREE_TYPES_END \ } \ BLI_ghashIterator_free(__node_tree_type_iter__); \ -} +} (void)0 void ntreeSetTypes(const struct bContext *C, struct bNodeTree *ntree); @@ -746,6 +746,7 @@ struct ShadeResult; #define SH_NODE_VECT_TRANSFORM 182 #define SH_NODE_SEPHSV 183 #define SH_NODE_COMBHSV 184 +#define SH_NODE_BSDF_HAIR 185 /* custom defines options for Material node */ #define SH_NODE_MAT_DIFF 1 @@ -898,6 +899,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria #define CMP_NODE_PIXELATE 318 #define CMP_NODE_MAP_RANGE 319 +#define CMP_NODE_PLANETRACKDEFORM 320 /* channel toggles */ #define CMP_CHAN_RGB 1 diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 992792dcb99..e99eb2a64f2 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -60,6 +60,7 @@ void BKE_object_copy_softbody(struct Object *obn, struct Object *ob); void BKE_object_free_particlesystems(struct Object *ob); void BKE_object_free_softbody(struct Object *ob); void BKE_object_free_bulletsoftbody(struct Object *ob); +void BKE_object_free_curve_cache(struct Object *ob); void BKE_object_update_base_layer(struct Scene *scene, struct Object *ob); void BKE_object_free(struct Object *ob); @@ -169,7 +170,7 @@ int BKE_object_is_deform_modified(struct Scene *scene, struct Object *ob); void BKE_object_relink(struct Object *ob); -struct MovieClip *BKE_object_movieclip_get(struct Scene *scene, struct Object *ob, int use_default); +struct MovieClip *BKE_object_movieclip_get(struct Scene *scene, struct Object *ob, bool use_default); /* this function returns a superset of the scenes selection based on relationships */ @@ -193,6 +194,8 @@ struct LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet struct LinkNode *BKE_object_groups(struct Object *ob); void BKE_object_groups_clear(struct Scene *scene, struct Base *base, struct Object *object); +struct KDTree *BKE_object_as_kdtree(struct Object *ob, int *r_tot); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h index b733204e078..b750d8b283a 100644 --- a/source/blender/blenkernel/BKE_ocean.h +++ b/source/blender/blenkernel/BKE_ocean.h @@ -23,6 +23,10 @@ #ifndef __BKE_OCEAN_H__ #define __BKE_OCEAN_H__ +/** \file BKE_ocean.h + * \ingroup bli + */ + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 2baa8b78e47..1d81dfefe65 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -173,5 +173,4 @@ void free_sculptsession(struct Object *ob); void free_sculptsession_deformMats(struct SculptSession *ss); void sculptsession_bm_to_me(struct Object *ob, int reorder); void sculptsession_bm_to_me_for_render(struct Object *object); - #endif diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 56b550a6f5d..d4965cf55fe 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -54,6 +54,7 @@ struct MCol; struct MFace; struct MVert; struct IpoCurve; +struct LatticeDeformData; struct LinkNode; struct KDTree; struct RNG; @@ -258,7 +259,7 @@ void psys_set_current_num(Object *ob, int index); /* UNUSED */ // struct Object *psys_find_object(struct Scene *scene, struct ParticleSystem *psys); -struct Object *psys_get_lattice(struct ParticleSimulationData *sim); +struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim); int psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys); int psys_check_enabled(struct Object *ob, struct ParticleSystem *psys); diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 7d3d8d7dcbd..9e21831dba0 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -172,8 +172,8 @@ int BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data); /* test if AABB is at least partially outside the planes' volume */ int BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data); -struct GHash *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node); -struct GHash *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node); +struct GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node); +struct GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node); void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node); void BKE_pbvh_bmesh_after_stroke(PBVH *bvh); @@ -235,9 +235,10 @@ typedef struct PBVHVertexIter { float *vmask; /* bmesh */ - struct GHashIterator bm_unique_verts; - struct GHashIterator bm_other_verts; + struct GSetIterator bm_unique_verts; + struct GSetIterator bm_other_verts; struct CustomData *bm_vdata; + int cd_vert_mask_offset; /* result: these are all computed in the macro, but we assume * that compiler optimization's will skip the ones we don't use */ @@ -294,22 +295,20 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, vi.mask = &vi.vmask[vi.vert_indices[vi.gx]]; \ } \ else { \ - if (!BLI_ghashIterator_done(&vi.bm_unique_verts)) {\ - vi.bm_vert = BLI_ghashIterator_getKey(&vi.bm_unique_verts); \ - BLI_ghashIterator_step(&vi.bm_unique_verts); \ + if (!BLI_gsetIterator_done(&vi.bm_unique_verts)) {\ + vi.bm_vert = BLI_gsetIterator_getKey(&vi.bm_unique_verts); \ + BLI_gsetIterator_step(&vi.bm_unique_verts); \ } \ else { \ - vi.bm_vert = BLI_ghashIterator_getKey(&vi.bm_other_verts); \ - BLI_ghashIterator_step(&vi.bm_other_verts); \ + vi.bm_vert = BLI_gsetIterator_getKey(&vi.bm_other_verts); \ + BLI_gsetIterator_step(&vi.bm_other_verts); \ } \ if (mode == PBVH_ITER_UNIQUE && \ BM_elem_flag_test(vi.bm_vert, BM_ELEM_HIDDEN)) \ continue; \ vi.co = vi.bm_vert->co; \ vi.fno = vi.bm_vert->no; \ - vi.mask = CustomData_bmesh_get(vi.bm_vdata, \ - vi.bm_vert->head.data, \ - CD_PAINT_MASK); \ + vi.mask = BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \ } #define BKE_pbvh_vertex_iter_end \ diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 1cb50425c40..d5131fcd19e 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -156,6 +156,8 @@ typedef struct PTCacheID { /* total number of simulated points (the cfra parameter is just for using same function pointer with totwrite) */ int (*totpoint)(void *calldata, int cfra); + /* report error if number of points does not match */ + void (*error)(void *calldata, const char *message); /* number of points written for current cache frame */ int (*totwrite)(void *calldata, int cfra); diff --git a/source/blender/blenkernel/BKE_report.h b/source/blender/blenkernel/BKE_report.h index ae457cf4f47..101fc463375 100644 --- a/source/blender/blenkernel/BKE_report.h +++ b/source/blender/blenkernel/BKE_report.h @@ -34,6 +34,7 @@ extern "C" { #include <stdio.h> #include "DNA_windowmanager_types.h" +#include "BLI_compiler_attrs.h" #include "BLI_utildefines.h" /* Reporting Information and Errors @@ -47,18 +48,10 @@ void BKE_reports_init(ReportList *reports, int flag); void BKE_reports_clear(ReportList *reports); void BKE_report(ReportList *reports, ReportType type, const char *message); -void BKE_reportf(ReportList *reports, ReportType type, const char *format, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 3, 4))) -#endif -; +void BKE_reportf(ReportList *reports, ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4); void BKE_reports_prepend(ReportList *reports, const char *prepend); -void BKE_reports_prependf(ReportList *reports, const char *prepend, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 2, 3))) -#endif -; +void BKE_reports_prependf(ReportList *reports, const char *prepend, ...) ATTR_PRINTF_FORMAT(2, 3); ReportType BKE_report_print_level(ReportList *reports); void BKE_report_print_level_set(ReportList *reports, ReportType level); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index c883bdf74e0..3c0928d38a0 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -189,9 +189,15 @@ typedef struct PanelType { /* uilist types */ -/* draw an item in the uiList */ +/* Draw an item in the uiList */ typedef void (*uiListDrawItemFunc)(struct uiList *, struct bContext *, struct uiLayout *, struct PointerRNA *, - struct PointerRNA *, int, struct PointerRNA *, const char *, int); + struct PointerRNA *, int, struct PointerRNA *, const char *, int, int); + +/* Draw the filtering part of an uiList */ +typedef void (*uiListDrawFilterFunc)(struct uiList *, struct bContext *, struct uiLayout *); + +/* Filter items of an uiList */ +typedef void (*uiListFilterItemsFunc)(struct uiList *, struct bContext *, struct PointerRNA *, const char *); typedef struct uiListType { struct uiListType *next, *prev; @@ -199,6 +205,8 @@ typedef struct uiListType { char idname[BKE_ST_MAXNAME]; /* unique name */ uiListDrawItemFunc draw_item; + uiListDrawFilterFunc draw_filter; + uiListFilterItemsFunc filter_items; /* RNA integration */ ExtensionRNA ext; diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 78018f04458..12b6d18ab7c 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -194,6 +194,7 @@ void BKE_sequencer_editing_free(struct Scene *scene); void BKE_sequencer_sort(struct Scene *scene); +struct Sequence *BKE_sequencer_from_elem(ListBase *seqbase, struct StripElem *se); struct Sequence *BKE_sequencer_active_get(struct Scene *scene); int BKE_sequencer_active_get_pair(struct Scene *scene, struct Sequence **seq_act, struct Sequence **seq_other); void BKE_sequencer_active_set(struct Scene *scene, struct Sequence *seq); @@ -318,6 +319,8 @@ void BKE_sequencer_update_sound_bounds(struct Scene *scene, struct Sequence *seq void BKE_sequencer_update_muting(struct Editing *ed); void BKE_sequencer_update_sound(struct Scene *scene, struct bSound *sound); +void BKE_sequencer_refresh_sound_length(struct Scene *scene); + void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq); void BKE_sequence_base_dupli_recursive(struct Scene *scene, struct Scene *scene_to, ListBase *nseqbase, ListBase *seqbase, int dupe_flag); bool BKE_sequence_is_valid_check(struct Sequence *seq); diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index 61d82e6c604..323a926863c 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -134,9 +134,9 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object * Thus it provides an easy way to cast the same ray across several trees * (where each tree was built on its own coords space) */ -int normal_projection_project_vertex(char options, const float vert[3], const float dir[3], - const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, - BVHTree_RayCastCallback callback, void *userdata); +int BKE_shrinkwrap_project_normal(char options, const float vert[3], const float dir[3], + const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, + BVHTree_RayCastCallback callback, void *userdata); /* * NULL initializers to local data diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h index 653f2a42675..ab8b8b29915 100644 --- a/source/blender/blenkernel/BKE_subsurf.h +++ b/source/blender/blenkernel/BKE_subsurf.h @@ -72,11 +72,11 @@ struct DerivedMesh *subsurf_make_derived_from_derived( void subsurf_calculate_limit_positions(struct Mesh *me, float (*positions_r)[3]); /* get gridsize from 'level', level must be greater than zero */ -int ccg_gridsize(int level); +int BKE_ccg_gridsize(int level); /* x/y grid coordinates at 'low_level' can be multiplied by the result * of this function to convert to grid coordinates at 'high_level' */ -int ccg_factor(int low_level, int high_level); +int BKE_ccg_factor(int low_level, int high_level); void subsurf_copy_grid_hidden(struct DerivedMesh *dm, const struct MPoly *mpoly, diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index 24fd763d078..bba209334d4 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -58,7 +58,7 @@ void BKE_text_write (struct Text *text, const char *str); char *txt_to_buf (struct Text *text); void txt_clean_text (struct Text *text); -void txt_order_cursors (struct Text *text); +void txt_order_cursors (struct Text *text, const bool reverse); int txt_find_string (struct Text *text, const char *findstr, int wrap, int match_case); int txt_has_sel (struct Text *text); int txt_get_span (struct TextLine *from, struct TextLine *to); diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index ac0d507003e..2a00dee2a3f 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -101,8 +101,8 @@ void set_current_particle_texture(struct ParticleSettings *part, struct Tex *tex int has_current_material_texture(struct Material *ma); -struct TexMapping *add_tex_mapping(void); -void default_tex_mapping(struct TexMapping *texmap); +struct TexMapping *add_tex_mapping(int type); +void default_tex_mapping(struct TexMapping *texmap, int type); void init_tex_mapping(struct TexMapping *texmap); struct ColorMapping *add_color_mapping(void); diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h index 84bca0bd3ba..51f97180ddb 100644 --- a/source/blender/blenkernel/BKE_tracking.h +++ b/source/blender/blenkernel/BKE_tracking.h @@ -38,6 +38,8 @@ struct ListBase; struct MovieReconstructContext; struct MovieTrackingTrack; struct MovieTrackingMarker; +struct MovieTrackingPlaneTrack; +struct MovieTrackingPlaneMarker; struct MovieTracking; struct MovieTrackingContext; struct MovieTrackingObject; @@ -55,6 +57,7 @@ void BKE_tracking_free(struct MovieTracking *tracking); void BKE_tracking_settings_init(struct MovieTracking *tracking); struct ListBase *BKE_tracking_get_active_tracks(struct MovieTracking *tracking); +struct ListBase *BKE_tracking_get_active_plane_tracks(struct MovieTracking *tracking); struct MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(struct MovieTracking *tracking); /* matrices for constraints and drawing */ @@ -65,7 +68,7 @@ void BKE_tracking_get_projection_matrix(struct MovieTracking *tracking, struct M /* **** Clipboard **** */ void BKE_tracking_clipboard_free(void); void BKE_tracking_clipboard_copy_tracks(struct MovieTracking *tracking, struct MovieTrackingObject *object); -int BKE_tracking_clipboard_has_tracks(void); +bool BKE_tracking_clipboard_has_tracks(void); void BKE_tracking_clipboard_paste_tracks(struct MovieTracking *tracking, struct MovieTrackingObject *object); /* **** Track **** */ @@ -77,8 +80,8 @@ void BKE_tracking_track_free(struct MovieTrackingTrack *track); void BKE_tracking_track_flag_set(struct MovieTrackingTrack *track, int area, int flag); void BKE_tracking_track_flag_clear(struct MovieTrackingTrack *track, int area, int flag); -int BKE_tracking_track_has_marker_at_frame(struct MovieTrackingTrack *track, int framenr); -int BKE_tracking_track_has_enabled_marker_at_frame(struct MovieTrackingTrack *track, int framenr); +bool BKE_tracking_track_has_marker_at_frame(struct MovieTrackingTrack *track, int framenr); +bool BKE_tracking_track_has_enabled_marker_at_frame(struct MovieTrackingTrack *track, int framenr); void BKE_tracking_track_path_clear(struct MovieTrackingTrack *track, int ref_frame, int action); void BKE_tracking_tracks_join(struct MovieTracking *tracking, struct MovieTrackingTrack *dst_track, struct MovieTrackingTrack *src_track); @@ -95,8 +98,9 @@ float *BKE_tracking_track_get_mask(int frame_width, int frame_height, struct Mov struct MovieTrackingMarker *marker); /* selection */ -void BKE_tracking_track_select(struct ListBase *tracksbase, struct MovieTrackingTrack *track, int area, int extend); +void BKE_tracking_track_select(struct ListBase *tracksbase, struct MovieTrackingTrack *track, int area, bool extend); void BKE_tracking_track_deselect(struct MovieTrackingTrack *track, int area); +void BKE_tracking_tracks_deselect_all(struct ListBase *tracksbase); /* **** Marker **** */ struct MovieTrackingMarker *BKE_tracking_marker_insert(struct MovieTrackingTrack *track, @@ -113,9 +117,35 @@ void BKE_tracking_marker_pattern_minmax(const struct MovieTrackingMarker *marker void BKE_tracking_marker_get_subframe_position(struct MovieTrackingTrack *track, float framenr, float pos[2]); +/* **** Plane Track **** */ +struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(struct MovieTracking *tracking, struct ListBase *plane_tracks_base, + struct ListBase *tracks, int framenr); +void BKE_tracking_plane_track_unique_name(struct ListBase *plane_tracks_base, struct MovieTrackingPlaneTrack *plane_track); +void BKE_tracking_plane_track_free(struct MovieTrackingPlaneTrack *plane_track); + +bool BKE_tracking_plane_track_has_marker_at_frame(struct MovieTrackingPlaneTrack *plane_track, int framenr); +bool BKE_tracking_plane_track_has_enabled_marker_at_frame(struct MovieTrackingPlaneTrack *plane_track, int framenr); + +struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_named(struct MovieTracking *tracking, + struct MovieTrackingObject *object, + const char *name); + +struct MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_active(struct MovieTracking *tracking); + +void BKE_tracking_plane_tracks_deselect_all(struct ListBase *plane_tracks_base); + +/* **** Plane Marker **** */ +struct MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(struct MovieTrackingPlaneTrack *plane_track, + struct MovieTrackingPlaneMarker *plane_marker); +void BKE_tracking_plane_marker_delete(struct MovieTrackingPlaneTrack *plane_track, int framenr); + +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); + /* **** Object **** */ struct MovieTrackingObject *BKE_tracking_object_add(struct MovieTracking *tracking, const char *name); -int BKE_tracking_object_delete(struct MovieTracking *tracking, struct MovieTrackingObject *object); +bool BKE_tracking_object_delete(struct MovieTracking *tracking, struct MovieTrackingObject *object); void BKE_tracking_object_unique_name(struct MovieTracking *tracking, struct MovieTrackingObject *object); @@ -125,6 +155,7 @@ struct MovieTrackingObject *BKE_tracking_object_get_active(struct MovieTracking struct MovieTrackingObject *BKE_tracking_object_get_camera(struct MovieTracking *tracking); struct ListBase *BKE_tracking_object_get_tracks(struct MovieTracking *tracking, struct MovieTrackingObject *object); +struct ListBase *BKE_tracking_object_get_plane_tracks(struct MovieTracking *tracking, struct MovieTrackingObject *object); struct MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(struct MovieTracking *tracking, struct MovieTrackingObject *object); @@ -147,7 +178,7 @@ void BKE_tracking_distortion_update(struct MovieDistortion *distortion, struct M void BKE_tracking_distortion_set_threads(struct MovieDistortion *distortion, int threads); struct MovieDistortion *BKE_tracking_distortion_copy(struct MovieDistortion *distortion); struct ImBuf *BKE_tracking_distortion_exec(struct MovieDistortion *distortion, struct MovieTracking *tracking, - struct ImBuf *ibuf, int width, int height, float overscan, int undistort); + struct ImBuf *ibuf, int width, int height, float overscan, bool undistort); void BKE_tracking_distortion_free(struct MovieDistortion *distortion); void BKE_tracking_distort_v2(struct MovieTracking *tracking, const float co[2], float r_co[2]); @@ -163,15 +194,15 @@ void BKE_tracking_max_undistortion_delta_across_bound(struct MovieTracking *trac /* **** Image sampling **** */ struct ImBuf *BKE_tracking_sample_pattern(int frame_width, int frame_height, struct ImBuf *struct_ibuf, struct MovieTrackingTrack *track, - struct MovieTrackingMarker *marker, int from_anchor, int use_mask, + struct MovieTrackingMarker *marker, bool from_anchor, bool use_mask, int num_samples_x, int num_samples_y, float pos[2]); struct ImBuf *BKE_tracking_get_pattern_imbuf(struct ImBuf *ibuf, struct MovieTrackingTrack *track, - struct MovieTrackingMarker *marker, int anchored, int disable_channels); + struct MovieTrackingMarker *marker, bool anchored, bool disable_channels); struct ImBuf *BKE_tracking_get_search_imbuf(struct ImBuf *ibuf, struct MovieTrackingTrack *track, - struct MovieTrackingMarker *marker, int anchored, int disable_channels); + struct MovieTrackingMarker *marker, bool anchored, bool disable_channels); -void BKE_tracking_disable_channels(struct ImBuf *ibuf, int disable_red, int disable_green, - int disable_blue, int grayscale); +void BKE_tracking_disable_channels(struct ImBuf *ibuf, bool disable_red, bool disable_green, + bool disable_blue, bool grayscale); /* **** 2D tracking **** */ struct MovieTrackingContext *BKE_tracking_context_new(struct MovieClip *clip, struct MovieClipUser *user, @@ -179,12 +210,20 @@ struct MovieTrackingContext *BKE_tracking_context_new(struct MovieClip *clip, st void BKE_tracking_context_free(struct MovieTrackingContext *context); void BKE_tracking_context_sync(struct MovieTrackingContext *context); void BKE_tracking_context_sync_user(const struct MovieTrackingContext *context, struct MovieClipUser *user); -int BKE_tracking_context_step(struct MovieTrackingContext *context); -void BKE_tracking_refine_marker(struct MovieClip *clip, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker, int backwards); +bool BKE_tracking_context_step(struct MovieTrackingContext *context); +void BKE_tracking_context_finish(struct MovieTrackingContext *context); + +void BKE_tracking_refine_marker(struct MovieClip *clip, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker, bool backwards); + +/* **** Plane tracking **** */ + +void BKE_tracking_track_plane_from_existing_motion(struct MovieTrackingPlaneTrack *plane_track, int start_frame); +void BKE_tracking_retrack_plane_from_existing_motion_at_segment(struct MovieTrackingPlaneTrack *plane_track, int start_frame); +void BKE_tracking_homography_between_two_quads(/*const*/ float reference_corners[4][2], /*const*/ float corners[4][2], float H[3][3]); /* **** Camera solving **** */ -int BKE_tracking_reconstruction_check(struct MovieTracking *tracking, struct MovieTrackingObject *object, - char *error_msg, int error_size); +bool BKE_tracking_reconstruction_check(struct MovieTracking *tracking, struct MovieTrackingObject *object, + char *error_msg, int error_size); struct MovieReconstructContext *BKE_tracking_reconstruction_context_new(struct MovieTracking *tracking, struct MovieTrackingObject *object, @@ -193,14 +232,14 @@ struct MovieReconstructContext *BKE_tracking_reconstruction_context_new(struct M void BKE_tracking_reconstruction_context_free(struct MovieReconstructContext *context); void BKE_tracking_reconstruction_solve(struct MovieReconstructContext *context, short *stop, short *do_update, float *progress, char *stats_message, int message_size); -int BKE_tracking_reconstruction_finish(struct MovieReconstructContext *context, struct MovieTracking *tracking); +bool BKE_tracking_reconstruction_finish(struct MovieReconstructContext *context, struct MovieTracking *tracking); void BKE_tracking_reconstruction_scale(struct MovieTracking *tracking, float scale[3]); /* **** Feature detection **** */ void BKE_tracking_detect_fast(struct MovieTracking *tracking, struct ListBase *tracksbase, struct ImBuf *imbuf, int framenr, int margin, int min_trackness, int min_distance, struct bGPDlayer *layer, - int place_outside_layer); + bool place_outside_layer); /* **** 2D stabilization **** */ void BKE_tracking_stabilization_data_get(struct MovieTracking *tracking, int framenr, int width, int height, diff --git a/source/blender/blenkernel/BKE_treehash.h b/source/blender/blenkernel/BKE_treehash.h new file mode 100644 index 00000000000..54deef1ce2f --- /dev/null +++ b/source/blender/blenkernel/BKE_treehash.h @@ -0,0 +1,52 @@ +/* + * ***** 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. + * + * Contributor(s): Blender Foundation 2013 + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_TREEHASH_H__ +#define __BKE_TREEHASH_H__ + +/** \file BKE_treehash.h + * \ingroup bke + */ + +struct ID; +struct GHash; +struct BLI_mempool; +struct TreeStoreElem; + +/* create and fill hashtable with treestore elements */ +void *BKE_treehash_create_from_treestore(struct BLI_mempool *treestore); + +/* full rebuild for already allocated hashtable */ +void *BKE_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore); + +/* full rebuild for already allocated hashtable */ +void BKE_treehash_add_element(void *treehash, struct TreeStoreElem *elem); + +/* find first unused element with specific type, nr and id */ +struct TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id); + +/* find user or unused element with specific type, nr and id */ +struct TreeStoreElem *BKE_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id); + +/* free treehash structure */ +void BKE_treehash_free(void *treehash); + +#endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 655e0d65133..0ac3737b6a2 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -45,6 +45,7 @@ set(INC ../../../intern/raskter ../../../intern/smoke/extern ../../../extern/libmv + ../../../intern/atomic # XXX - BAD LEVEL CALL WM_api.h ../windowmanager @@ -114,6 +115,7 @@ set(SRC intern/material.c intern/mball.c intern/mesh.c + intern/mesh_evaluate.c intern/mesh_validate.c intern/modifier.c intern/modifiers_bmesh.c @@ -152,6 +154,7 @@ set(SRC intern/text.c intern/texture.c intern/tracking.c + intern/treehash.c intern/unit.c intern/world.c intern/writeavi.c @@ -243,6 +246,7 @@ set(SRC BKE_text.h BKE_texture.h BKE_tracking.h + BKE_treehash.h BKE_unit.h BKE_utildefines.h BKE_world.h diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index 6d080fea031..3c3ac61a3cb 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -52,6 +52,7 @@ incs = [ '#/intern/iksolver/extern', '#/intern/opennl/extern', '#/intern/smoke/extern', + '#/intern/atomic', '../avi', '../blenfont', '../blenlib', diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index d4454a95a2d..ffb92788d4d 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -248,7 +248,7 @@ static CCGAllocatorIFC *_getStandardAllocatorIFC(void) /***/ -int ccg_gridsize(int level) +BLI_INLINE int ccg_gridsize(int level) { BLI_assert(level > 0); BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1); @@ -256,7 +256,12 @@ int ccg_gridsize(int level) return (1 << (level - 1)) + 1; } -int ccg_factor(int low_level, int high_level) +int BKE_ccg_gridsize(int level) +{ + return ccg_gridsize(level); +} + +int BKE_ccg_factor(int low_level, int high_level) { BLI_assert(low_level > 0 && high_level > 0); BLI_assert(low_level <= high_level); @@ -264,7 +269,7 @@ int ccg_factor(int low_level, int high_level) return 1 << (high_level - low_level); } -static int ccg_edgesize(int level) +BLI_INLINE int ccg_edgesize(int level) { BLI_assert(level > 0); BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1); @@ -272,7 +277,7 @@ static int ccg_edgesize(int level) return 1 + (1 << level); } -static int ccg_spacing(int high_level, int low_level) +BLI_INLINE int ccg_spacing(int high_level, int low_level) { BLI_assert(high_level > 0 && low_level > 0); BLI_assert(high_level >= low_level); @@ -281,7 +286,7 @@ static int ccg_spacing(int high_level, int low_level) return 1 << (high_level - low_level); } -static int ccg_edgebase(int level) +BLI_INLINE int ccg_edgebase(int level) { BLI_assert(level > 0); BLI_assert(level <= CCGSUBSURF_LEVEL_MAX + 1); @@ -742,7 +747,7 @@ BLI_INLINE float *_face_getIFNo(CCGFace *f, int lvl, int S, int x, int y, int le byte *gridBase = FACE_getCenterData(f) + dataSize * (1 + S * (maxGridSize + maxGridSize * maxGridSize)); return (float *) &gridBase[dataSize * (maxGridSize + (y * maxGridSize + x) * spacing) + normalDataOffset]; } -static int _face_getVertIndex(CCGFace *f, CCGVert *v) +BLI_INLINE int _face_getVertIndex(CCGFace *f, CCGVert *v) { int i; for (i = 0; i < f->numVerts; i++) @@ -750,7 +755,7 @@ static int _face_getVertIndex(CCGFace *f, CCGVert *v) return i; return -1; } -static int _face_getEdgeIndex(CCGFace *f, CCGEdge *e) +BLI_INLINE int _face_getEdgeIndex(CCGFace *f, CCGEdge *e) { int i; for (i = 0; i < f->numVerts; i++) diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h index d350d1f4280..fdf6d2df99f 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.h +++ b/source/blender/blenkernel/intern/CCGSubSurf.h @@ -18,6 +18,9 @@ * ***** END GPL LICENSE BLOCK ***** */ +#ifndef __CCGSUBSURF_H__ +#define __CCGSUBSURF_H__ + /** \file blender/blenkernel/intern/CCGSubSurf.h * \ingroup bke */ @@ -182,3 +185,5 @@ 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 2ece90183bd..368c1e517ef 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -82,11 +82,20 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm); #include "GPU_extensions.h" #include "GPU_material.h" +/* very slow! enable for testing only! */ +// #define USE_MODIFIER_VALIDATE + +#ifdef USE_MODIFIER_VALIDATE +# define ASSERT_IS_VALID_DM(dm) (BLI_assert((dm == NULL) || (DM_is_valid(dm) == true))) +#else +# define ASSERT_IS_VALID_DM(dm) +#endif + static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob); static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid); -/////////////////////////////////// -/////////////////////////////////// + +/* -------------------------------------------------------------------- */ static MVert *dm_getVertArray(DerivedMesh *dm) { @@ -429,9 +438,9 @@ void DM_update_tessface_data(DerivedMesh *dm) int *polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX); - int mf_idx, - totface = dm->getNumTessFaces(dm), - ml_idx[4]; + const int totface = dm->getNumTessFaces(dm); + int mf_idx; + int ml_idx[4]; /* Should never occure, but better abort than segfault! */ if (!polyindex) @@ -879,6 +888,7 @@ DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob, add_shapekey_layers(tdm, me, ob); dm = modwrap_applyModifier(md, ob, tdm, 0); + ASSERT_IS_VALID_DM(dm); if (tdm != dm) tdm->release(tdm); } @@ -1440,6 +1450,8 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos /* XXX Same as above... For now, only weights preview in WPaint mode. */ const int do_mod_wmcol = do_init_wmcol; + VirtualModifierData virtualModifierData; + ModifierApplyFlag app_flags = useRenderParams ? MOD_APPLY_RENDER : 0; ModifierApplyFlag deform_app_flags = app_flags; if (useCache) @@ -1451,7 +1463,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos has_multires = 0; if (!skipVirtualArmature) { - firstmd = modifiers_getVirtualModifierList(ob); + firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData); } else { /* game engine exception */ @@ -1648,6 +1660,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos } else { dm = CDDM_from_mesh(me, ob); + ASSERT_IS_VALID_DM(dm); if (build_shapekey_layers) add_shapekey_layers(dm, me, ob); @@ -1672,7 +1685,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL); -#pragma omp parallel sections if (dm->numVertData + dm->numEdgeData + dm->numPolyData >= DM_OMP_LIMIT) +#pragma omp parallel sections if (dm->numVertData + dm->numEdgeData + dm->numPolyData >= BKE_MESH_OMP_LIMIT) { #pragma omp section { range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0); } @@ -1705,6 +1718,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos } ndm = modwrap_applyModifier(md, ob, dm, app_flags); + ASSERT_IS_VALID_DM(ndm); if (ndm) { /* if the modifier returned a new dm, release the old one */ @@ -1731,6 +1745,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos mti->requiredDataMask(ob, md) : 0)); ndm = modwrap_applyModifier(md, ob, orcodm, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO); + ASSERT_IS_VALID_DM(ndm); if (ndm) { /* if the modifier returned a new dm, release the old one */ @@ -1748,6 +1763,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos DM_set_only_copy(clothorcodm, nextmask | CD_MASK_ORIGINDEX); ndm = modwrap_applyModifier(md, ob, clothorcodm, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO); + ASSERT_IS_VALID_DM(ndm); if (ndm) { /* if the modifier returned a new dm, release the old one */ @@ -1961,6 +1977,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D int do_init_wmcol = ((((Mesh *)ob->data)->drawflag & ME_DRAWEIGHT) && !do_final_wmcol); int do_init_statvis = ((((Mesh *)ob->data)->drawflag & ME_DRAW_STATVIS) && !do_init_wmcol); const int do_mod_wmcol = do_init_wmcol; + VirtualModifierData virtualModifierData; modifiers_clearErrors(ob); @@ -1969,7 +1986,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D } dm = NULL; - md = modifiers_getVirtualModifierList(ob); + md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* copied from mesh_calc_modifiers */ if (do_mod_wmcol) { @@ -2049,6 +2066,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D } else { dm = CDDM_from_editbmesh(em, FALSE, FALSE); + ASSERT_IS_VALID_DM(dm); if (deformedVerts) { CDDM_apply_vert_coords(dm, deformedVerts); @@ -2068,10 +2086,13 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D mask &= ~CD_MASK_ORCO; DM_set_only_copy(orcodm, mask | CD_MASK_ORIGINDEX); - if (mti->applyModifierEM) + if (mti->applyModifierEM) { ndm = modwrap_applyModifierEM(md, ob, em, orcodm, MOD_APPLY_ORCO); - else + } + else { ndm = modwrap_applyModifier(md, ob, orcodm, MOD_APPLY_ORCO); + } + ASSERT_IS_VALID_DM(ndm); if (ndm) { /* if the modifier returned a new dm, release the old one */ @@ -2097,6 +2118,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D ndm = modwrap_applyModifierEM(md, ob, em, dm, MOD_APPLY_USECACHE); else ndm = modwrap_applyModifier(md, ob, dm, MOD_APPLY_USECACHE); + ASSERT_IS_VALID_DM(ndm); if (ndm) { if (dm && dm != ndm) @@ -2738,11 +2760,9 @@ void DM_calc_auto_bump_scale(DerivedMesh *dm) int offs = 0; /* initial triangulation is 0,1,2 and 0, 2, 3 */ if (nr_verts == 4) { float pos_len_diag0, pos_len_diag1; - float vtmp[3]; - sub_v3_v3v3(vtmp, verts[2], verts[0]); - pos_len_diag0 = dot_v3v3(vtmp, vtmp); - sub_v3_v3v3(vtmp, verts[3], verts[1]); - pos_len_diag1 = dot_v3v3(vtmp, vtmp); + + pos_len_diag0 = len_squared_v3v3(verts[2], verts[0]); + pos_len_diag1 = len_squared_v3v3(verts[3], verts[1]); if (pos_len_diag1 < pos_len_diag0) { offs = 1; // alter split @@ -2750,10 +2770,8 @@ void DM_calc_auto_bump_scale(DerivedMesh *dm) else if (pos_len_diag0 == pos_len_diag1) { /* do UV check instead */ float tex_len_diag0, tex_len_diag1; - sub_v2_v2v2(vtmp, tex_coords[2], tex_coords[0]); - tex_len_diag0 = dot_v2v2(vtmp, vtmp); - sub_v2_v2v2(vtmp, tex_coords[3], tex_coords[1]); - tex_len_diag1 = dot_v2v2(vtmp, vtmp); + tex_len_diag0 = len_squared_v2v2(tex_coords[2], tex_coords[0]); + tex_len_diag1 = len_squared_v2v2(tex_coords[3], tex_coords[1]); if (tex_len_diag1 < tex_len_diag0) { offs = 1; /* alter split */ @@ -2762,7 +2780,7 @@ void DM_calc_auto_bump_scale(DerivedMesh *dm) } nr_tris_to_pile = nr_verts - 2; if (nr_tris_to_pile == 1 || nr_tris_to_pile == 2) { - const int indices[] = {offs + 0, offs + 1, offs + 2, offs + 0, offs + 2, (offs + 3) & 0x3 }; + const int indices[6] = {offs + 0, offs + 1, offs + 2, offs + 0, offs + 2, (offs + 3) & 0x3 }; int t; for (t = 0; t < nr_tris_to_pile; t++) { float f2x_area_uv; @@ -2782,7 +2800,7 @@ void DM_calc_auto_bump_scale(DerivedMesh *dm) cross_v3_v3v3(norm, v0, v1); f2x_surf_area = len_v3(norm); - fsurf_ratio = f2x_surf_area / f2x_area_uv; // tri area divided by texture area + fsurf_ratio = f2x_surf_area / f2x_area_uv; /* tri area divided by texture area */ nr_accumulated++; dsum += (double)(fsurf_ratio); @@ -3262,4 +3280,35 @@ void DM_debug_print_cdlayers(CustomData *data) printf("}\n"); } +bool DM_is_valid(DerivedMesh *dm) +{ + const bool do_verbose = true; + const bool do_fixes = false; + + bool is_valid = true; + bool is_change = true; + + is_valid &= BKE_mesh_validate_all_customdata( + dm->getVertDataLayout(dm), + dm->getEdgeDataLayout(dm), + dm->getLoopDataLayout(dm), + dm->getPolyDataLayout(dm), + 0, /* setting mask here isn't useful, gives false positives */ + do_verbose, do_fixes, &is_change); + + is_valid &= BKE_mesh_validate_arrays( + NULL, + dm->getVertArray(dm), dm->getNumVerts(dm), + dm->getEdgeArray(dm), dm->getNumEdges(dm), + dm->getTessFaceArray(dm), dm->getNumTessFaces(dm), + dm->getLoopArray(dm), dm->getNumLoops(dm), + dm->getPolyArray(dm), dm->getNumPolys(dm), + dm->getVertDataArray(dm, CD_MDEFORMVERT), + do_verbose, do_fixes, &is_change); + + BLI_assert(is_change == false); + + return is_valid; +} + #endif /* NDEBUG */ diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index bfef3542c45..b0644da4598 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -489,6 +489,22 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name) return chan; } +#ifndef NDEBUG +bool BKE_pose_channels_is_valid(const bPose *pose) +{ + if (pose->chanhash) { + bPoseChannel *pchan; + for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + if (BLI_ghash_lookup(pose->chanhash, pchan->name) != pchan) { + return false; + } + } + } + + return true; +} + +#endif /* Find the active posechannel for an object (we can't just use pose, as layer info is in armature) */ bPoseChannel *BKE_pose_channel_active(Object *ob) { @@ -594,11 +610,43 @@ void BKE_pose_ikparam_init(bPose *pose) } } + +/* only for real IK, not for auto-IK */ +static bool pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan, int level) +{ + bConstraint *con; + Bone *bone; + + /* No need to check if constraint is active (has influence), + * since all constraints with CONSTRAINT_IK_AUTO are active */ + for (con = pchan->constraints.first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_KINEMATIC) { + bKinematicConstraint *data = con->data; + if ((data->rootbone == 0) || (data->rootbone > level)) { + if ((data->flag & CONSTRAINT_IK_AUTO) == 0) + return true; + } + } + } + for (bone = pchan->bone->childbase.first; bone; bone = bone->next) { + pchan = BKE_pose_channel_find_name(ob->pose, bone->name); + if (pchan && pose_channel_in_IK_chain(ob, pchan, level + 1)) + return true; + } + return false; +} + +bool BKE_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan) +{ + return pose_channel_in_IK_chain(ob, pchan, 0); +} + + void BKE_pose_channels_hash_make(bPose *pose) { if (!pose->chanhash) { bPoseChannel *pchan; - + pose->chanhash = BLI_ghash_str_new("make_pose_chan gh"); for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) BLI_ghash_insert(pose->chanhash, pchan->name, pchan); diff --git a/source/blender/blenkernel/intern/addon.c b/source/blender/blenkernel/intern/addon.c index ae6ec7cd7e1..129bc4657b4 100644 --- a/source/blender/blenkernel/intern/addon.c +++ b/source/blender/blenkernel/intern/addon.c @@ -20,6 +20,10 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/blenkernel/intern/addon.c + * \ingroup bke + */ + #include <stddef.h> #include <stdlib.h> diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index ba680147201..5c3f67d8959 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -488,18 +488,16 @@ void free_path(Path *path) /* calculate a curve-deform path for a curve * - only called from displist.c -> do_makeDispListCurveTypes */ -void calc_curvepath(Object *ob) +void calc_curvepath(Object *ob, ListBase *nurbs) { BevList *bl; BevPoint *bevp, *bevpn, *bevpfirst, *bevplast; PathPoint *pp; - Curve *cu; Nurb *nu; Path *path; float *fp, *dist, *maxdist, xyz[3]; float fac, d = 0, fac1, fac2; int a, tot, cycl = 0; - ListBase *nurbs; /* in a path vertices are with equal differences: path->len = number of verts */ /* NOW WITH BEVELCURVE!!! */ @@ -507,21 +505,19 @@ void calc_curvepath(Object *ob) if (ob == NULL || ob->type != OB_CURVE) { return; } - cu = ob->data; - if (cu->path) free_path(cu->path); - cu->path = NULL; + if (ob->curve_cache->path) free_path(ob->curve_cache->path); + ob->curve_cache->path = NULL; /* weak! can only use first curve */ - bl = cu->bev.first; + bl = ob->curve_cache->bev.first; if (bl == NULL || !bl->nr) { return; } - nurbs = BKE_curve_nurbs_get(cu); nu = nurbs->first; - cu->path = path = MEM_callocN(sizeof(Path), "calc_curvepath"); + ob->curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath"); /* if POLY: last vertice != first vertice */ cycl = (bl->poly != -1); @@ -598,8 +594,7 @@ void calc_curvepath(Object *ob) static int interval_test(const int min, const int max, int p1, const int cycl) { if (cycl) { - if (p1 < min) p1 = ((p1 - min) % (max - min + 1)) + max + 1; - else if (p1 > max) p1 = ((p1 - min) % (max - min + 1)) + min; + p1 = mod_i(p1 - min, (max - min + 1)) + min; } else { if (p1 < min) p1 = min; @@ -630,15 +625,15 @@ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float qua if (ob == NULL || ob->type != OB_CURVE) return 0; cu = ob->data; - if (cu->path == NULL || cu->path->data == NULL) { + if (ob->curve_cache == NULL || ob->curve_cache->path == NULL || ob->curve_cache->path->data == NULL) { printf("no path!\n"); return 0; } - path = cu->path; + path = ob->curve_cache->path; pp = path->data; /* test for cyclic */ - bl = cu->bev.first; + bl = ob->curve_cache->bev.first; if (!bl) return 0; if (!bl->nr) return 0; if (bl->poly > -1) cycl = 1; @@ -756,14 +751,24 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int persiste DupliObject *dob; Group *group; GroupObject *go; - float mat[4][4], tmat[4][4], id; - + float mat[4][4], ob_obmat_ofs[4][4], id; + if (ob->dup_group == NULL) return; group = ob->dup_group; /* simple preventing of too deep nested groups */ if (level > MAX_DUPLI_RECUR) return; + /* don't access 'ob->obmat' from now on. */ + copy_m4_m4(ob_obmat_ofs, ob->obmat); + + if (!is_zero_v3(group->dupli_ofs)) { + float tvec[3]; + copy_v3_v3(tvec, group->dupli_ofs); + mul_mat3_m4_v3(ob_obmat_ofs, tvec); + sub_v3_v3(ob_obmat_ofs[3], tvec); + } + /* handles animated groups, and */ /* we need to check update for objects that are not in scene... */ @@ -781,14 +786,7 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int persiste if (go->ob != ob) { /* group dupli offset, should apply after everything else */ - if (!is_zero_v3(group->dupli_ofs)) { - copy_m4_m4(tmat, go->ob->obmat); - sub_v3_v3v3(tmat[3], tmat[3], group->dupli_ofs); - mul_m4_m4m4(mat, ob->obmat, tmat); - } - else { - mul_m4_m4m4(mat, ob->obmat, go->ob->obmat); - } + mul_m4_m4m4(mat, ob_obmat_ofs, go->ob->obmat); dob = new_dupli_object(lb, go->ob, mat, ob->lay, persistent_id, level, id, OB_DUPLIGROUP, flag); @@ -802,7 +800,7 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int persiste if (go->ob->transflag & OB_DUPLI) { copy_m4_m4(dob->ob->obmat, dob->mat); - object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, persistent_id, level + 1, id, flag); + object_duplilist_recursive(&group->id, scene, go->ob, lb, ob_obmat_ofs, persistent_id, level + 1, id, flag); copy_m4_m4(dob->ob->obmat, dob->omat); } } @@ -1332,7 +1330,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p psys_check_group_weights(part); - psys->lattice = psys_get_lattice(&sim); + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); /* gather list of objects or single object */ if (part->ren_as == PART_DRAW_GR) { @@ -1569,9 +1567,9 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p if (obcopylist) MEM_freeN(obcopylist); - if (psys->lattice) { - end_latt_deform(psys->lattice); - psys->lattice = NULL; + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; } } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 4b05b0800a5..74578266c63 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -42,6 +42,7 @@ #include "BLI_blenlib.h" #include "BLI_alloca.h" #include "BLI_dynstr.h" +#include "BLI_listbase.h" #include "BLF_translation.h" @@ -759,6 +760,76 @@ void BKE_animdata_fix_paths_rename(ID *owner_id, AnimData *adt, ID *ref_id, cons MEM_freeN(newN); } +/* *************************** */ +/* remove of individual paths */ + +/* Check RNA-Paths for a list of F-Curves */ +static void fcurves_path_remove_fix(const char *prefix, ListBase *curves) +{ + FCurve *fcu, *fcn; + if (!prefix) return; + + /* we need to check every curve... */ + for (fcu = curves->first; fcu; fcu = fcn) { + fcn = fcu->next; + + if (fcu->rna_path) { + if (STRPREFIX(fcu->rna_path, prefix)) { + BLI_remlink(curves, fcu); + free_fcurve(fcu); + } + } + } +} + +/* Check RNA-Paths for a list of F-Curves */ +static void nlastrips_path_remove_fix(const char *prefix, ListBase *strips) +{ + NlaStrip *strip; + + /* recursively check strips, fixing only actions... */ + for (strip = strips->first; strip; strip = strip->next) { + + /* fix strip's action */ + if (strip->act) + fcurves_path_remove_fix(prefix, &strip->act->curves); + + /* check sub-strips (if metas) */ + nlastrips_path_remove_fix(prefix, &strip->strips); + } +} + +void BKE_animdata_fix_paths_remove(ID *id, const char *prefix) +{ + /* Only some ID-blocks have this info for now, so we cast the + * types that do to be of type IdAdtTemplate + */ + NlaTrack *nlt; + + if (id_type_can_have_animdata(id)) { + IdAdtTemplate *iat = (IdAdtTemplate *)id; + AnimData *adt = iat->adt; + + /* check if there's any AnimData to start with */ + if (adt) { + + /* free fcurves */ + if (adt->action) + fcurves_path_remove_fix(prefix, &adt->action->curves); + + if (adt->tmpact) + fcurves_path_remove_fix(prefix, &adt->tmpact->curves); + + /* free drivers - stored as a list of F-Curves */ + fcurves_path_remove_fix(prefix, &adt->drivers); + + /* NLA Data - Animation Data for Strips */ + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) + nlastrips_path_remove_fix(prefix, &nlt->strips); + } + } +} + /* Whole Database Ops -------------------------------------------- */ /* apply the given callback function on all data in main database */ @@ -1652,19 +1723,19 @@ static void nlaevalchan_value_init(NlaEvalChannel *nec) */ switch (RNA_property_type(prop)) { case PROP_BOOLEAN: - if (RNA_property_array_length(ptr, prop)) + if (RNA_property_array_check(prop)) nec->value = (float)RNA_property_boolean_get_default_index(ptr, prop, index); else nec->value = (float)RNA_property_boolean_get_default(ptr, prop); break; case PROP_INT: - if (RNA_property_array_length(ptr, prop)) + if (RNA_property_array_check(prop)) nec->value = (float)RNA_property_int_get_default_index(ptr, prop, index); else nec->value = (float)RNA_property_int_get_default(ptr, prop); break; case PROP_FLOAT: - if (RNA_property_array_length(ptr, prop)) + if (RNA_property_array_check(prop)) nec->value = RNA_property_float_get_default_index(ptr, prop, index); else nec->value = RNA_property_float_get_default(ptr, prop); @@ -2071,19 +2142,19 @@ void nladata_flush_channels(ListBase *channels) /* write values - see animsys_write_rna_setting() to sync the code */ switch (RNA_property_type(prop)) { case PROP_BOOLEAN: - if (RNA_property_array_length(ptr, prop)) + if (RNA_property_array_check(prop)) RNA_property_boolean_set_index(ptr, prop, array_index, ANIMSYS_FLOAT_AS_BOOL(value)); else RNA_property_boolean_set(ptr, prop, ANIMSYS_FLOAT_AS_BOOL(value)); break; case PROP_INT: - if (RNA_property_array_length(ptr, prop)) + if (RNA_property_array_check(prop)) RNA_property_int_set_index(ptr, prop, array_index, (int)value); else RNA_property_int_set(ptr, prop, (int)value); break; case PROP_FLOAT: - if (RNA_property_array_length(ptr, prop)) + if (RNA_property_array_check(prop)) RNA_property_float_set_index(ptr, prop, array_index, value); else RNA_property_float_set(ptr, prop, value); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index f006710dc21..6b2b782717d 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -381,8 +381,6 @@ int bone_autoside_name(char name[MAXBONENAME], int UNUSED(strip_number), short a /* ************* B-Bone support ******************* */ -#define MAX_BBONE_SUBDIV 32 - /* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */ static void equalize_bezier(float *data, int desired) { @@ -426,11 +424,8 @@ static void equalize_bezier(float *data, int desired) /* returns pointer to static array, filled with desired amount of bone->segments elements */ /* this calculation is done within unit bone space */ -Mat4 *b_bone_spline_setup(bPoseChannel *pchan, int rest) +void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV]) { - static Mat4 bbone_array[MAX_BBONE_SUBDIV]; - static Mat4 bbone_rest_array[MAX_BBONE_SUBDIV]; - Mat4 *result_array = (rest) ? bbone_rest_array : bbone_array; bPoseChannel *next, *prev; Bone *bone = pchan->bone; float h1[3], h2[3], scale[3], length, hlength1, hlength2, roll1 = 0.0f, roll2; @@ -587,8 +582,6 @@ Mat4 *b_bone_spline_setup(bPoseChannel *pchan, int rest) mul_serie_m4(result_array[a].mat, iscalemat, result_array[a].mat, scalemat, NULL, NULL, NULL, NULL, NULL); } } - - return result_array; } /* ************ Armature Deform ******************* */ @@ -602,13 +595,15 @@ typedef struct bPoseChanDeform { static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info, int use_quaternion) { Bone *bone = pchan->bone; - Mat4 *b_bone = b_bone_spline_setup(pchan, 0); - Mat4 *b_bone_rest = b_bone_spline_setup(pchan, 1); + Mat4 b_bone[MAX_BBONE_SUBDIV], b_bone_rest[MAX_BBONE_SUBDIV]; Mat4 *b_bone_mats; DualQuat *b_bone_dual_quats = NULL; float tmat[4][4] = MAT4_UNITY; int a; + b_bone_spline_setup(pchan, 0, b_bone); + b_bone_spline_setup(pchan, 1, b_bone_rest); + /* allocate b_bone matrices and dual quats */ b_bone_mats = MEM_mallocN((1 + bone->segments) * sizeof(Mat4), "BBone defmats"); pdef_info->b_bone_mats = b_bone_mats; @@ -1826,18 +1821,16 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos * - this is a workaround for a depsgraph bug... */ if (ikData->tar) { - Curve *cu = ikData->tar->data; - /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, * currently for paths to work it needs to go through the bevlist/displist system (ton) */ /* only happens on reload file, but violates depsgraph still... fix! */ - if (ELEM(NULL, cu->path, cu->path->data)) { + if (ELEM3(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { BKE_displist_make_curveTypes(scene, ikData->tar, 0); /* path building may fail in EditMode after removing verts [#33268]*/ - if (ELEM(NULL, cu->path, cu->path->data)) { + if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { /* BLI_assert(cu->path != NULL); */ return; } @@ -1901,7 +1894,6 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos * since it's easier to determine the positions of all the joints beforehand this way */ if ((ikData->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) && (totLength != 0.0f)) { - Curve *cu = (Curve *)ikData->tar->data; float splineLen, maxScale; int i; @@ -1914,7 +1906,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos /* get the current length of the curve */ /* NOTE: this is assumed to be correct even after the curve was resized */ - splineLen = cu->path->totdist; + splineLen = ikData->tar->curve_cache->path->totdist; /* calculate the scale factor to multiply all the path values by so that the * bone chain retains its current length, such that diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 26f481e5341..5ef39e8d48e 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -462,13 +462,16 @@ int BKE_read_file(bContext *C, const char *filepath, ReportList *reports) return (bfd ? retval : BKE_READ_FILE_FAIL); } -int BKE_read_file_from_memory(bContext *C, const void *filebuf, int filelength, ReportList *reports) +int BKE_read_file_from_memory(bContext *C, const void *filebuf, int filelength, ReportList *reports, int update_defaults) { BlendFileData *bfd; bfd = BLO_read_from_memory(filebuf, filelength, reports); - if (bfd) + if (bfd) { + if (update_defaults) + BLO_update_defaults_startup_blend(bfd->main); setup_app_data(C, bfd, "<memory2>"); + } else BKE_reports_prepend(reports, "Loading failed: "); @@ -924,9 +927,7 @@ int BKE_copybuffer_save(const char *filename, ReportList *reports) ID *id; ListBase *lb1 = lbarray[a], *lb2 = fromarray[a]; - while (lb2->first) { - id = lb2->first; - BLI_remlink(lb2, id); + while ((id = BLI_pophead(lb2))) { BLI_addtail(lb1, id); id_sort_by_name(lb1, id); } diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index cf761bf3dab..a8d64ea9fb6 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -206,6 +206,8 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues * BVHTreeRayHit hit; float radius = val->personal_space * pa->size, ray_dir[3]; + memset(&col, 0, sizeof(ParticleCollision)); + copy_v3_v3(col.co1, pa->prev_state.co); add_v3_v3v3(col.co2, pa->prev_state.co, pa->prev_state.vel); sub_v3_v3v3(ray_dir, col.co2, col.co1); @@ -253,7 +255,8 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues * //check boids in own system if (acbr->options & BRULE_ACOLL_WITH_BOIDS) { - neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, acbr->look_ahead * len_v3(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn); + neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, pa->prev_state.co, pa->prev_state.ave, + &ptn, acbr->look_ahead * len_v3(pa->prev_state.vel)); if (neighbors > 1) for (n=1; n<neighbors; n++) { copy_v3_v3(co1, pa->prev_state.co); copy_v3_v3(vel1, pa->prev_state.vel); @@ -299,7 +302,8 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues * ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); if (epsys) { - neighbors = BLI_kdtree_range_search(epsys->tree, acbr->look_ahead * len_v3(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn); + neighbors = BLI_kdtree_range_search(epsys->tree, pa->prev_state.co, pa->prev_state.ave, + &ptn, acbr->look_ahead * len_v3(pa->prev_state.vel)); if (neighbors > 0) for (n=0; n<neighbors; n++) { copy_v3_v3(co1, pa->prev_state.co); copy_v3_v3(vel1, pa->prev_state.vel); @@ -354,7 +358,8 @@ static int rule_separate(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues ParticleTarget *pt; float len = 2.0f * val->personal_space * pa->size + 1.0f; float vec[3] = {0.0f, 0.0f, 0.0f}; - int neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn); + int neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, pa->prev_state.co, NULL, + &ptn, 2.0f * val->personal_space * pa->size); int ret = 0; if (neighbors > 1 && ptn[1].dist!=0.0f) { @@ -372,7 +377,8 @@ static int rule_separate(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); if (epsys) { - neighbors = BLI_kdtree_range_search(epsys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn); + neighbors = BLI_kdtree_range_search(epsys->tree, pa->prev_state.co, NULL, + &ptn, 2.0f * val->personal_space * pa->size); if (neighbors > 0 && ptn[0].dist < len) { sub_v3_v3v3(vec, pa->prev_state.co, ptn[0].co); @@ -392,7 +398,7 @@ static int rule_flock(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues *UN { KDTreeNearest ptn[11]; float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; - int neighbors = BLI_kdtree_find_n_nearest(bbd->sim->psys->tree, 11, pa->state.co, pa->prev_state.ave, ptn); + int neighbors = BLI_kdtree_find_nearest_n(bbd->sim->psys->tree, pa->state.co, pa->prev_state.ave, ptn, 11); int n; int ret = 0; @@ -619,7 +625,8 @@ static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, Parti int n, ret = 0; /* calculate own group strength */ - int neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn); + int neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, pa->prev_state.co, NULL, + &ptn, fbr->distance); for (n=0; n<neighbors; n++) { bpa = bbd->sim->psys->particles[ptn[n].index].boid; health += bpa->data.health; @@ -635,7 +642,8 @@ static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, Parti if (epsys) { epars = epsys->particles; - neighbors = BLI_kdtree_range_search(epsys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn); + neighbors = BLI_kdtree_range_search(epsys->tree, pa->prev_state.co, NULL, + &ptn, fbr->distance); health = 0.0f; @@ -771,6 +779,8 @@ static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float grou if (!bbd->sim->colliders) return NULL; + memset(&col, 0, sizeof(ParticleCollision)); + /* first try to find below boid */ copy_v3_v3(col.co1, pa->state.co); sub_v3_v3v3(col.co2, pa->state.co, zvec); diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 4018b757559..b7a6cf4153a 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -76,7 +76,7 @@ #include "BKE_node.h" #include "BKE_report.h" #include "BKE_sequencer.h" -#include "BKE_image.h" /* so we can check the image's type */ +#include "BKE_image.h" #include "BKE_bpath.h" /* own include */ @@ -297,7 +297,14 @@ static bool findMissingFiles_visit_cb(void *userdata, char *path_dst, const char return false; } else { + bool was_relative = BLI_path_is_rel(path_dst); + BLI_strncpy(path_dst, filename_new, FILE_MAX); + + /* keep path relative if the previous one was relative */ + if (was_relative) + BLI_path_rel(path_dst, data->basedir); + return true; } } @@ -307,6 +314,7 @@ void BKE_bpath_missing_files_find(Main *bmain, const char *searchpath, ReportLis { struct BPathFind_Data data = {NULL}; + data.basedir = bmain->name; data.reports = reports; data.searchdir = searchpath; data.find_all = find_all; @@ -330,6 +338,9 @@ static bool rewrite_path_fixed(char *path, BPathVisitor visit_cb, const char *ab path_src = path; } + /* so functions can check old value */ + BLI_strncpy(path_dst, path, FILE_MAX); + if (visit_cb(userdata, path_dst, path_src)) { BLI_strncpy(path, path_dst, FILE_MAX); return true; @@ -388,6 +399,13 @@ static bool rewrite_path_alloc(char **path, BPathVisitor visit_cb, const char *a } } +/* fix the image user "ok" tag after updating paths, so ImBufs get loaded */ +static void bpath_traverse_image_user_cb(Image *ima, ImageUser *iuser, void *customdata) +{ + if (ima == customdata) + iuser->ok = 1; +} + /* Run visitor function 'visit' on all paths contained in 'id'. */ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int flag, void *bpath_user_data) { @@ -404,7 +422,12 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int ima = (Image *)id; if (ima->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) { if (ELEM3(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { - rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data); + if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) { + if (!ima->packedfile) { + BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); + BKE_image_walk_all_users(bmain, ima, bpath_traverse_image_user_cb); + } + } } } break; diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 70b5d90120d..790c1f09ff0 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -951,7 +951,6 @@ float BKE_brush_curve_strength_clamp(Brush *br, float p, const float len) if (p >= len) return 0; else p = p / len; - curvemapping_initialize(br->curve); strength = curvemapping_evaluateF(br->curve, 0, p); CLAMP(strength, 0.0f, 1.0f); @@ -967,15 +966,14 @@ float BKE_brush_curve_strength(Brush *br, float p, const float len) else p = p / len; - curvemapping_initialize(br->curve); 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) +unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_secondary) { unsigned int *texcache = NULL; - MTex *mtex = &br->mtex; + MTex *mtex = (use_secondary) ? &br->mask_mtex : &br->mtex; TexResult texres = {0}; int hasrgb, ix, iy; int side = half_side * 2; @@ -1016,7 +1014,7 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side) /**** Radial Control ****/ -struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br) +struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary) { ImBuf *im = MEM_callocN(sizeof(ImBuf), "radial control texture"); unsigned int *texcache; @@ -1024,7 +1022,8 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br) int half = side / 2; int i, j; - texcache = BKE_brush_gen_texture_cache(br, half); + curvemapping_initialize(br->curve); + texcache = BKE_brush_gen_texture_cache(br, half, secondary); im->rect_float = MEM_callocN(sizeof(float) * side * side, "radial control rect"); im->x = im->y = side; diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 5b66b8b4cd4..370dbc62ef8 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -355,7 +355,7 @@ float nearest_point_in_tri_surface(const float v0[3], const float v1[3], const f /* - * BVH from meshs callbacks + * BVH from meshes callbacks */ /* Callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_faces. diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index f9444ca2cf9..536ec95e3d1 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -456,9 +456,10 @@ void BKE_camera_view_frame(Scene *scene, Camera *camera, float r_vec[4][3]) 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[4]; + float dist_vals_sq[4]; /* distance squared (signed) */ unsigned int tot; } CameraViewFrameData; @@ -468,9 +469,9 @@ static void camera_to_frame_view_cb(const float co[3], void *user_data) unsigned int i; for (i = 0; i < 4; i++) { - float nd = dist_to_plane_v3(co, data->frame_tx[i], data->normal_tx[i]); - if (nd < data->dist_vals[i]) { - data->dist_vals[i] = nd; + float nd = dist_squared_to_plane_v3(co, data->plane_tx[i]); + if (nd < data->dist_vals_sq[i]) { + data->dist_vals_sq[i] = nd; } } @@ -514,15 +515,12 @@ int BKE_camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object } 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]); + 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]); } /* initialize callback data */ - data_cb.dist_vals[0] = - data_cb.dist_vals[1] = - data_cb.dist_vals[2] = - data_cb.dist_vals[3] = FLT_MAX; + 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, @@ -537,11 +535,16 @@ int BKE_camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object float plane_isect_pt_1[3], plane_isect_pt_2[3]; + /* could make a generic macro */ +#define SQRT_SIGNED(f) copysign(sqrtf(fabsf(f)), f) + /* 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], data_cb.dist_vals[i]); + mul_v3_v3fl(plane_tx[i], data_cb.normal_tx[i], SQRT_SIGNED(data_cb.dist_vals_sq[i])); } +#undef SQRT_SIGNED + 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]); diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 6205c8016b6..1bc12cffe7b 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -1814,7 +1814,13 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *UNUSED(ob)) DerivedMesh *CDDM_from_curve(Object *ob) { - return CDDM_from_curve_displist(ob, &ob->disp); + ListBase disp = {NULL, NULL}; + + if (ob->curve_cache) { + disp = ob->curve_cache->disp; + } + + return CDDM_from_curve_displist(ob, &disp); } DerivedMesh *CDDM_from_curve_displist(Object *ob, ListBase *dispbase) @@ -2399,7 +2405,7 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int STACK_DECLARE(mpoly); STACK_DECLARE(oldp); - EdgeHash *ehash = BLI_edgehash_new(); + EdgeHash *ehash = BLI_edgehash_new_ex(__func__, totedge); int i, j, c; @@ -2601,10 +2607,12 @@ void CDDM_calc_edges_tessface(DerivedMesh *dm) EdgeHashIterator *ehi; MFace *mf = cddm->mface; MEdge *med; - EdgeHash *eh = BLI_edgehash_new(); - int i, *index, numEdges, maxFaces = dm->numTessFaceData; + EdgeHash *eh; + int i, *index, numEdges, numFaces = dm->numTessFaceData; + + eh = BLI_edgehash_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(numFaces)); - for (i = 0; i < maxFaces; i++, mf++) { + for (i = 0; i < numFaces; i++, mf++) { if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2)) BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL); if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3)) @@ -2634,7 +2642,7 @@ void CDDM_calc_edges_tessface(DerivedMesh *dm) for (ehi = BLI_edgehashIterator_new(eh), i = 0; BLI_edgehashIterator_isDone(ehi) == FALSE; - BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) + BLI_edgehashIterator_step(ehi), i++, med++, index++) { BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2); @@ -2662,21 +2670,27 @@ void CDDM_calc_edges(DerivedMesh *dm) MPoly *mp = cddm->mpoly; MLoop *ml; MEdge *med, *origmed; - EdgeHash *eh = BLI_edgehash_new(); + EdgeHash *eh; + unsigned int eh_reserve; int v1, v2; int *eindex; - int i, j, *index, numEdges = cddm->dm.numEdgeData, maxFaces = dm->numPolyData; + int i, j, *index; + const int numFaces = dm->numPolyData; + const int numLoops = dm->numLoopData; + int numEdges = dm->numEdgeData; eindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX); - med = cddm->medge; + + eh_reserve = max_ii(med ? numEdges : 0, BLI_EDGEHASH_SIZE_GUESS_FROM_LOOPS(numLoops)); + eh = BLI_edgehash_new_ex(__func__, eh_reserve); if (med) { for (i = 0; i < numEdges; i++, med++) { BLI_edgehash_insert(eh, med->v1, med->v2, SET_INT_IN_POINTER(i + 1)); } } - for (i = 0; i < maxFaces; i++, mp++) { + for (i = 0; i < numFaces; i++, mp++) { ml = cddm->mloop + mp->loopstart; for (j = 0; j < mp->totloop; j++, ml++) { v1 = ml->v; @@ -2726,7 +2740,7 @@ void CDDM_calc_edges(DerivedMesh *dm) cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); mp = cddm->mpoly; - for (i = 0; i < maxFaces; i++, mp++) { + for (i = 0; i < numFaces; i++, mp++) { ml = cddm->mloop + mp->loopstart; for (j = 0; j < mp->totloop; j++, ml++) { v1 = ml->v; diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 05ffd4a6265..e4c6f7790d7 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -332,11 +332,13 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul if (clmd->clothObject == NULL) { if (!cloth_from_object(ob, clmd, result, framenr, 1)) { BKE_ptcache_invalidate(cache); + modifier_setError(&(clmd->modifier), "Can't initialize cloth"); return 0; } if (clmd->clothObject == NULL) { BKE_ptcache_invalidate(cache); + modifier_setError(&(clmd->modifier), "Null cloth object"); return 0; } @@ -973,6 +975,18 @@ static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm ) * SPRING NETWORK BUILDING IMPLEMENTATION BEGIN ***************************************************************************************/ +BLI_INLINE void spring_verts_ordered_set(ClothSpring *spring, int v0, int v1) +{ + if (v0 < v1) { + spring->ij = v0; + spring->kl = v1; + } + else { + spring->ij = v1; + spring->kl = v0; + } +} + // be careful: implicit solver has to be resettet when using this one! // --> only for implicit handling of this spring! int cloth_add_spring(ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type) @@ -1004,10 +1018,20 @@ int cloth_add_spring(ClothModifierData *clmd, unsigned int indexA, unsigned int return 0; } -static void cloth_free_errorsprings(Cloth *cloth, EdgeHash *UNUSED(edgehash), LinkNode **edgelist) +static void cloth_free_edgelist(LinkNode **edgelist, unsigned int numverts) +{ + if (edgelist) { + unsigned int i; + for (i = 0; i < numverts; i++) { + BLI_linklist_free(edgelist[i], NULL); + } + + MEM_freeN(edgelist); + } +} + +static void cloth_free_errorsprings(Cloth *cloth, LinkNode **edgelist) { - unsigned int i = 0; - if ( cloth->springs != NULL ) { LinkNode *search = cloth->springs; while (search) { @@ -1020,17 +1044,13 @@ static void cloth_free_errorsprings(Cloth *cloth, EdgeHash *UNUSED(edgehash), Li cloth->springs = NULL; } - - if (edgelist) { - for ( i = 0; i < cloth->numverts; i++ ) { - BLI_linklist_free ( edgelist[i], NULL ); - } - MEM_freeN ( edgelist ); - } + cloth_free_edgelist(edgelist, cloth->numverts); - if (cloth->edgehash) - BLI_edgehash_free ( cloth->edgehash, NULL ); + if (cloth->edgehash) { + BLI_edgehash_free(cloth->edgehash, NULL); + cloth->edgehash = NULL; + } } /* update stiffness if vertex group values are changing from frame to frame */ @@ -1094,30 +1114,25 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) if ( numedges==0 ) return 0; + /* NOTE: handling ownership of sptings and edgehash is quite sloppy + * currenlty they are never initialized but assert just to be sure */ + BLI_assert(cloth->springs == NULL); + BLI_assert(cloth->edgehash == NULL); + cloth->springs = NULL; + cloth->edgehash = NULL; edgelist = MEM_callocN ( sizeof (LinkNode *) * numverts, "cloth_edgelist_alloc" ); if (!edgelist) return 0; - - for ( i = 0; i < numverts; i++ ) { - edgelist[i] = NULL; - } - - if ( cloth->springs ) - MEM_freeN ( cloth->springs ); - - // create spring network hash - edgehash = BLI_edgehash_new(); // structural springs for ( i = 0; i < numedges; i++ ) { spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if ( spring ) { - spring->ij = MIN2(medge[i].v1, medge[i].v2); - spring->kl = MAX2(medge[i].v2, medge[i].v1); + spring_verts_ordered_set(spring, medge[i].v1, medge[i].v2); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); clmd->sim_parms->avg_spring_len += spring->restlen; cloth->verts[spring->ij].avg_spring_len += spring->restlen; @@ -1132,11 +1147,11 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) BLI_linklist_prepend ( &cloth->springs, spring ); } else { - cloth_free_errorsprings(cloth, edgehash, edgelist); + cloth_free_errorsprings(cloth, edgelist); return 0; } } - + if (struct_springs > 0) clmd->sim_parms->avg_spring_len /= struct_springs; @@ -1153,12 +1168,11 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring"); if (!spring) { - cloth_free_errorsprings(cloth, edgehash, edgelist); + cloth_free_errorsprings(cloth, edgelist); return 0; } - spring->ij = MIN2(mface[i].v1, mface[i].v3); - spring->kl = MAX2(mface[i].v3, mface[i].v1); + spring_verts_ordered_set(spring, mface[i].v1, mface[i].v3); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; @@ -1174,12 +1188,11 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if (!spring) { - cloth_free_errorsprings(cloth, edgehash, edgelist); + cloth_free_errorsprings(cloth, edgelist); return 0; } - spring->ij = MIN2(mface[i].v2, mface[i].v4); - spring->kl = MAX2(mface[i].v4, mface[i].v2); + spring_verts_ordered_set(spring, mface[i].v2, mface[i].v4); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_SHEAR; spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f; @@ -1191,6 +1204,9 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) BLI_linklist_prepend ( &cloth->springs, spring ); } + edgehash = BLI_edgehash_new_ex(__func__, numedges); + cloth->edgehash = edgehash; + if (numfaces) { // bending springs search2 = cloth->springs; @@ -1206,18 +1222,17 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) // check for existing spring // check also if startpoint is equal to endpoint - if (!BLI_edgehash_haskey(edgehash, MIN2(tspring2->ij, index2), MAX2(tspring2->ij, index2)) && - (index2 != tspring2->ij)) + if ((index2 != tspring2->ij) && + !BLI_edgehash_haskey(edgehash, tspring2->ij, index2)) { spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if (!spring) { - cloth_free_errorsprings(cloth, edgehash, edgelist); + cloth_free_errorsprings(cloth, edgelist); return 0; } - spring->ij = MIN2(tspring2->ij, index2); - spring->kl = MAX2(tspring2->ij, index2); + spring_verts_ordered_set(spring, tspring2->ij, index2); spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f; @@ -1249,7 +1264,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); if (!spring) { - cloth_free_errorsprings(cloth, edgehash, edgelist); + cloth_free_errorsprings(cloth, edgelist); return 0; } @@ -1268,34 +1283,30 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) } } + /* note: the edges may already exist so run reinsert */ + /* insert other near springs in edgehash AFTER bending springs are calculated (for selfcolls) */ for (i = 0; i < numedges; i++) { /* struct springs */ - BLI_edgehash_insert(edgehash, MIN2(medge[i].v1, medge[i].v2), MAX2(medge[i].v2, medge[i].v1), NULL); + BLI_edgehash_reinsert(edgehash, medge[i].v1, medge[i].v2, NULL); } for (i = 0; i < numfaces; i++) { /* edge springs */ if (mface[i].v4) { - BLI_edgehash_insert(edgehash, MIN2(mface[i].v1, mface[i].v3), MAX2(mface[i].v3, mface[i].v1), NULL); + BLI_edgehash_reinsert(edgehash, mface[i].v1, mface[i].v3, NULL); - BLI_edgehash_insert(edgehash, MIN2(mface[i].v2, mface[i].v4), MAX2(mface[i].v2, mface[i].v4), NULL); + BLI_edgehash_reinsert(edgehash, mface[i].v2, mface[i].v4, NULL); } } cloth->numsprings = struct_springs + shear_springs + bend_springs; - if ( edgelist ) { - for ( i = 0; i < numverts; i++ ) { - BLI_linklist_free ( edgelist[i], NULL ); - } - - MEM_freeN ( edgelist ); - } - - cloth->edgehash = edgehash; - + cloth_free_edgelist(edgelist, numverts); + +#if 0 if (G.debug_value > 0) printf("avg_len: %f\n", clmd->sim_parms->avg_spring_len); +#endif return 1; diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 91a09bb8554..e3081b9e670 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -281,7 +281,7 @@ static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionM /* Decrease in magnitude of relative tangential velocity due to coulomb friction * in original formula "magrelVel" should be the "change of relative velocity in normal direction" */ - magtangent = min_ff(clmd->coll_parms->friction * 0.01f * magrelVel, sqrtf(dot_v3v3(vrel_t_pre, vrel_t_pre))); + magtangent = min_ff(clmd->coll_parms->friction * 0.01f * magrelVel, len_v3(vrel_t_pre)); /* Apply friction impulse. */ if ( magtangent > ALMOST_ZERO ) { @@ -865,8 +865,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa if ( ( ABS ( temp[0] ) > mindistance ) || ( ABS ( temp[1] ) > mindistance ) || ( ABS ( temp[2] ) > mindistance ) ) continue; - // check for adjacent points (i must be smaller j) - if ( BLI_edgehash_haskey ( cloth->edgehash, MIN2(i, j), MAX2(i, j) ) ) { + if (BLI_edgehash_haskey(cloth->edgehash, i, j)) { continue; } diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 7e878e86c1e..578fa5d348d 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -972,9 +972,6 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM if (ibuf->rect_float) cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings); - /* persistent draw */ - hist->flag |= HISTO_FLAG_SAMPLELINE; /* keep drawing the flag after */ - for (i = 0; i < 256; i++) { x = (int)(0.5f + x1 + (float)i * (x2 - x1) / 255.0f); y = (int)(0.5f + y1 + (float)i * (y2 - y1) / 255.0f); @@ -1260,6 +1257,7 @@ void BKE_color_managed_view_settings_init(ColorManagedViewSettings *settings) * for now use NONE to be compatible with all current files */ BLI_strncpy(settings->view_transform, "Default", sizeof(settings->view_transform)); + BLI_strncpy(settings->look, "None", sizeof(settings->look)); settings->gamma = 1.0f; settings->exposure = 0.0f; @@ -1268,6 +1266,7 @@ void BKE_color_managed_view_settings_init(ColorManagedViewSettings *settings) void BKE_color_managed_view_settings_copy(ColorManagedViewSettings *new_settings, const ColorManagedViewSettings *settings) { + BLI_strncpy(new_settings->look, settings->look, sizeof(new_settings->look)); BLI_strncpy(new_settings->view_transform, settings->view_transform, sizeof(new_settings->view_transform)); new_settings->flag = settings->flag; diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index eda770ddf30..1f892432d80 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -69,6 +69,7 @@ #include "BKE_bvhutils.h" #include "BKE_camera.h" #include "BKE_constraint.h" +#include "BKE_curve.h" #include "BKE_displist.h" #include "BKE_deform.h" #include "BKE_DerivedMesh.h" /* for geometry targets */ @@ -448,7 +449,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m { Lattice *lt = (Lattice *)ob->data; - DispList *dl = BKE_displist_find(&ob->disp, DL_VERTS); + DispList *dl = ob->curve_cache ? BKE_displist_find(&ob->curve_cache->disp, DL_VERTS) : NULL; float *co = dl ? dl->verts : NULL; BPoint *bp = lt->def; @@ -1163,10 +1164,10 @@ static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra */ /* only happens on reload file, but violates depsgraph still... fix! */ - if (cu->path == NULL || cu->path->data == NULL) + if (ct->tar->curve_cache == NULL || ct->tar->curve_cache->path == NULL || ct->tar->curve_cache->path->data == NULL) BKE_displist_make_curveTypes(cob->scene, ct->tar, 0); - if (cu->path && cu->path->data) { + if (ct->tar->curve_cache->path && ct->tar->curve_cache->path->data) { float quat[4]; if ((data->followflag & FOLLOWPATH_STATIC) == 0) { /* animated position along curve depending on time */ @@ -1933,10 +1934,8 @@ static void pycon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTa if (VALID_CONS_TARGET(ct)) { /* special exception for curves - depsgraph issues */ if (ct->tar->type == OB_CURVE) { - Curve *cu = ct->tar->data; - /* this check is to make sure curve objects get updated on file load correctly.*/ - if (cu->path == NULL || cu->path->data == NULL) /* only happens on reload file, but violates depsgraph still... fix! */ + if (ct->tar->curve_cache == NULL || ct->tar->curve_cache->path == NULL || ct->tar->curve_cache->path->data == NULL) /* only happens on reload file, but violates depsgraph still... fix! */ BKE_displist_make_curveTypes(cob->scene, ct->tar, 0); } @@ -3009,14 +3008,12 @@ static void clampto_flush_tars(bConstraint *con, ListBase *list, short nocopy) static void clampto_get_tarmat(bConstraint *UNUSED(con), bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) { if (VALID_CONS_TARGET(ct)) { - Curve *cu = ct->tar->data; - /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, * currently for paths to work it needs to go through the bevlist/displist system (ton) */ /* only happens on reload file, but violates depsgraph still... fix! */ - if (cu->path == NULL || cu->path->data == NULL) + if (ct->tar->curve_cache == NULL || ct->tar->curve_cache->path == NULL || ct->tar->curve_cache->path->data == NULL) BKE_displist_make_curveTypes(cob->scene, ct->tar, 0); } @@ -3034,7 +3031,6 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar /* only evaluate if there is a target and it is a curve */ if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) { - Curve *cu = data->tar->data; float obmat[4][4], ownLoc[3]; float curveMin[3], curveMax[3]; float targetMatrix[4][4] = MAT4_UNITY; @@ -3047,7 +3043,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar BKE_object_minmax(ct->tar, curveMin, curveMax, TRUE); /* get targetmatrix */ - if (cu->path && cu->path->data) { + if (data->tar->curve_cache && data->tar->curve_cache->path && data->tar->curve_cache->path->data) { float vec[4], dir[3], totmat[4][4]; float curvetime; short clamp_axis; @@ -3312,6 +3308,14 @@ static void shrinkwrap_id_looper(bConstraint *con, ConstraintIDFunc func, void * func(con, (ID **)&data->target, FALSE, userdata); } +static void shrinkwrap_new_data(void *cdata) +{ + bShrinkwrapConstraint *data = (bShrinkwrapConstraint *)cdata; + + data->projAxis = OB_POSZ; + data->projAxisSpace = CONSTRAINT_SPACE_LOCAL; +} + static int shrinkwrap_get_tars(bConstraint *con, ListBase *list) { if (con && list) { @@ -3343,24 +3347,14 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data; if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_MESH) ) { - int fail = FALSE; + bool fail = false; float co[3] = {0.0f, 0.0f, 0.0f}; - float no[3] = {0.0f, 0.0f, 0.0f}; - float dist; SpaceTransform transform; DerivedMesh *target = object_get_derived_final(ct->tar); - BVHTreeRayHit hit; - BVHTreeNearest nearest; BVHTreeFromMesh treeData = {NULL}; - nearest.index = -1; - nearest.dist = FLT_MAX; - - hit.index = -1; - hit.dist = 100000.0f; //TODO should use FLT_MAX.. but normal projection doenst yet supports it - unit_m4(ct->matrix); if (target != NULL) { @@ -3369,7 +3363,13 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra switch (scon->shrinkType) { case MOD_SHRINKWRAP_NEAREST_SURFACE: case MOD_SHRINKWRAP_NEAREST_VERTEX: - + { + BVHTreeNearest nearest; + float dist; + + nearest.index = -1; + nearest.dist = FLT_MAX; + if (scon->shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) bvhtree_from_mesh_verts(&treeData, target, 0.0, 2, 6); else @@ -3390,32 +3390,54 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra } space_transform_invert(&transform, co); break; - + } case MOD_SHRINKWRAP_PROJECT: - if (scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) no[0] = 1.0f; - if (scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) no[1] = 1.0f; - if (scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) no[2] = 1.0f; + { + BVHTreeRayHit hit; + + float mat[4][4]; + float no[3] = {0.0f, 0.0f, 0.0f}; + + /* TODO should use FLT_MAX.. but normal projection doenst yet supports it */ + hit.index = -1; + hit.dist = (scon->projLimit == 0.0f) ? 100000.0f : scon->projLimit; + + switch (scon->projAxis) { + case OB_POSX: case OB_POSY: case OB_POSZ: + no[scon->projAxis - OB_POSX] = 1.0f; + break; + case OB_NEGX: case OB_NEGY: case OB_NEGZ: + no[scon->projAxis - OB_NEGX] = -1.0f; + break; + } - if (dot_v3v3(no, no) < FLT_EPSILON) { + /* transform normal into requested space */ + unit_m4(mat); + BKE_constraint_mat_convertspace(cob->ob, cob->pchan, mat, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace); + invert_m4(mat); + mul_mat3_m4_v3(mat, no); + + if (normalize_v3(no) < FLT_EPSILON) { fail = TRUE; break; } - - normalize_v3(no); - - + bvhtree_from_mesh_faces(&treeData, target, scon->dist, 4, 6); if (treeData.tree == NULL) { fail = TRUE; break; } + - if (normal_projection_project_vertex(0, co, no, &transform, treeData.tree, &hit, treeData.raycast_callback, &treeData) == FALSE) { + if (BKE_shrinkwrap_project_normal(0, co, no, &transform, treeData.tree, &hit, + treeData.raycast_callback, &treeData) == false) + { fail = TRUE; break; } copy_v3_v3(co, hit.co); break; + } } free_bvhtree_from_mesh(&treeData); @@ -3452,7 +3474,7 @@ static bConstraintTypeInfo CTI_SHRINKWRAP = { NULL, /* free data */ shrinkwrap_id_looper, /* id looper */ NULL, /* copy data */ - NULL, /* new data */ + shrinkwrap_new_data, /* new data */ shrinkwrap_get_tars, /* get constraint targets */ shrinkwrap_flush_tars, /* flush constraint targets */ shrinkwrap_get_tarmat, /* get a target matrix */ @@ -3650,14 +3672,12 @@ static void splineik_flush_tars(bConstraint *con, ListBase *list, short nocopy) static void splineik_get_tarmat(bConstraint *UNUSED(con), bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime)) { if (VALID_CONS_TARGET(ct)) { - Curve *cu = ct->tar->data; - /* note: when creating constraints that follow path, the curve gets the CU_PATH set now, * currently for paths to work it needs to go through the bevlist/displist system (ton) */ /* only happens on reload file, but violates depsgraph still... fix! */ - if (cu->path == NULL || cu->path->data == NULL) + if (ct->tar->curve_cache == NULL || ct->tar->curve_cache->path == NULL || ct->tar->curve_cache->path->data == NULL) BKE_displist_make_curveTypes(cob->scene, ct->tar, 0); } diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 622b4f6df5a..2eb763831e4 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -198,8 +198,7 @@ void CTX_store_free_list(ListBase *contexts) { bContextStore *ctx; - while ((ctx = contexts->first)) { - BLI_remlink(contexts, ctx); + while ((ctx = BLI_pophead(contexts))) { CTX_store_free(ctx); } } diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 2285d7d8dc0..e255732d3fb 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -145,7 +145,6 @@ void BKE_curve_editNurb_free(Curve *cu) void BKE_curve_free(Curve *cu) { BKE_nurbList_free(&cu->nurb); - BLI_freelistN(&cu->bev); BKE_displist_free(&cu->disp); BKE_curve_editfont_free(cu); @@ -161,8 +160,6 @@ void BKE_curve_free(Curve *cu) MEM_freeN(cu->strinfo); if (cu->bb) MEM_freeN(cu->bb); - if (cu->path) - free_path(cu->path); if (cu->tb) MEM_freeN(cu->tb); } @@ -229,8 +226,6 @@ Curve *BKE_curve_copy(Curve *cu) if (cun->key) cun->key->from = (ID *)cun; cun->disp.first = cun->disp.last = NULL; - cun->bev.first = cun->bev.last = NULL; - cun->path = NULL; cun->editnurb = NULL; cun->editfont = NULL; @@ -372,62 +367,76 @@ void BKE_curve_type_test(Object *ob) BKE_curve_curve_dimension_update((Curve *)ob->data); } -void BKE_curve_texspace_calc(Curve *cu) +void BKE_curve_boundbox_calc(Curve *cu, float r_loc[3], float r_size[3]) { - DispList *dl; BoundBox *bb; - float *fp, min[3], max[3]; - int tot, do_it = FALSE; + float min[3], max[3]; + float mloc[3], msize[3]; - if (cu->bb == NULL) - cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox"); + if (cu->bb == NULL) cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox"); bb = cu->bb; + if (!r_loc) r_loc = mloc; + if (!r_size) r_size = msize; + INIT_MINMAX(min, max); + BKE_displist_minmax(&cu->disp, min, max); + mid_v3_v3v3(r_loc, min, max); - dl = cu->disp.first; - while (dl) { - tot = ELEM(dl->type, DL_INDEX3, DL_INDEX4) ? dl->nr : dl->nr * dl->parts; + r_size[0] = (max[0] - min[0]) / 2.0f; + r_size[1] = (max[1] - min[1]) / 2.0f; + r_size[2] = (max[2] - min[2]) / 2.0f; - if (tot) do_it = TRUE; - fp = dl->verts; - while (tot--) { - minmax_v3v3_v3(min, max, fp); - fp += 3; - } - dl = dl->next; - } + BKE_boundbox_init_from_minmax(bb, min, max); - if (do_it == FALSE) { - min[0] = min[1] = min[2] = -1.0f; - max[0] = max[1] = max[2] = 1.0f; - } + bb->flag &= ~BOUNDBOX_DIRTY; +} - BKE_boundbox_init_from_minmax(bb, min, max); +BoundBox *BKE_curve_boundbox_get(Object *ob) +{ + Curve *cu = ob->data; - if (cu->texflag & CU_AUTOSPACE) { - mid_v3_v3v3(cu->loc, min, max); - cu->size[0] = (max[0] - min[0]) / 2.0f; - cu->size[1] = (max[1] - min[1]) / 2.0f; - cu->size[2] = (max[2] - min[2]) / 2.0f; + if (ob->bb) + return ob->bb; - zero_v3(cu->rot); + if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { + BKE_curve_texspace_calc(cu); + } - if (cu->size[0] == 0.0f) cu->size[0] = 1.0f; - else if (cu->size[0] > 0.0f && cu->size[0] < 0.00001f) cu->size[0] = 0.00001f; - else if (cu->size[0] < 0.0f && cu->size[0] > -0.00001f) cu->size[0] = -0.00001f; + return cu->bb; +} - if (cu->size[1] == 0.0f) cu->size[1] = 1.0f; - else if (cu->size[1] > 0.0f && cu->size[1] < 0.00001f) cu->size[1] = 0.00001f; - else if (cu->size[1] < 0.0f && cu->size[1] > -0.00001f) cu->size[1] = -0.00001f; +void BKE_curve_texspace_calc(Curve *cu) +{ + float loc[3], size[3]; + int a; - if (cu->size[2] == 0.0f) cu->size[2] = 1.0f; - else if (cu->size[2] > 0.0f && cu->size[2] < 0.00001f) cu->size[2] = 0.00001f; - else if (cu->size[2] < 0.0f && cu->size[2] > -0.00001f) cu->size[2] = -0.00001f; + BKE_curve_boundbox_calc(cu, loc, size); + if (cu->texflag & CU_AUTOSPACE) { + for (a = 0; a < 3; a++) { + if (size[a] == 0.0f) size[a] = 1.0f; + else if (size[a] > 0.0f && size[a] < 0.00001f) size[a] = 0.00001f; + else if (size[a] < 0.0f && size[a] > -0.00001f) size[a] = -0.00001f; + } + + copy_v3_v3(cu->loc, loc); + copy_v3_v3(cu->size, size); + zero_v3(cu->rot); } } +void BKE_curve_texspace_get(Curve *cu, float r_loc[3], float r_rot[3], float r_size[3]) +{ + if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { + BKE_curve_texspace_calc(cu); + } + + if (r_loc) copy_v3_v3(r_loc, cu->loc); + if (r_rot) copy_v3_v3(r_rot, cu->rot); + if (r_size) copy_v3_v3(r_size, cu->size); +} + int BKE_nurbList_index_get_co(ListBase *nurb, const int index, float r_co[3]) { Nurb *nu; @@ -1586,10 +1595,10 @@ void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp, int forRende dl = bevdisp.first; } else { - dl = cu->bevobj->disp.first; + dl = cu->bevobj->curve_cache ? cu->bevobj->curve_cache->disp.first : NULL; if (dl == NULL) { BKE_displist_make_curveTypes(scene, cu->bevobj, 0); - dl = cu->bevobj->disp.first; + dl = cu->bevobj->curve_cache->disp.first; } } @@ -1845,15 +1854,15 @@ static bool bevelinside(BevList *bl1, BevList *bl2) } -struct bevelsort { - float left; +struct BevelSort { BevList *bl; + float left; int dir; }; static int vergxcobev(const void *a1, const void *a2) { - const struct bevelsort *x1 = a1, *x2 = a2; + const struct BevelSort *x1 = a1, *x2 = a2; if (x1->left > x2->left) return 1; @@ -2372,12 +2381,23 @@ static void make_bevel_list_2D(BevList *bl) /* note: bevp->dir and bevp->quat are not needed for beveling but are * used when making a path from a 2D curve, therefor they need to be set - Campbell */ - BevPoint *bevp2 = (BevPoint *)(bl + 1); - BevPoint *bevp1 = bevp2 + (bl->nr - 1); - BevPoint *bevp0 = bevp1 - 1; + BevPoint *bevp0, *bevp1, *bevp2; int nr; - nr = bl->nr; + if (bl->poly != -1) { + bevp2 = (BevPoint *)(bl + 1); + bevp1 = bevp2 + (bl->nr - 1); + bevp0 = bevp1 - 1; + nr = bl->nr; + } + else { + bevp0 = (BevPoint *)(bl + 1); + bevp1 = bevp0 + 1; + bevp2 = bevp1 + 1; + + nr = bl->nr - 2; + } + while (nr--) { const float x1 = bevp1->vec[0] - bevp0->vec[0]; const float x2 = bevp1->vec[0] - bevp2->vec[0]; @@ -2399,15 +2419,23 @@ static void make_bevel_list_2D(BevList *bl) /* correct non-cyclic cases */ if (bl->poly == -1) { - BevPoint *bevp = (BevPoint *)(bl + 1); - bevp1 = bevp + 1; - bevp->sina = bevp1->sina; - bevp->cosa = bevp1->cosa; + BevPoint *bevp; + float angle; + + /* first */ + bevp = (BevPoint *)(bl + 1); + angle = atan2(bevp->dir[0], bevp->dir[1]) - M_PI / 2.0; + bevp->sina = sinf(angle); + bevp->cosa = cosf(angle); + vec_to_quat(bevp->quat, bevp->dir, 5, 1); + + /* last */ bevp = (BevPoint *)(bl + 1); bevp += (bl->nr - 1); - bevp1 = bevp - 1; - bevp->sina = bevp1->sina; - bevp->cosa = bevp1->cosa; + angle = atan2(bevp->dir[0], bevp->dir[1]) - M_PI / 2.0; + bevp->sina = sinf(angle); + bevp->cosa = cosf(angle); + vec_to_quat(bevp->quat, bevp->dir, 5, 1); } } @@ -2428,7 +2456,7 @@ static void bevlist_firstlast_direction_calc_from_bpoint(Nurb *nu, BevList *bl) } } -void BKE_curve_bevelList_make(Object *ob) +void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) { /* * - convert all curves to polys, with indication of resol and flags for double-vertices @@ -2443,28 +2471,27 @@ void BKE_curve_bevelList_make(Object *ob) BevList *bl, *blnew, *blnext; BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0; float min, inp; - struct bevelsort *sortdata, *sd, *sd1; + struct BevelSort *sortdata, *sd, *sd1; int a, b, nr, poly, resolu = 0, len = 0; int do_tilt, do_radius, do_weight; int is_editmode = 0; + ListBase *bev; /* this function needs an object, because of tflag and upflag */ cu = ob->data; + bev = &ob->curve_cache->bev; + /* do we need to calculate the radius for each point? */ /* do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 : 1; */ /* STEP 1: MAKE POLYS */ - BLI_freelistN(&(cu->bev)); + BLI_freelistN(&(ob->curve_cache->bev)); + nu = nurbs->first; if (cu->editnurb && ob->type != OB_FONT) { - ListBase *nurbs = BKE_curve_editNurbs_get(cu); - nu = nurbs->first; is_editmode = 1; } - else { - nu = cu->nurb.first; - } for (; nu; nu = nu->next) { @@ -2480,12 +2507,12 @@ void BKE_curve_bevelList_make(Object *ob) * enforced in the UI but can go wrong possibly */ if (!BKE_nurb_check_valid_u(nu)) { bl = MEM_callocN(sizeof(BevList) + 1 * sizeof(BevPoint), "makeBevelList1"); - BLI_addtail(&(cu->bev), bl); + BLI_addtail(bev, bl); bl->nr = 0; bl->charidx = nu->charidx; } else { - if (G.is_rendering && cu->resolu_ren != 0) + if (for_render && cu->resolu_ren != 0) resolu = cu->resolu_ren; else resolu = nu->resolu; @@ -2493,7 +2520,7 @@ void BKE_curve_bevelList_make(Object *ob) if (nu->type == CU_POLY) { len = nu->pntsu; bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList2"); - BLI_addtail(&(cu->bev), bl); + BLI_addtail(bev, bl); bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1; bl->nr = len; @@ -2520,7 +2547,7 @@ void BKE_curve_bevelList_make(Object *ob) /* in case last point is not cyclic */ len = resolu * (nu->pntsu + (nu->flagu & CU_NURB_CYCLIC) - 1) + 1; bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelBPoints"); - BLI_addtail(&(cu->bev), bl); + BLI_addtail(bev, bl); bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1; bl->charidx = nu->charidx; @@ -2613,7 +2640,7 @@ void BKE_curve_bevelList_make(Object *ob) len = (resolu * SEGMENTSU(nu)); bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList3"); - BLI_addtail(&(cu->bev), bl); + BLI_addtail(bev, bl); bl->nr = len; bl->dupe_nr = 0; bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1; @@ -2635,12 +2662,19 @@ void BKE_curve_bevelList_make(Object *ob) } /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */ - bl = cu->bev.first; + bl = bev->first; while (bl) { if (bl->nr) { /* null bevel items come from single points */ + bool is_cyclic = bl->poly != -1; nr = bl->nr; - bevp1 = (BevPoint *)(bl + 1); - bevp0 = bevp1 + (nr - 1); + if (is_cyclic) { + bevp1 = (BevPoint *)(bl + 1); + bevp0 = bevp1 + (nr - 1); + } + else { + bevp0 = (BevPoint *)(bl + 1); + bevp1 = bevp0 + 1; + } nr--; while (nr--) { if (fabsf(bevp0->vec[0] - bevp1->vec[0]) < 0.00001f) { @@ -2657,7 +2691,7 @@ void BKE_curve_bevelList_make(Object *ob) } bl = bl->next; } - bl = cu->bev.first; + bl = bev->first; while (bl) { blnext = bl->next; if (bl->nr && bl->dupe_nr) { @@ -2665,8 +2699,8 @@ void BKE_curve_bevelList_make(Object *ob) blnew = MEM_mallocN(sizeof(BevList) + nr * sizeof(BevPoint), "makeBevelList4"); memcpy(blnew, bl, sizeof(BevList)); blnew->nr = 0; - BLI_remlink(&(cu->bev), bl); - BLI_insertlinkbefore(&(cu->bev), blnext, blnew); /* to make sure bevlijst is tuned with nurblist */ + BLI_remlink(bev, bl); + BLI_insertlinkbefore(bev, blnext, blnew); /* to make sure bevlijst is tuned with nurblist */ bevp0 = (BevPoint *)(bl + 1); bevp1 = (BevPoint *)(blnew + 1); nr = bl->nr; @@ -2685,7 +2719,7 @@ void BKE_curve_bevelList_make(Object *ob) } /* STEP 3: POLYS COUNT AND AUTOHOLE */ - bl = cu->bev.first; + bl = bev->first; poly = 0; while (bl) { if (bl->nr && bl->poly >= 0) { @@ -2698,8 +2732,8 @@ void BKE_curve_bevelList_make(Object *ob) /* find extreme left points, also test (turning) direction */ if (poly > 0) { - sd = sortdata = MEM_mallocN(sizeof(struct bevelsort) * poly, "makeBevelList5"); - bl = cu->bev.first; + sd = sortdata = MEM_mallocN(sizeof(struct BevelSort) * poly, "makeBevelList5"); + bl = bev->first; while (bl) { if (bl->poly > 0) { @@ -2740,7 +2774,7 @@ void BKE_curve_bevelList_make(Object *ob) bl = bl->next; } - qsort(sortdata, poly, sizeof(struct bevelsort), vergxcobev); + qsort(sortdata, poly, sizeof(struct BevelSort), vergxcobev); sd = sortdata + 1; for (a = 1; a < poly; a++, sd++) { @@ -2779,7 +2813,7 @@ void BKE_curve_bevelList_make(Object *ob) /* STEP 4: 2D-COSINES or 3D ORIENTATION */ if ((cu->flag & CU_3D) == 0) { /* 2D Curves */ - for (bl = cu->bev.first; bl; bl = bl->next) { + for (bl = bev->first; bl; bl = bl->next) { if (bl->nr < 2) { /* do nothing */ } @@ -2793,7 +2827,7 @@ void BKE_curve_bevelList_make(Object *ob) } else { /* 3D Curves */ - for (bl = cu->bev.first; bl; bl = bl->next) { + for (bl = bev->first; bl; bl = bl->next) { if (bl->nr < 2) { /* do nothing */ } @@ -3057,47 +3091,78 @@ void BKE_nurb_handles_calc(Nurb *nu) /* first, if needed, set handle flags */ calchandlesNurb_intern(nu, FALSE); } +/* similar to BKE_nurb_handle_calc but for curves and + * figures out the previous and next for us */ +void BKE_nurb_handle_calc_simple(Nurb *nu, BezTriple *bezt) +{ + if (nu->pntsu > 1) { + BezTriple *prev = BKE_nurb_bezt_get_prev(nu, bezt); + BezTriple *next = BKE_nurb_bezt_get_next(nu, bezt); + BKE_nurb_handle_calc(bezt, prev, next, 0); + } +} -void BKE_nurb_handles_test(Nurb *nu) +/** + * Use when something has changed handle positions. + * + * The caller needs to recalculate handles. + */ +void BKE_nurb_bezt_handle_test(BezTriple *bezt, const bool use_handle) { - /* use when something has changed with handles. - * it treats all BezTriples with the following rules: - * PHASE 1: do types have to be altered? - * Auto handles: become aligned when selection status is NOT(000 || 111) - * Vector handles: become 'nothing' when (one half selected AND other not) - * PHASE 2: recalculate handles - */ - BezTriple *bezt; - short flag, a; + short flag = 0; - if (nu->type != CU_BEZIER) return; +#define SEL_F1 (1 << 0) +#define SEL_F2 (1 << 1) +#define SEL_F3 (1 << 2) - bezt = nu->bezt; - a = nu->pntsu; - while (a--) { - flag = 0; - if (bezt->f1 & SELECT) - flag++; - if (bezt->f2 & SELECT) - flag += 2; - if (bezt->f3 & SELECT) - flag += 4; + if (use_handle) { + if (bezt->f1 & SELECT) flag |= SEL_F1; + if (bezt->f2 & SELECT) flag |= SEL_F2; + if (bezt->f3 & SELECT) flag |= SEL_F3; + } + else { + flag = (bezt->f2 & SELECT) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0; + } - if (!(flag == 0 || flag == 7) ) { - if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) { /* auto */ - bezt->h1 = HD_ALIGN; - } - if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */ - bezt->h2 = HD_ALIGN; - } + /* check for partial selection */ + if (!ELEM(flag, 0, SEL_F1 | SEL_F2 | SEL_F3)) { + if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) { + bezt->h1 = HD_ALIGN; + } + if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { + bezt->h2 = HD_ALIGN; + } - if (bezt->h1 == HD_VECT) { /* vector */ - if (flag < 4) bezt->h1 = 0; + if (bezt->h1 == HD_VECT) { + if ((!(flag & SEL_F1)) != (!(flag & SEL_F2))) { + bezt->h1 = HD_FREE; } - if (bezt->h2 == HD_VECT) { /* vector */ - if (flag > 3) bezt->h2 = 0; + } + if (bezt->h2 == HD_VECT) { + if ((!(flag & SEL_F3)) != (!(flag & SEL_F2))) { + bezt->h2 = HD_FREE; } } + } + +#undef SEL_F1 +#undef SEL_F2 +#undef SEL_F3 + +} + +void BKE_nurb_handles_test(Nurb *nu, const bool use_handle) +{ + BezTriple *bezt; + short a; + + if (nu->type != CU_BEZIER) + return; + + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + BKE_nurb_bezt_handle_test(bezt, use_handle); bezt++; } @@ -3107,9 +3172,11 @@ void BKE_nurb_handles_test(Nurb *nu) void BKE_nurb_handles_autocalc(Nurb *nu, int flag) { /* checks handle coordinates and calculates type */ + const float eps = 0.0001f; + const float eps_sq = eps * eps; BezTriple *bezt2, *bezt1, *bezt0; - int i, align, leftsmall, rightsmall; + int i; if (nu == NULL || nu->bezt == NULL) return; @@ -3120,54 +3187,54 @@ void BKE_nurb_handles_autocalc(Nurb *nu, int flag) i = nu->pntsu; while (i--) { - align = leftsmall = rightsmall = 0; + bool align = false, leftsmall = false, rightsmall = false; /* left handle: */ if (flag == 0 || (bezt1->f1 & flag) ) { - bezt1->h1 = 0; + bezt1->h1 = HD_FREE; /* distance too short: vectorhandle */ - if (len_v3v3(bezt1->vec[1], bezt0->vec[1]) < 0.0001f) { + if (len_squared_v3v3(bezt1->vec[1], bezt0->vec[1]) < eps_sq) { bezt1->h1 = HD_VECT; - leftsmall = 1; + leftsmall = true; } else { /* aligned handle? */ - if (dist_to_line_v2(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < 0.0001f) { - align = 1; + if (dist_to_line_v2(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < eps) { + align = true; bezt1->h1 = HD_ALIGN; } /* or vector handle? */ - if (dist_to_line_v2(bezt1->vec[0], bezt1->vec[1], bezt0->vec[1]) < 0.0001f) + if (dist_to_line_v2(bezt1->vec[0], bezt1->vec[1], bezt0->vec[1]) < eps) bezt1->h1 = HD_VECT; } } /* right handle: */ if (flag == 0 || (bezt1->f3 & flag) ) { - bezt1->h2 = 0; + bezt1->h2 = HD_FREE; /* distance too short: vectorhandle */ - if (len_v3v3(bezt1->vec[1], bezt2->vec[1]) < 0.0001f) { + if (len_squared_v3v3(bezt1->vec[1], bezt2->vec[1]) < eps_sq) { bezt1->h2 = HD_VECT; - rightsmall = 1; + rightsmall = true; } else { /* aligned handle? */ if (align) bezt1->h2 = HD_ALIGN; /* or vector handle? */ - if (dist_to_line_v2(bezt1->vec[2], bezt1->vec[1], bezt2->vec[1]) < 0.0001f) + if (dist_to_line_v2(bezt1->vec[2], bezt1->vec[1], bezt2->vec[1]) < eps) bezt1->h2 = HD_VECT; } } if (leftsmall && bezt1->h2 == HD_ALIGN) - bezt1->h2 = 0; + bezt1->h2 = HD_FREE; if (rightsmall && bezt1->h1 == HD_ALIGN) - bezt1->h1 = 0; + bezt1->h1 = HD_FREE; /* undesired combination: */ if (bezt1->h1 == HD_ALIGN && bezt1->h2 == HD_VECT) - bezt1->h1 = 0; + bezt1->h1 = HD_FREE; if (bezt1->h2 == HD_ALIGN && bezt1->h1 == HD_VECT) - bezt1->h2 = 0; + bezt1->h2 = HD_FREE; bezt0 = bezt1; bezt1 = bezt2; @@ -3271,6 +3338,33 @@ void BKE_nurbList_handles_set(ListBase *editnurb, short code) } } +void BKE_nurbList_flag_set(ListBase *editnurb, short flag) +{ + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + int a; + + for (nu = editnurb->first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + a = nu->pntsu; + bezt = nu->bezt; + while (a--) { + bezt->f1 = bezt->f2 = bezt->f3 = flag; + bezt++; + } + } + else { + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + while (a--) { + bp->f1 = flag; + bp++; + } + } + } +} + void BKE_nurb_direction_switch(Nurb *nu) { BezTriple *bezt1, *bezt2; @@ -3382,7 +3476,7 @@ void BKE_nurb_direction_switch(Nurb *nu) } -float (*BKE_curve_vertexCos_get(Curve *UNUSED(cu), ListBase *lb, int *numVerts_r))[3] +float (*BKE_curve_nurbs_vertexCos_get(ListBase *lb, int *numVerts_r))[3] { int i, numVerts = *numVerts_r = BKE_nurbList_verts_count(lb); float *co, (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "cu_vcos"); @@ -3411,7 +3505,7 @@ float (*BKE_curve_vertexCos_get(Curve *UNUSED(cu), ListBase *lb, int *numVerts_r return cos; } -void BK_curve_vertexCos_apply(Curve *UNUSED(cu), ListBase *lb, float (*vertexCos)[3]) +void BK_curve_nurbs_vertexCos_apply(ListBase *lb, float (*vertexCos)[3]) { float *co = vertexCos[0]; Nurb *nu; @@ -3439,7 +3533,7 @@ void BK_curve_vertexCos_apply(Curve *UNUSED(cu), ListBase *lb, float (*vertexCos } } -float (*BKE_curve_keyVertexCos_get(Curve *UNUSED(cu), ListBase *lb, float *key))[3] +float (*BKE_curve_nurbs_keyVertexCos_get(ListBase *lb, float *key))[3] { int i, numVerts = BKE_nurbList_verts_count(lb); float *co, (*cos)[3] = MEM_mallocN(sizeof(*cos) * numVerts, "cu_vcos"); @@ -3470,7 +3564,7 @@ float (*BKE_curve_keyVertexCos_get(Curve *UNUSED(cu), ListBase *lb, float *key)) return cos; } -void BKE_curve_keyVertexTilts_apply(Curve *UNUSED(cu), ListBase *lb, float *key) +void BKE_curve_nurbs_keyVertexTilts_apply(ListBase *lb, float *key) { Nurb *nu; int i; diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index d69ec6a9597..8a74f4719d5 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -45,11 +45,12 @@ #include "DNA_ID.h" #include "BLI_utildefines.h" -#include "BLI_blenlib.h" -#include "BLI_linklist.h" +#include "BLI_string.h" +#include "BLI_path_util.h" #include "BLI_math.h" #include "BLI_mempool.h" #include "BLI_utildefines.h" +#include "BLI_alloca.h" #include "BLF_translation.h" @@ -256,7 +257,7 @@ static void layerInterp_mdeformvert(void **sources, const float *weights, /* if this def_nr is not in the list, add it */ if (!node) { - struct MDeformWeight_Link *tmp_dwlink = MEM_mallocN(sizeof(*tmp_dwlink), __func__); + struct MDeformWeight_Link *tmp_dwlink = alloca(sizeof(*tmp_dwlink)); tmp_dwlink->dw.def_nr = dw->def_nr; tmp_dwlink->dw.weight = weight; @@ -286,12 +287,9 @@ static void layerInterp_mdeformvert(void **sources, const float *weights, } if (totweight) { - struct MDeformWeight_Link *node_next; dvert->totweight = totweight; - for (i = 0, node = dest_dwlink; node; node = node_next, i++) { - node_next = node->next; + for (i = 0, node = dest_dwlink; node; node = node->next, i++) { dvert->dw[i] = node->dw; - MEM_freeN(node); } } else { @@ -973,6 +971,11 @@ static void layerDefault_mcol(void *data, int count) } } +static void layerDefault_origindex(void *data, int count) +{ + fill_vn_i((int *)data, count, ORIGINDEX_NONE); +} + static void layerInterp_bweight(void **sources, const float *weights, const float *UNUSED(sub_weights), int count, void *dest) { @@ -1079,7 +1082,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(MCol) * 4, "MCol", 4, N_("Col"), NULL, NULL, layerInterp_mcol, layerSwap_mcol, layerDefault_mcol}, /* 7: CD_ORIGINDEX */ - {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_origindex}, /* 8: CD_NORMAL */ /* 3 floats per normal vector */ {sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL}, @@ -1217,6 +1220,16 @@ const CustomDataMask CD_MASK_BMESH = const CustomDataMask CD_MASK_FACECORNERS = CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL; +const CustomDataMask CD_MASK_EVERYTHING = + CD_MASK_MVERT | CD_MASK_MSTICKY /* DEPRECATED */ | CD_MASK_MDEFORMVERT | CD_MASK_MEDGE | CD_MASK_MFACE | + CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_NORMAL /* | CD_MASK_POLYINDEX */ | CD_MASK_PROP_FLT | + CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | + CD_MASK_MLOOPCOL | CD_MASK_TANGENT | CD_MASK_MDISPS | CD_MASK_PREVIEW_MCOL | CD_MASK_CLOTH_ORCO | CD_MASK_RECAST | + /* BMESH ONLY START */ + CD_MASK_MPOLY | CD_MASK_MLOOP | CD_MASK_SHAPE_KEYINDEX | CD_MASK_SHAPEKEY | CD_MASK_BWEIGHT | CD_MASK_CREASE | + CD_MASK_ORIGSPACE_MLOOP | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_BM_ELEM_PYPTR | + /* BMESH ONLY END */ + CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE; static const LayerTypeInfo *layerType_getInfo(int type) { @@ -1305,7 +1318,7 @@ bool CustomData_merge(const struct CustomData *source, struct CustomData *dest, if (lastflag & CD_FLAG_NOCOPY) continue; else if (!(mask & CD_TYPE_AS_MASK(type))) continue; - else if (number < CustomData_number_of_layers(dest, type)) continue; + else if (CustomData_get_layer_named(dest, type, layer->name)) continue; switch (alloctype) { case CD_ASSIGN: @@ -1449,8 +1462,9 @@ int CustomData_get_named_layer_index(const CustomData *data, int type, const cha int i; for (i = 0; i < data->totlayer; ++i) - if (data->layers[i].type == type && strcmp(data->layers[i].name, name) == 0) - return i; + if (data->layers[i].type == type) + if (strcmp(data->layers[i].name, name) == 0) + return i; return -1; } @@ -1939,13 +1953,61 @@ void CustomData_copy_elements(int type, void *source, void *dest, int count) memcpy(dest, source, typeInfo->size * count); } +static void CustomData_copy_data_layer(const CustomData *source, CustomData *dest, + int src_i, int dest_i, + int source_index, int dest_index, int count) { + const LayerTypeInfo *typeInfo; + int src_offset; + int dest_offset; + + char *src_data = source->layers[src_i].data; + char *dest_data = dest->layers[dest_i].data; + + typeInfo = layerType_getInfo(source->layers[src_i].type); + + src_offset = source_index * typeInfo->size; + dest_offset = dest_index * typeInfo->size; + + if (!src_data || !dest_data) { + if (!(src_data == NULL && dest_data == NULL)) { + printf("%s: warning null data for %s type (%p --> %p), skipping\n", + __func__, layerType_getName(source->layers[src_i].type), + (void *)src_data, (void *)dest_data); + } + return; + } + + if (typeInfo->copy) + typeInfo->copy(src_data + src_offset, + dest_data + dest_offset, + count); + else + memcpy(dest_data + dest_offset, + src_data + src_offset, + count * typeInfo->size); +} + +void CustomData_copy_data_named(const CustomData *source, CustomData *dest, + int source_index, int dest_index, int count) +{ + int src_i, dest_i; + + /* copies a layer at a time */ + for (src_i = 0; src_i < source->totlayer; ++src_i) { + + dest_i = CustomData_get_named_layer_index(dest, source->layers[src_i].type, source->layers[src_i].name); + + /* if we found a matching layer, copy the data */ + if (dest_i > -1) { + CustomData_copy_data_layer(source, dest, src_i, dest_i, source_index, dest_index, count); + } + } +} + void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count) { - const LayerTypeInfo *typeInfo; int src_i, dest_i; - int src_offset; - int dest_offset; /* copies a layer at a time */ dest_i = 0; @@ -1963,32 +2025,8 @@ void CustomData_copy_data(const CustomData *source, CustomData *dest, /* if we found a matching layer, copy the data */ if (dest->layers[dest_i].type == source->layers[src_i].type) { - char *src_data = source->layers[src_i].data; - char *dest_data = dest->layers[dest_i].data; - - typeInfo = layerType_getInfo(source->layers[src_i].type); - - src_offset = source_index * typeInfo->size; - dest_offset = dest_index * typeInfo->size; - - if (!src_data || !dest_data) { - if (src_data != NULL && dest_data != NULL) { - printf("%s: warning null data for %s type (%p --> %p), skipping\n", - __func__, layerType_getName(source->layers[src_i].type), - (void *)src_data, (void *)dest_data); - } - continue; - } + CustomData_copy_data_layer(source, dest, src_i, dest_i, source_index, dest_index, count); - if (typeInfo->copy) - typeInfo->copy(src_data + src_offset, - dest_data + dest_offset, - count); - else - memcpy(dest_data + dest_offset, - src_data + src_offset, - count * typeInfo->size); - /* if there are multiple source & dest layers of the same type, * we don't want to copy all source layers to the same dest, so * increment dest_i diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 4ce06623bae..cb7b4a32feb 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -29,6 +29,7 @@ #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <math.h> @@ -819,12 +820,26 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation"); } +static void build_dag_group(DagForest *dag, DagNode *scenenode, Scene *scene, Group *group, short mask) +{ + GroupObject *go; + + if (group->id.flag & LIB_DOIT) + return; + + group->id.flag |= LIB_DOIT; + + for (go = group->gobject.first; go; go = go->next) { + build_dag_object(dag, scenenode, scene, go->ob, mask); + if (go->ob->dup_group) + build_dag_group(dag, scenenode, scene, go->ob->dup_group, mask); + } +} + DagForest *build_dag(Main *bmain, Scene *sce, short mask) { Base *base; Object *ob; - Group *group; - GroupObject *go; DagNode *node; DagNode *scenenode; DagForest *dag; @@ -841,6 +856,7 @@ DagForest *build_dag(Main *bmain, Scene *sce, short mask) /* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later [#32017] */ tag_main_idcode(bmain, ID_MA, FALSE); tag_main_idcode(bmain, ID_LA, FALSE); + tag_main_idcode(bmain, ID_GR, FALSE); /* add base node for scene. scene is always the first node in DAG */ scenenode = dag_add_node(dag, sce); @@ -852,21 +868,11 @@ DagForest *build_dag(Main *bmain, Scene *sce, short mask) build_dag_object(dag, scenenode, sce, ob, mask); if (ob->proxy) build_dag_object(dag, scenenode, sce, ob->proxy, mask); - - /* handled in next loop */ if (ob->dup_group) - ob->dup_group->id.flag |= LIB_DOIT; + build_dag_group(dag, scenenode, sce, ob->dup_group, mask); } - /* add groups used in current scene objects */ - for (group = bmain->group.first; group; group = group->id.next) { - if (group->id.flag & LIB_DOIT) { - for (go = group->gobject.first; go; go = go->next) { - build_dag_object(dag, scenenode, sce, go->ob, mask); - } - group->id.flag &= ~LIB_DOIT; - } - } + tag_main_idcode(bmain, ID_GR, FALSE); /* Now all relations were built, but we need to solve 1 exceptional case; * When objects have multiple "parents" (for example parent + constraint working on same object) @@ -1927,6 +1933,25 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob) lib_id_recalc_data_tag(bmain, &ob->id); } + +/* recursively update objects in groups, each group is done at most once */ +static void dag_group_update_flags(Main *bmain, Scene *scene, Group *group, const short do_time) +{ + GroupObject *go; + + if (group->id.flag & LIB_DOIT) + return; + + group->id.flag |= LIB_DOIT; + + for (go = group->gobject.first; go; go = go->next) { + if (do_time) + dag_object_time_update_flags(bmain, scene, go->ob); + if (go->ob->dup_group) + dag_group_update_flags(bmain, scene, go->ob->dup_group, do_time); + } +} + /* flag all objects that need recalc, for changes in time for example */ /* do_time: make this optional because undo resets objects to their animated locations without this */ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const short do_time) @@ -1937,6 +1962,8 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const s GroupObject *go; Scene *sce_iter; + tag_main_idcode(bmain, ID_GR, FALSE); + /* set ob flags where animated systems are */ for (SETLOOPER(scene, sce_iter, base)) { ob = base->object; @@ -1951,20 +1978,9 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const s dag_object_time_update_flags(bmain, sce_iter, ob); } - /* handled in next loop */ + /* recursively tag groups with LIB_DOIT, and update flags for objects */ if (ob->dup_group) - ob->dup_group->id.flag |= LIB_DOIT; - } - - if (do_time) { - /* we do groups each once */ - for (group = bmain->group.first; group; group = group->id.next) { - if (group->id.flag & LIB_DOIT) { - for (go = group->gobject.first; go; go = go->next) { - dag_object_time_update_flags(bmain, scene, go->ob); - } - } - } + dag_group_update_flags(bmain, scene, ob->dup_group, do_time); } for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) @@ -2048,6 +2064,26 @@ static void dag_current_scene_layers(Main *bmain, ListBase *lb) } } +static void dag_group_on_visible_update(Group *group) +{ + GroupObject *go; + + if (group->id.flag & LIB_DOIT) + return; + + group->id.flag |= LIB_DOIT; + + for (go = group->gobject.first; go; go = go->next) { + if (ELEM6(go->ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) + go->ob->recalc |= OB_RECALC_DATA; + if (go->ob->proxy_from) + go->ob->recalc |= OB_RECALC_OB; + + if (go->ob->dup_group) + dag_group_on_visible_update(go->ob->dup_group); + } +} + void DAG_on_visible_update(Main *bmain, const short do_time) { ListBase listbase; @@ -2061,8 +2097,6 @@ void DAG_on_visible_update(Main *bmain, const short do_time) Scene *sce_iter; Base *base; Object *ob; - Group *group; - GroupObject *go; DagNode *node; unsigned int lay = dsl->layer, oblay; @@ -2071,6 +2105,7 @@ void DAG_on_visible_update(Main *bmain, const short do_time) * note armature poses or object matrices are preserved and do not * require updates, so we skip those */ dag_scene_flush_layers(scene, lay); + tag_main_idcode(bmain, ID_GR, FALSE); for (SETLOOPER(scene, sce_iter, base)) { ob = base->object; @@ -2080,23 +2115,14 @@ void DAG_on_visible_update(Main *bmain, const short do_time) if ((oblay & lay) & ~scene->lay_updated) { if (ELEM6(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) ob->recalc |= OB_RECALC_DATA; + if (ob->proxy && (ob->proxy_group == NULL)) + ob->proxy->recalc |= OB_RECALC_DATA; if (ob->dup_group) - ob->dup_group->id.flag |= LIB_DOIT; + dag_group_on_visible_update(ob->dup_group); } } - for (group = bmain->group.first; group; group = group->id.next) { - if (group->id.flag & LIB_DOIT) { - for (go = group->gobject.first; go; go = go->next) { - if (ELEM6(go->ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) - go->ob->recalc |= OB_RECALC_DATA; - if (go->ob->proxy_from) - go->ob->recalc |= OB_RECALC_OB; - } - - group->id.flag &= ~LIB_DOIT; - } - } + tag_main_idcode(bmain, ID_GR, FALSE); /* now tag update flags, to ensure deformers get calculated on redraw */ DAG_scene_update_flags(bmain, scene, lay, do_time); @@ -2274,7 +2300,7 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id) * so it should happen tracking-related constraints recalculation * when camera is changing (sergey) */ if (sce->camera && &sce->camera->id == id) { - MovieClip *clip = BKE_object_movieclip_get(sce, sce->camera, 1); + MovieClip *clip = BKE_object_movieclip_get(sce, sce->camera, true); if (clip) dag_id_flush_update(bmain, sce, &clip->id); diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 38a0b848339..6a89ca2cb84 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -43,6 +43,7 @@ #include "DNA_material_types.h" #include "BLI_blenlib.h" +#include "BLI_memarena.h" #include "BLI_math.h" #include "BLI_scanfill.h" #include "BLI_utildefines.h" @@ -62,8 +63,7 @@ #include "BLI_sys_types.h" // for intptr_t support -static void boundbox_displist(Object *ob); -static void boundbox_dispbase(BoundBox *bb, ListBase *dispbase); +static void boundbox_displist_object(Object *ob); void BKE_displist_elem_free(DispList *dl) { @@ -82,11 +82,8 @@ void BKE_displist_free(ListBase *lb) { DispList *dl; - dl = lb->first; - while (dl) { - BLI_remlink(lb, dl); + while ((dl = BLI_pophead(lb))) { BKE_displist_elem_free(dl); - dl = lb->first; } } @@ -454,6 +451,7 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, const float normal_proj ScanFillContext sf_ctx; ScanFillVert *sf_vert, *sf_vert_new, *sf_vert_last; ScanFillFace *sf_tri; + MemArena *sf_arena; DispList *dlnew = NULL, *dl; float *f1; int colnr = 0, charidx = 0, cont = 1, tot, a, *index, nextcol = 0; @@ -464,12 +462,14 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, const float normal_proj if (dispbase->first == NULL) return; + sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__); + while (cont) { cont = 0; totvert = 0; nextcol = 0; - BLI_scanfill_begin(&sf_ctx); + BLI_scanfill_begin_arena(&sf_ctx, sf_arena); dl = dispbase->first; while (dl) { @@ -557,7 +557,7 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, const float normal_proj BLI_addhead(to, dlnew); } - BLI_scanfill_end(&sf_ctx); + BLI_scanfill_end_arena(&sf_ctx, sf_arena); if (nextcol) { /* stay at current char but fill polys with next material */ @@ -570,6 +570,8 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, const float normal_proj } } + BLI_memarena_free(sf_arena); + /* do not free polys, needed for wireframe display */ } @@ -667,10 +669,10 @@ static float displist_calc_taper(Scene *scene, Object *taperobj, float fac) if (taperobj == NULL || taperobj->type != OB_CURVE) return 1.0; - dl = taperobj->disp.first; + dl = taperobj->curve_cache ? taperobj->curve_cache->disp.first : NULL; if (dl == NULL) { BKE_displist_make_curveTypes(scene, taperobj, 0); - dl = taperobj->disp.first; + dl = taperobj->curve_cache->disp.first; } if (dl) { float minx, dx, *fp; @@ -712,29 +714,28 @@ void BKE_displist_make_mball(Scene *scene, Object *ob) if (!ob || ob->type != OB_MBALL) return; - /* XXX: mball stuff uses plenty of global variables - * while this is unchanged updating during render is unsafe - */ - if (G.is_rendering) - return; - - BKE_displist_free(&(ob->disp)); + if (ob->curve_cache) { + BKE_displist_free(&(ob->curve_cache->disp)); + } + else { + ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall"); + } if (ob->type == OB_MBALL) { if (ob == BKE_mball_basis_find(scene, ob)) { - BKE_mball_polygonize(scene, ob, &ob->disp); + BKE_mball_polygonize(scene, ob, &ob->curve_cache->disp, false); BKE_mball_texspace_calc(ob); - object_deform_mball(ob, &ob->disp); + object_deform_mball(ob, &ob->curve_cache->disp); } - } - boundbox_displist(ob); + boundbox_displist_object(ob); + } } void BKE_displist_make_mball_forRender(Scene *scene, Object *ob, ListBase *dispbase) { - BKE_mball_polygonize(scene, ob, dispbase); + BKE_mball_polygonize(scene, ob, dispbase, true); BKE_mball_texspace_calc(ob); object_deform_mball(ob, dispbase); @@ -742,7 +743,8 @@ void BKE_displist_make_mball_forRender(Scene *scene, Object *ob, ListBase *dispb static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob, int renderResolution, int editmode) { - ModifierData *md = modifiers_getVirtualModifierList(ob); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); ModifierData *pretessellatePoint; int required_mode; @@ -780,18 +782,16 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob, int re return pretessellatePoint; } -static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, int renderResolution, - float (**originalVerts_r)[3], - float (**deformedVerts_r)[3], int *numVerts_r) +static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb, + int forRender, int renderResolution) { - ModifierData *md = modifiers_getVirtualModifierList(ob); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); ModifierData *pretessellatePoint; Curve *cu = ob->data; - ListBase *nurb = BKE_curve_nurbs_get(cu); int numVerts = 0; const int editmode = (!forRender && (cu->editnurb || cu->editfont)); ModifierApplyFlag app_flag = 0; - float (*originalVerts)[3] = NULL; float (*deformedVerts)[3] = NULL; float *keyVerts = NULL; int required_mode; @@ -818,8 +818,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, in * tilts, which is passed through in the modifier stack. * this is also the reason curves do not use a virtual * shape key modifier yet. */ - deformedVerts = BKE_curve_keyVertexCos_get(cu, nurb, keyVerts); - originalVerts = MEM_dupallocN(deformedVerts); + deformedVerts = BKE_curve_nurbs_keyVertexCos_get(nurb, keyVerts); BLI_assert(BKE_nurbList_verts_count(nurb) == numVerts); } } @@ -836,8 +835,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, in continue; if (!deformedVerts) { - deformedVerts = BKE_curve_vertexCos_get(cu, nurb, &numVerts); - originalVerts = MEM_dupallocN(deformedVerts); + deformedVerts = BKE_curve_nurbs_vertexCos_get(nurb, &numVerts); } mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, app_flag); @@ -847,17 +845,15 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, in } } - if (deformedVerts) - BK_curve_vertexCos_apply(cu, nurb, deformedVerts); + if (deformedVerts) { + BK_curve_nurbs_vertexCos_apply(nurb, deformedVerts); + MEM_freeN(deformedVerts); + } if (keyVerts) /* these are not passed through modifier stack */ - BKE_curve_keyVertexTilts_apply(cu, nurb, keyVerts); + BKE_curve_nurbs_keyVertexTilts_apply(nurb, keyVerts); if (keyVerts) MEM_freeN(keyVerts); - - *originalVerts_r = originalVerts; - *deformedVerts_r = deformedVerts; - *numVerts_r = numVerts; } static float (*displist_get_allverts(ListBase *dispbase, int *totvert))[3] @@ -894,14 +890,14 @@ static void displist_apply_allverts(ListBase *dispbase, float (*allverts)[3]) } } -static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispbase, DerivedMesh **derivedFinal, - int forRender, int renderResolution, - float (*originalVerts)[3], float (*deformedVerts)[3]) +static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb, + ListBase *dispbase, DerivedMesh **derivedFinal, + int forRender, int renderResolution) { - ModifierData *md = modifiers_getVirtualModifierList(ob); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); ModifierData *pretessellatePoint; Curve *cu = ob->data; - ListBase *nurb = BKE_curve_nurbs_get(cu); int required_mode = 0, totvert = 0; int editmode = (!forRender && (cu->editnurb || cu->editfont)); DerivedMesh *dm = NULL, *ndm; @@ -1046,12 +1042,6 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba } (*derivedFinal) = dm; } - - if (deformedVerts) { - BK_curve_vertexCos_apply(ob->data, nurb, originalVerts); - MEM_freeN(originalVerts); - MEM_freeN(deformedVerts); - } } static void displist_surf_indices(DispList *dl) @@ -1142,8 +1132,8 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *derivedFina /* this function represents logic of mesh's orcodm calculation * for displist-based objects */ - - ModifierData *md = modifiers_getVirtualModifierList(ob); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); ModifierData *pretessellatePoint; Curve *cu = ob->data; int required_mode; @@ -1201,25 +1191,24 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *derivedFina void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase, DerivedMesh **derivedFinal, int forRender, int forOrco, int renderResolution) { - ListBase *nubase; + ListBase nubase = {NULL, NULL}; Nurb *nu; Curve *cu = ob->data; DispList *dl; float *data; int len; - int numVerts; - float (*originalVerts)[3]; - float (*deformedVerts)[3]; - if (!forRender && cu->editnurb) - nubase = BKE_curve_editNurbs_get(cu); - else - nubase = &cu->nurb; + if (!forRender && cu->editnurb) { + BKE_nurbList_duplicate(&nubase, BKE_curve_editNurbs_get(cu)); + } + else { + BKE_nurbList_duplicate(&nubase, &cu->nurb); + } if (!forOrco) - curve_calc_modifiers_pre(scene, ob, forRender, renderResolution, &originalVerts, &deformedVerts, &numVerts); + curve_calc_modifiers_pre(scene, ob, &nubase, forRender, renderResolution); - for (nu = nubase->first; nu; nu = nu->next) { + for (nu = nubase.first; nu; nu = nu->next) { if (forRender || nu->hide == 0) { int resolu = nu->resolu, resolv = nu->resolv; @@ -1287,15 +1276,12 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase, * already applied, thats how it worked for years, so keep for compatibility (sergey) */ BKE_displist_copy(&cu->disp, dispbase); - if (!forRender) { - BKE_curve_texspace_calc(cu); - } - if (!forOrco) { - curve_calc_modifiers_post(scene, ob, dispbase, derivedFinal, - forRender, renderResolution, - originalVerts, deformedVerts); + curve_calc_modifiers_post(scene, ob, &nubase, dispbase, derivedFinal, + forRender, renderResolution); } + + BKE_nurbList_free(&nubase); } static void rotateBevelPiece(Curve *cu, BevPoint *bevp, BevPoint *nbevp, DispList *dlb, float bev_blend, float widfac, float fac, float **data_r) @@ -1389,37 +1375,34 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba } else if (ELEM(ob->type, OB_CURVE, OB_FONT)) { ListBase dlbev; - ListBase *nubase; - float (*originalVerts)[3]; - float (*deformedVerts)[3]; - int numVerts; + ListBase nubase = {NULL, NULL}; - nubase = BKE_curve_nurbs_get(cu); + BLI_freelistN(&(ob->curve_cache->bev)); - BLI_freelistN(&(cu->bev)); - - if (cu->path) free_path(cu->path); - cu->path = NULL; + if (ob->curve_cache->path) free_path(ob->curve_cache->path); + ob->curve_cache->path = NULL; if (ob->type == OB_FONT) BKE_vfont_to_curve(G.main, scene, ob, 0); + BKE_nurbList_duplicate(&nubase, BKE_curve_nurbs_get(cu)); + if (!forOrco) - curve_calc_modifiers_pre(scene, ob, forRender, renderResolution, &originalVerts, &deformedVerts, &numVerts); + curve_calc_modifiers_pre(scene, ob, &nubase, forRender, renderResolution); - BKE_curve_bevelList_make(ob); + BKE_curve_bevelList_make(ob, &nubase, forRender != FALSE); /* If curve has no bevel will return nothing */ BKE_curve_bevel_make(scene, ob, &dlbev, forRender, renderResolution); /* no bevel or extrude, and no width correction? */ if (!dlbev.first && cu->width == 1.0f) { - curve_to_displist(cu, nubase, dispbase, forRender, renderResolution); + curve_to_displist(cu, &nubase, dispbase, forRender, renderResolution); } else { float widfac = cu->width - 1.0f; - BevList *bl = cu->bev.first; - Nurb *nu = nubase->first; + BevList *bl = ob->curve_cache->bev.first; + Nurb *nu = nubase.first; for (; bl && nu; bl = bl->next, nu = nu->next) { DispList *dl; @@ -1586,27 +1569,25 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba } if (!(cu->flag & CU_DEFORM_FILL)) { - curve_to_filledpoly(cu, nubase, dispbase); + curve_to_filledpoly(cu, &nubase, dispbase); } if ((cu->flag & CU_PATH) && !forOrco) - calc_curvepath(ob); + calc_curvepath(ob, &nubase); /* make copy of 'undeformed" displist for texture space calculation * actually, it's not totally undeformed -- pre-tessellation modifiers are * already applied, thats how it worked for years, so keep for compatibility (sergey) */ BKE_displist_copy(&cu->disp, dispbase); - if (!forRender) { - BKE_curve_texspace_calc(cu); - } - if (!forOrco) - curve_calc_modifiers_post(scene, ob, dispbase, derivedFinal, forRender, renderResolution, originalVerts, deformedVerts); + curve_calc_modifiers_post(scene, ob, &nubase, dispbase, derivedFinal, forRender, renderResolution); if (cu->flag & CU_DEFORM_FILL && !ob->derivedFinal) { - curve_to_filledpoly(cu, nubase, dispbase); + curve_to_filledpoly(cu, &nubase, dispbase); } + + BKE_nurbList_free(&nubase); } } @@ -1621,37 +1602,36 @@ void BKE_displist_make_curveTypes(Scene *scene, Object *ob, int forOrco) if (!ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return; - BKE_displist_free(&(ob->disp)); - dispbase = &(ob->disp); - BKE_displist_free(dispbase); - - /* free displist used for textspace */ BKE_displist_free(&cu->disp); + BKE_object_free_derived_caches(ob); - do_makeDispListCurveTypes(scene, ob, dispbase, &ob->derivedFinal, 0, forOrco, 0); + if (!ob->curve_cache) { + ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types"); + } - if (ob->derivedFinal) { - DM_set_object_boundbox(ob, ob->derivedFinal); + dispbase = &(ob->curve_cache->disp); - /* always keep curve's BB in sync with non-deformed displist */ - if (cu->bb == NULL) - cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox"); + do_makeDispListCurveTypes(scene, ob, dispbase, &ob->derivedFinal, 0, forOrco, 0); - boundbox_dispbase(cu->bb, &cu->disp); - } - else { - boundbox_displist(ob); - } + boundbox_displist_object(ob); } void BKE_displist_make_curveTypes_forRender(Scene *scene, Object *ob, ListBase *dispbase, DerivedMesh **derivedFinal, int forOrco, int renderResolution) { + if (ob->curve_cache == NULL) { + ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall"); + } + do_makeDispListCurveTypes(scene, ob, dispbase, derivedFinal, 1, forOrco, renderResolution); } void BKE_displist_make_curveTypes_forOrco(struct Scene *scene, struct Object *ob, struct ListBase *dispbase) { + if (ob->curve_cache == NULL) { + ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall"); + } + do_makeDispListCurveTypes(scene, ob, dispbase, NULL, 1, 1, 1); } @@ -1676,16 +1656,13 @@ float *BKE_displist_make_orco(Scene *scene, Object *ob, DerivedMesh *derivedFina return orco; } -static void boundbox_dispbase(BoundBox *bb, ListBase *dispbase) +void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3]) { - float min[3], max[3]; DispList *dl; float *vert; int a, tot = 0; int doit = 0; - INIT_MINMAX(min, max); - for (dl = dispbase->first; dl; dl = dl->next) { tot = (dl->type == DL_INDEX3) ? dl->nr : dl->nr * dl->parts; vert = dl->verts; @@ -1700,26 +1677,29 @@ static void boundbox_dispbase(BoundBox *bb, ListBase *dispbase) zero_v3(min); zero_v3(max); } - - BKE_boundbox_init_from_minmax(bb, min, max); } /* this is confusing, there's also min_max_object, appplying the obmat... */ -static void boundbox_displist(Object *ob) +static void boundbox_displist_object(Object *ob) { if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - Curve *cu = ob->data; - - /* calculate curve's BB based on non-deformed displist */ - if (cu->bb == NULL) - cu->bb = MEM_callocN(sizeof(BoundBox), "boundbox"); - - boundbox_dispbase(cu->bb, &cu->disp); + /* Curver's BB is already calculated as a part of modifier stack, + * here we only calculate object BB based on final display list. + */ /* object's BB is calculated from final displist */ if (ob->bb == NULL) ob->bb = MEM_callocN(sizeof(BoundBox), "boundbox"); - boundbox_dispbase(ob->bb, &ob->disp); + if (ob->derivedFinal) { + DM_set_object_boundbox(ob, ob->derivedFinal); + } + else { + float min[3], max[3]; + + INIT_MINMAX(min, max); + BKE_displist_minmax(&ob->curve_cache->disp, min, max); + BKE_boundbox_init_from_minmax(ob->bb, min, max); + } } } diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index a62ca530bf9..580172bcccd 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -20,6 +20,9 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/blenkernel/intern/dynamicpaint.c + * \ingroup bke + */ #include "MEM_guardedalloc.h" @@ -3802,14 +3805,15 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, */ KDTreeNearest *nearest; - int n, particles = 0; + int n, particles; float smooth_range = smooth * (1.0f - strength), dist; /* calculate max range that can have particles with higher influence than the nearest one */ float max_range = smooth - strength * smooth + solidradius; /* Make gcc happy! */ dist = max_range; - particles = BLI_kdtree_range_search(tree, max_range, bData->realCoord[bData->s_pos[index]].v, NULL, &nearest); + particles = BLI_kdtree_range_search(tree, bData->realCoord[bData->s_pos[index]].v, NULL, + &nearest, max_range); /* Find particle that produces highest influence */ for (n = 0; n < particles; n++) { diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index e8e56c6f17b..caa5bf90584 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -1872,7 +1872,7 @@ static void statvis_calc_thickness( normal_tri_v3(ray_no, cos[2], cos[1], cos[0]); #define FACE_RAY_TEST_ANGLE \ - f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, \ + f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, \ &dist, NULL, NULL); \ if (f_hit && dist < face_dists[index]) { \ float angle_fac = fabsf(dot_v3v3(ltri[0]->f->no, f_hit->no)); \ diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index 74cd8834d5d..6a89d16d7bf 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -36,6 +36,7 @@ #include "DNA_mesh_types.h" #include "BLI_math.h" +#include "BLI_memarena.h" #include "BLI_scanfill.h" #include "BKE_editmesh.h" @@ -123,6 +124,7 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em) int i = 0; ScanFillContext sf_ctx; + MemArena *sf_arena = NULL; #if 0 /* note, we could be clever and re-use this array but would need to ensure @@ -217,7 +219,11 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em) ScanFillFace *sf_tri; int totfilltri; - BLI_scanfill_begin(&sf_ctx); + if (UNLIKELY(sf_arena == NULL)) { + sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__); + } + + BLI_scanfill_begin_arena(&sf_ctx, sf_arena); /* scanfill time */ j = 0; @@ -262,10 +268,15 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em) l_ptr[2] = l3; } - BLI_scanfill_end(&sf_ctx); + BLI_scanfill_end_arena(&sf_ctx, sf_arena); } } + if (sf_arena) { + BLI_memarena_free(sf_arena); + sf_arena = NULL; + } + em->tottri = i; em->looptris = looptris; diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c index fced3472566..cb65fd80fc4 100644 --- a/source/blender/blenkernel/intern/editmesh_bvh.c +++ b/source/blender/blenkernel/intern/editmesh_bvh.c @@ -193,12 +193,17 @@ static void bmbvh_ray_cast_cb(void *userdata, int index, const BVHTreeRay *ray, const BMLoop **ltri = bmcb_data->looptris[index]; float dist, uv[2]; const float *tri_cos[3]; + bool isect; bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage); - if (isect_ray_tri_v3(ray->origin, ray->direction, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv) && - (dist < hit->dist)) - { + isect = (ray->radius > 0.0f ? + isect_ray_tri_epsilon_v3(ray->origin, ray->direction, + tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv, ray->radius) : + isect_ray_tri_v3(ray->origin, ray->direction, + tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv)); + + if (isect && dist < hit->dist) { hit->dist = dist; hit->index = index; @@ -213,14 +218,14 @@ static void bmbvh_ray_cast_cb(void *userdata, int index, const BVHTreeRay *ray, } } -BMFace *BKE_bmbvh_ray_cast(BMBVHTree *bmtree, const float co[3], const float dir[3], +BMFace *BKE_bmbvh_ray_cast(BMBVHTree *bmtree, const float co[3], const float dir[3], const float radius, float *r_dist, float r_hitout[3], float r_cagehit[3]) { BVHTreeRayHit hit; struct RayCastUserData bmcb_data; const float dist = r_dist ? *r_dist : FLT_MAX; - if (bmtree->cos_cage) BLI_assert(!(bmtree->em->bm->elem_index_dirty & BM_VERT)); + if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT)); hit.dist = dist; hit.index = -1; @@ -229,7 +234,7 @@ BMFace *BKE_bmbvh_ray_cast(BMBVHTree *bmtree, const float co[3], const float dir bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->em->looptris; bmcb_data.cos_cage = (const float (*)[3])bmtree->cos_cage; - BLI_bvhtree_ray_cast(bmtree->tree, co, dir, 0.0f, &hit, bmbvh_ray_cast_cb, &bmcb_data); + 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) { @@ -314,7 +319,7 @@ BMFace *BKE_bmbvh_find_face_segment(BMBVHTree *bmtree, const float co_a[3], cons const float dist = len_v3v3(co_a, co_b); float dir[3]; - if (bmtree->cos_cage) BLI_assert(!(bmtree->em->bm->elem_index_dirty & BM_VERT)); + if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT)); sub_v3_v3v3(dir, co_b, co_a); @@ -400,7 +405,7 @@ BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *bmtree, const float co[3], const struct VertSearchUserData bmcb_data; const float maxdist_sq = maxdist * maxdist; - if (bmtree->cos_cage) BLI_assert(!(bmtree->em->bm->elem_index_dirty & BM_VERT)); + if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT)); hit.dist = maxdist_sq; hit.index = -1; diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 0df8684044a..81b0de9fd32 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -67,6 +67,7 @@ #include "BKE_blender.h" #include "BKE_collision.h" #include "BKE_constraint.h" +#include "BKE_curve.h" #include "BKE_deform.h" #include "BKE_depsgraph.h" #include "BKE_displist.h" @@ -176,10 +177,10 @@ static void precalculate_effector(EffectorCache *eff) if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type==OB_CURVE) { Curve *cu= eff->ob->data; if (cu->flag & CU_PATH) { - if (cu->path==NULL || cu->path->data==NULL) + if (eff->ob->curve_cache == NULL || eff->ob->curve_cache->path==NULL || eff->ob->curve_cache->path->data==NULL) BKE_displist_make_curveTypes(eff->scene, eff->ob, 0); - if (cu->path && cu->path->data) { + if (eff->ob->curve_cache->path && eff->ob->curve_cache->path->data) { where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL); mul_m4_v3(eff->ob->obmat, eff->guide_loc); mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 791c47cc551..dbdf30ea63d 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -688,21 +688,27 @@ short fcurve_are_keyframes_usable(FCurve *fcu) return 1; } +bool BKE_fcurve_is_protected(FCurve *fcu) +{ + return ((fcu->flag & FCURVE_PROTECTED) || + ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED))); +} + /* Can keyframes be added to F-Curve? * Keyframes can only be added if they are already visible */ -short fcurve_is_keyframable(FCurve *fcu) +bool fcurve_is_keyframable(FCurve *fcu) { /* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */ if (fcurve_are_keyframes_usable(fcu) == 0) - return 0; + return false; /* F-Curve must currently be editable too */ - if ( (fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ) - return 0; + if (BKE_fcurve_is_protected(fcu)) + return false; /* F-Curve is keyframable */ - return 1; + return true; } /* ***************************** Keyframe Column Tools ********************************* */ @@ -841,14 +847,7 @@ void calchandles_fcurve(FCurve *fcu) } } -/* Use when F-Curve with handles has changed - * It treats all BezTriples with the following rules: - * - PHASE 1: do types have to be altered? - * -> Auto handles: become aligned when selection status is NOT(000 || 111) - * -> Vector handles: become 'nothing' when (one half selected AND other not) - * - PHASE 2: recalculate handles - */ -void testhandles_fcurve(FCurve *fcu, const short use_handle) +void testhandles_fcurve(FCurve *fcu, const bool use_handle) { BezTriple *bezt; unsigned int a; @@ -856,45 +855,10 @@ void testhandles_fcurve(FCurve *fcu, const short use_handle) /* only beztriples have handles (bpoints don't though) */ if (ELEM(NULL, fcu, fcu->bezt)) return; - + /* loop over beztriples */ for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) { - short flag = 0; - - /* flag is initialized as selection status - * of beztriple control-points (labelled 0, 1, 2) - */ - if (bezt->f2 & SELECT) flag |= (1 << 1); // == 2 - if (use_handle == FALSE) { - if (flag & 2) { - flag |= (1 << 0) | (1 << 2); - } - } - else { - if (bezt->f1 & SELECT) flag |= (1 << 0); // == 1 - if (bezt->f3 & SELECT) flag |= (1 << 2); // == 4 - } - - /* one or two handles selected only */ - if (ELEM(flag, 0, 7) == 0) { - /* auto handles become aligned */ - if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) - bezt->h1 = HD_ALIGN; - if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) - bezt->h2 = HD_ALIGN; - - /* vector handles become 'free' when only one half selected */ - if (bezt->h1 == HD_VECT) { - /* only left half (1 or 2 or 1+2) */ - if (flag < 4) - bezt->h1 = 0; - } - if (bezt->h2 == HD_VECT) { - /* only right half (4 or 2+4) */ - if (flag > 3) - bezt->h2 = 0; - } - } + BKE_nurb_bezt_handle_test(bezt, use_handle); } /* recalculate handles */ diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 7c23438f93d..f24d84df2e8 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -41,6 +41,7 @@ #include "BLI_math.h" #include "BLI_blenlib.h" +#include "BLI_threads.h" #include "BLI_vfontdata.h" #include "BLI_utildefines.h" @@ -59,6 +60,7 @@ #include "BKE_curve.h" #include "BKE_displist.h" +static ThreadMutex vfont_mutex = BLI_MUTEX_INITIALIZER; /* The vfont code */ void BKE_vfont_free_data(struct VFont *vfont) @@ -138,6 +140,18 @@ static VFontData *vfont_get_data(Main *bmain, VFont *vfont) if (!vfont->data) { PackedFile *pf; + BLI_mutex_lock(&vfont_mutex); + + if (vfont->data) { + /* Check data again, since it might have been already + * initialized from other thread (previous check is + * not accurate or threading, just prevents unneeded + * lock if all the data is here for sure). + */ + BLI_mutex_unlock(&vfont_mutex); + return vfont->data; + } + if (BKE_vfont_is_builtin(vfont)) { pf = get_builtin_packedfile(); } @@ -175,8 +189,10 @@ static VFontData *vfont_get_data(Main *bmain, VFont *vfont) freePackedFile(pf); } } + + BLI_mutex_unlock(&vfont_mutex); } - + return vfont->data; } @@ -819,8 +835,10 @@ makebreak: cucu->flag |= (CU_PATH + CU_FOLLOW); - if (cucu->path == NULL) BKE_displist_make_curveTypes(scene, cu->textoncurve, 0); - if (cucu->path) { + if (cu->textoncurve->curve_cache == NULL || cu->textoncurve->curve_cache->path == NULL) { + BKE_displist_make_curveTypes(scene, cu->textoncurve, 0); + } + if (cu->textoncurve->curve_cache->path) { float distfac, imat[4][4], imat3[3][3], cmat[3][3]; float minx, maxx, miny, maxy; float timeofs, sizefac; @@ -845,7 +863,7 @@ makebreak: /* we put the x-coordinaat exact at the curve, the y is rotated */ /* length correction */ - distfac = sizefac * cucu->path->totdist / (maxx - minx); + distfac = sizefac * cu->textoncurve->curve_cache->path->totdist / (maxx - minx); timeofs = 0.0f; if (distfac > 1.0f) { diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c index 32fe4ac4ba6..d87c93310c8 100644 --- a/source/blender/blenkernel/intern/freestyle.c +++ b/source/blender/blenkernel/intern/freestyle.c @@ -52,7 +52,7 @@ void BKE_freestyle_config_init(FreestyleConfig *config) config->modules.first = config->modules.last = NULL; config->flags = 0; - config->sphere_radius = 1.0f; + config->sphere_radius = 0.1f; config->dkr_epsilon = 0.0f; config->crease_angle = DEG2RADF(134.43f); @@ -107,7 +107,8 @@ void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *con static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *lineset) { new_lineset->linestyle = lineset->linestyle; - new_lineset->linestyle->id.us++; + if (new_lineset->linestyle) + new_lineset->linestyle->id.us++; new_lineset->flags = lineset->flags; new_lineset->selection = lineset->selection; new_lineset->qi = lineset->qi; diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 31dd79e7623..4d17bd286b4 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -42,6 +42,7 @@ #include "BLF_translation.h" #include "DNA_gpencil_types.h" +#include "DNA_userdef_types.h" #include "BKE_global.h" #include "BKE_gpencil.h" @@ -125,8 +126,8 @@ bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe) bGPDframe *gpf, *gf; short state = 0; - /* error checking */ - if ((gpl == NULL) || (cframe <= 0)) + /* error checking (neg frame only if they are not allowed in Blender!) */ + if ((gpl == NULL) || ((U.flag & USER_NONEGFRAMES) && (cframe <= 0))) return NULL; /* allocate memory for this frame */ @@ -349,7 +350,8 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, short addnew) /* error checking */ if (gpl == NULL) return NULL; - if (cframe <= 0) cframe = 1; + /* No reason to forbid negative frames when they are allowed in Blender! */ + if ((U.flag & USER_NONEGFRAMES) && cframe <= 0) cframe = 1; /* check if there is already an active frame */ if (gpl->actframe) { diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index ad0aed4691a..a5cbf064bc2 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -65,9 +65,7 @@ void BKE_group_free(Group *group) /* don't free group itself */ GroupObject *go; - while (group->gobject.first) { - go = group->gobject.first; - BLI_remlink(&group->gobject, go); + while ((go = BLI_pophead(&group->gobject))) { free_group_object(go); } } diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index f20506af967..6f275e4ec75 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -56,7 +56,13 @@ static char idp_size_table[] = { sizeof(double) }; -/* ------------Property Array Type ----------- */ + +/* -------------------------------------------------------------------- */ +/* Array Functions */ + +/** \name IDP Array API + * \{ */ + #define GETPROP(prop, i) (((IDProperty *)(prop)->data.pointer) + (i)) /* --------- property array type -------------*/ @@ -78,9 +84,12 @@ IDProperty *IDP_NewIDPArray(const char *name) IDProperty *IDP_CopyIDPArray(IDProperty *array) { /* don't use MEM_dupallocN because this may be part of an array */ - IDProperty *narray = MEM_mallocN(sizeof(IDProperty), "IDP_CopyIDPArray"), *tmp; + IDProperty *narray, *tmp; int i; + BLI_assert(array->type == IDP_IDPARRAY); + + narray = MEM_mallocN(sizeof(IDProperty), __func__); *narray = *array; narray->data.pointer = MEM_dupallocN(array->data.pointer); @@ -103,6 +112,8 @@ void IDP_FreeIDPArray(IDProperty *prop) { int i; + BLI_assert(prop->type == IDP_IDPARRAY); + for (i = 0; i < prop->len; i++) IDP_FreeProperty(GETPROP(prop, i)); @@ -113,7 +124,11 @@ void IDP_FreeIDPArray(IDProperty *prop) /*shallow copies item*/ void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item) { - IDProperty *old = GETPROP(prop, index); + IDProperty *old; + + BLI_assert(prop->type == IDP_IDPARRAY); + + old = GETPROP(prop, index); if (index >= prop->len || index < 0) return; if (item != old) IDP_FreeProperty(old); @@ -122,22 +137,27 @@ void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item) IDProperty *IDP_GetIndexArray(IDProperty *prop, int index) { + BLI_assert(prop->type == IDP_IDPARRAY); + return GETPROP(prop, index); } void IDP_AppendArray(IDProperty *prop, IDProperty *item) { + BLI_assert(prop->type == IDP_IDPARRAY); + IDP_ResizeIDPArray(prop, prop->len + 1); IDP_SetIndexArray(prop, prop->len - 1, item); } void IDP_ResizeIDPArray(IDProperty *prop, int newlen) { - void *newarr; - int newsize = newlen; + int newsize; + + BLI_assert(prop->type == IDP_IDPARRAY); - /*first check if the array buffer size has room*/ - /*if newlen is 200 chars less then totallen, reallocate anyway*/ + /* 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) { int i; @@ -154,6 +174,15 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen) } } + /* free trailing items */ + if (newlen < prop->len) { + /* newlen is smaller */ + int i; + for (i = newlen; i < prop->len; i++) { + IDP_FreeProperty(GETPROP(prop, i)); + } + } + /* - Note: This code comes from python, here's the corresponding comment. - */ /* This over-allocates proportional to the list size, making room * for additional growth. The over-allocation is mild, but is @@ -162,25 +191,9 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen) * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ + newsize = newlen; newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; - - newarr = MEM_callocN(sizeof(IDProperty) * newsize, "idproperty array resized"); - if (newlen >= prop->len) { - /* newlen is bigger */ - memcpy(newarr, prop->data.pointer, prop->len * sizeof(IDProperty)); - } - else { - int i; - /* newlen is smaller */ - for (i = newlen; i < prop->len; i++) { - IDP_FreeProperty(GETPROP(prop, i)); - } - memcpy(newarr, prop->data.pointer, newlen * sizeof(IDProperty)); - } - - if (prop->data.pointer) - MEM_freeN(prop->data.pointer); - prop->data.pointer = newarr; + prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * newsize); prop->len = newlen; prop->totallen = newsize; } @@ -217,11 +230,11 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) /*this function works for strings too!*/ void IDP_ResizeArray(IDProperty *prop, int newlen) { - void *newarr; - int newsize = newlen; + int newsize; + 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*/ + /* 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) { idp_resize_group_array(prop, newlen, prop->data.pointer); prop->len = newlen; @@ -236,22 +249,17 @@ void IDP_ResizeArray(IDProperty *prop, int newlen) * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ - newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; + newsize = newlen; + newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;\ - newarr = MEM_callocN(idp_size_table[(int)prop->subtype] * newsize, "idproperty array resized"); - if (newlen >= prop->len) { - /* newlen is bigger */ - memcpy(newarr, prop->data.pointer, prop->len * idp_size_table[(int)prop->subtype]); - idp_resize_group_array(prop, newlen, newarr); - } - else { - /* newlen is smaller */ - idp_resize_group_array(prop, newlen, newarr); - memcpy(newarr, prop->data.pointer, newlen * idp_size_table[(int)prop->subtype]); - } + 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); + + if (is_grow == true) + idp_resize_group_array(prop, newlen, prop->data.pointer); - MEM_freeN(prop->data.pointer); - prop->data.pointer = newarr; prop->len = newlen; prop->totallen = newsize; } @@ -299,16 +307,31 @@ static IDProperty *IDP_CopyArray(IDProperty *prop) return newp; } +/** \} */ + + +/* -------------------------------------------------------------------- */ +/* String Functions */ -/* ---------- String Type ------------ */ +/** \name IDProperty String API + * \{ */ + +/** + * + * \param st The string to assign. + * \param name The property name. + * \param maxlen The size of the new string (including the \0 terminator) + * \return + */ IDProperty *IDP_NewString(const char *st, const char *name, int maxlen) { IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty string"); if (st == NULL) { - prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1"); + prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1"); + *IDP_String(prop) = '\0'; prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS; - prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/ + prop->len = 1; /* NULL string, has len of 1 to account for null byte. */ } else { int stlen = strlen(st); @@ -318,7 +341,7 @@ IDProperty *IDP_NewString(const char *st, const char *name, int maxlen) stlen++; /* null terminator '\0' */ - prop->data.pointer = MEM_callocN(stlen, "id property string 2"); + prop->data.pointer = MEM_mallocN(stlen, "id property string 2"); prop->len = prop->totallen = stlen; BLI_strncpy(prop->data.pointer, st, stlen); } @@ -331,9 +354,13 @@ IDProperty *IDP_NewString(const char *st, const char *name, int maxlen) static IDProperty *IDP_CopyString(IDProperty *prop) { - IDProperty *newp = idp_generic_copy(prop); + IDProperty *newp; - if (prop->data.pointer) newp->data.pointer = MEM_dupallocN(prop->data.pointer); + BLI_assert(prop->type == IDP_STRING); + newp = idp_generic_copy(prop); + + if (prop->data.pointer) + newp->data.pointer = MEM_dupallocN(prop->data.pointer); newp->len = prop->len; newp->subtype = prop->subtype; newp->totallen = prop->totallen; @@ -344,8 +371,10 @@ static IDProperty *IDP_CopyString(IDProperty *prop) void IDP_AssignString(IDProperty *prop, const char *st, int maxlen) { - int stlen = strlen(st); + int stlen; + BLI_assert(prop->type == IDP_STRING); + stlen = strlen(st); if (maxlen > 0 && maxlen < stlen) stlen = maxlen; @@ -354,7 +383,7 @@ void IDP_AssignString(IDProperty *prop, const char *st, int maxlen) memcpy(prop->data.pointer, st, stlen); } else { - stlen++; /* make room for null byte */ + stlen++; IDP_ResizeArray(prop, stlen); BLI_strncpy(prop->data.pointer, st, stlen); } @@ -364,6 +393,8 @@ void IDP_ConcatStringC(IDProperty *prop, const char *st) { int newlen; + BLI_assert(prop->type == IDP_STRING); + newlen = prop->len + 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.*/ @@ -375,6 +406,8 @@ void IDP_ConcatString(IDProperty *str1, IDProperty *append) { int newlen; + BLI_assert(append->type == IDP_STRING); + /* since ->len for strings includes the NULL byte, we have to subtract one or * we'll get an extra null byte after each concatenation operation.*/ newlen = str1->len + append->len - 1; @@ -384,13 +417,19 @@ void IDP_ConcatString(IDProperty *str1, IDProperty *append) void IDP_FreeString(IDProperty *prop) { + BLI_assert(prop->type == IDP_STRING); + if (prop->data.pointer) MEM_freeN(prop->data.pointer); } +/** \} */ -/*-------- ID Type, not in use yet -------*/ +/* -------------------------------------------------------------------- */ +/* ID Type (not in use yet) */ +/** \name IDProperty ID API (unused) + * \{ */ void IDP_LinkID(IDProperty *prop, ID *id) { if (prop->data.pointer) ((ID *)prop->data.pointer)->us--; @@ -402,15 +441,26 @@ void IDP_UnlinkID(IDProperty *prop) { ((ID *)prop->data.pointer)->us--; } +/** \} */ + -/*-------- Group Functions -------*/ +/* -------------------------------------------------------------------- */ +/* Group Functions */ -/*checks if a property with the same name as prop exists, and if so replaces it.*/ +/** \name IDProperty Group API + * \{ */ + +/** + * Checks if a property with the same name as prop exists, and if so replaces it. + */ static IDProperty *IDP_CopyGroup(IDProperty *prop) { - IDProperty *newp = idp_generic_copy(prop), *link; - newp->len = prop->len; + IDProperty *newp, *link; + BLI_assert(prop->type == IDP_GROUP); + newp = idp_generic_copy(prop); + newp->len = prop->len; + for (link = prop->data.group.first; link; link = link->next) { BLI_addtail(&newp->data.group, IDP_CopyProperty(link)); } @@ -423,6 +473,10 @@ static IDProperty *IDP_CopyGroup(IDProperty *prop) void IDP_SyncGroupValues(IDProperty *dest, IDProperty *src) { IDProperty *other, *prop; + + BLI_assert(dest->type == IDP_GROUP); + BLI_assert(src->type == IDP_GROUP); + for (prop = src->data.group.first; prop; prop = prop->next) { other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name)); if (other && prop->type == other->type) { @@ -458,6 +512,10 @@ void IDP_SyncGroupValues(IDProperty *dest, IDProperty *src) void IDP_ReplaceGroupInGroup(IDProperty *dest, IDProperty *src) { IDProperty *loop, *prop; + + BLI_assert(dest->type == IDP_GROUP); + BLI_assert(src->type == IDP_GROUP); + for (prop = src->data.group.first; prop; prop = prop->next) { for (loop = dest->data.group.first; loop; loop = loop->next) { if (STREQ(loop->name, prop->name)) { @@ -488,6 +546,9 @@ void IDP_ReplaceGroupInGroup(IDProperty *dest, IDProperty *src) void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop) { IDProperty *loop; + + BLI_assert(group->type == IDP_GROUP); + if ((loop = IDP_GetPropertyFromGroup(group, prop->name))) { BLI_insertlinkafter(&group->data.group, loop, prop); @@ -501,13 +562,16 @@ void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop) } } -/* +/** * If a property is missing in \a dest, add it. */ void IDP_MergeGroup(IDProperty *dest, IDProperty *src, const int do_overwrite) { IDProperty *prop; + BLI_assert(dest->type == IDP_GROUP); + BLI_assert(src->type == IDP_GROUP); + if (do_overwrite) { for (prop = src->data.group.first; prop; prop = prop->next) { IDProperty *copy = IDP_CopyProperty(prop); @@ -542,6 +606,8 @@ void IDP_MergeGroup(IDProperty *dest, IDProperty *src, const int do_overwrite) */ int IDP_AddToGroup(IDProperty *group, IDProperty *prop) { + BLI_assert(group->type == IDP_GROUP); + if (IDP_GetPropertyFromGroup(group, prop->name) == NULL) { group->len++; BLI_addtail(&group->data.group, prop); @@ -557,6 +623,8 @@ int IDP_AddToGroup(IDProperty *group, IDProperty *prop) */ int IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew) { + BLI_assert(group->type == IDP_GROUP); + if (IDP_GetPropertyFromGroup(group, pnew->name) == NULL) { group->len++; BLI_insertlinkafter(&group->data.group, previous, pnew); @@ -575,12 +643,16 @@ int IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew) */ void IDP_RemFromGroup(IDProperty *group, IDProperty *prop) { + BLI_assert(group->type == IDP_GROUP); + group->len--; BLI_remlink(&group->data.group, prop); } IDProperty *IDP_GetPropertyFromGroup(IDProperty *prop, const char *name) { + BLI_assert(prop->type == IDP_GROUP); + return (IDProperty *)BLI_findstring(&prop->data.group, name, offsetof(IDProperty, name)); } /** same as above but ensure type match */ @@ -603,7 +675,10 @@ typedef struct IDPIter { */ void *IDP_GetGroupIterator(IDProperty *prop) { - IDPIter *iter = MEM_callocN(sizeof(IDPIter), "IDPIter"); + IDPIter *iter; + + BLI_assert(prop->type == IDP_GROUP); + iter = MEM_mallocN(sizeof(IDPIter), "IDPIter"); iter->next = prop->data.group.first; iter->parent = prop; return (void *) iter; @@ -644,14 +719,21 @@ void IDP_FreeIterBeforeEnd(void *vself) static void IDP_FreeGroup(IDProperty *prop) { IDProperty *loop; + + BLI_assert(prop->type == IDP_GROUP); for (loop = prop->data.group.first; loop; loop = loop->next) { IDP_FreeProperty(loop); } BLI_freelistN(&prop->data.group); } +/** \} */ -/*-------- Main Functions --------*/ +/* -------------------------------------------------------------------- */ +/* Main Functions */ + +/** \name IDProperty Main API + * \{ */ IDProperty *IDP_CopyProperty(IDProperty *prop) { switch (prop->type) { @@ -822,7 +904,8 @@ IDProperty *IDP_New(const int type, const IDPropertyTemplate *val, const char *n if (val->string.subtype == IDP_STRING_SUB_BYTE) { /* note, intentionally not null terminated */ if (st == NULL) { - prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1"); + prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1"); + *IDP_String(prop) = '\0'; prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS; prop->len = 0; } @@ -835,7 +918,8 @@ IDProperty *IDP_New(const int type, const IDPropertyTemplate *val, const char *n } else { if (st == NULL) { - prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1"); + prop->data.pointer = MEM_mallocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1"); + *IDP_String(prop) = '\0'; prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS; prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/ } @@ -911,3 +995,5 @@ void IDP_UnlinkProperty(IDProperty *prop) break; } } + +/** \} */ diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 86382c64ed3..2bf6304b04b 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -195,9 +195,7 @@ static void image_free_buffers(Image *ima) { ImBuf *ibuf; - while ((ibuf = ima->ibufs.first)) { - BLI_remlink(&ima->ibufs, ibuf); - + while ((ibuf = BLI_pophead(&ima->ibufs))) { if (ibuf->userdata) { MEM_freeN(ibuf->userdata); ibuf->userdata = NULL; @@ -524,8 +522,7 @@ void BKE_image_merge(Image *dest, Image *source) /* sanity check */ if (dest && source && dest != source) { - while ((ibuf = source->ibufs.first)) { - BLI_remlink(&source->ibufs, ibuf); + while ((ibuf = BLI_pophead(&source->ibufs))) { image_assign_ibuf(dest, ibuf, IMA_INDEX_PASS(ibuf->index), IMA_INDEX_FRAME(ibuf->index)); } @@ -1329,7 +1326,7 @@ int BKE_add_image_extension_from_type(char *string, const char imtype) void BKE_imformat_defaults(ImageFormatData *im_format) { memset(im_format, 0, sizeof(*im_format)); - im_format->planes = R_IMF_PLANES_RGB; + im_format->planes = R_IMF_PLANES_RGBA; im_format->imtype = R_IMF_IMTYPE_PNG; im_format->depth = R_IMF_CHAN_DEPTH_8; im_format->quality = 90; @@ -2152,9 +2149,7 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata, /* texture users */ for (tex = mainp->tex.first; tex; tex = tex->id.next) { if (tex->type == TEX_IMAGE && tex->ima) { - if (ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { - callback(tex->ima, &tex->iuser, customdata); - } + callback(tex->ima, &tex->iuser, customdata); } } @@ -2196,7 +2191,7 @@ static void image_tag_frame_recalc(Image *ima, ImageUser *iuser, void *customdat { Image *changed_image = customdata; - if (ima == changed_image) { + if (ima == changed_image && ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { iuser->flag |= IMA_NEED_FRAME_RECALC; } } diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index d2d2cb1c2d0..7b73dee73fc 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -85,29 +85,23 @@ void BKE_key_free(Key *key) KeyBlock *kb; BKE_free_animdata((ID *)key); - - while ( (kb = key->block.first) ) { - - if (kb->data) MEM_freeN(kb->data); - - BLI_remlink(&key->block, kb); + + while ((kb = BLI_pophead(&key->block))) { + if (kb->data) + MEM_freeN(kb->data); MEM_freeN(kb); } - } void BKE_key_free_nolib(Key *key) { KeyBlock *kb; - - while ( (kb = key->block.first) ) { - - if (kb->data) MEM_freeN(kb->data); - - BLI_remlink(&key->block, kb); + + while ((kb = BLI_pophead(&key->block))) { + if (kb->data) + MEM_freeN(kb->data); MEM_freeN(kb); } - } Key *BKE_key_add(ID *id) /* common function */ @@ -734,12 +728,13 @@ static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const } } -void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb, const int mode) +void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb, + float **per_keyblock_weights, const int mode) { KeyBlock *kb; int *ofsp, ofs[3], elemsize, b; char *cp, *poin, *reffrom, *from, elemstr[8]; - int poinsize; + int poinsize, keyblock_index; /* currently always 0, in future key_pointer_size may assign */ ofs[1] = 0; @@ -763,14 +758,14 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba /* step 2: do it */ - for (kb = key->block.first; kb; kb = kb->next) { + for (kb = key->block.first, keyblock_index = 0; kb; kb = kb->next, keyblock_index++) { if (kb != key->refkey) { float icuval = kb->curval; /* only with value, and no difference allowed */ if (!(kb->flag & KEYBLOCK_MUTE) && icuval != 0.0f && kb->totelem == tot) { KeyBlock *refb; - float weight, *weights = kb->weights; + float weight, *weights = per_keyblock_weights ? per_keyblock_weights[keyblock_index] : NULL; char *freefrom = NULL, *freereffrom = NULL; /* reference now can be any block */ @@ -1058,7 +1053,7 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key if (freek4) MEM_freeN(freek4); } -static float *get_weights_array(Object *ob, char *vgroup) +static float *get_weights_array(Object *ob, char *vgroup, WeightsArrayCache *cache) { MDeformVert *dvert = NULL; BMEditMesh *em = NULL; @@ -1091,7 +1086,21 @@ static float *get_weights_array(Object *ob, char *vgroup) if (defgrp_index != -1) { float *weights; int i; - + + if (cache) { + if (cache->defgroup_weights == NULL) { + int num_defgroup = BLI_countlist(&ob->defbase); + cache->defgroup_weights = + MEM_callocN(sizeof(*cache->defgroup_weights) * num_defgroup, + "cached defgroup weights"); + cache->num_defgroup_weights = num_defgroup; + } + + if (cache->defgroup_weights[defgrp_index]) { + return cache->defgroup_weights[defgrp_index]; + } + } + weights = MEM_mallocN(totvert * sizeof(float), "weights"); if (em) { @@ -1107,11 +1116,61 @@ static float *get_weights_array(Object *ob, char *vgroup) } } + if (cache) { + cache->defgroup_weights[defgrp_index] = weights; + } + return weights; } return NULL; } +float **BKE_keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCache *cache) +{ + KeyBlock *keyblock; + float **per_keyblock_weights; + int keyblock_index; + + per_keyblock_weights = + MEM_mallocN(sizeof(*per_keyblock_weights) * key->totkey, + "per keyblock weights"); + + for (keyblock = key->block.first, keyblock_index = 0; + keyblock; + keyblock = keyblock->next, keyblock_index++) + { + per_keyblock_weights[keyblock_index] = get_weights_array(ob, keyblock->vgroup, cache); + } + + return per_keyblock_weights; +} + +void BKE_keyblock_free_per_block_weights(Key *key, float **per_keyblock_weights, WeightsArrayCache *cache) +{ + int a; + + if (cache) { + if (cache->num_defgroup_weights) { + for (a = 0; a < cache->num_defgroup_weights; a++) { + if (cache->defgroup_weights[a]) { + MEM_freeN(cache->defgroup_weights[a]); + } + } + MEM_freeN(cache->defgroup_weights); + } + cache->defgroup_weights = NULL; + } + else { + for (a = 0; a < key->totkey; a++) { + if (per_keyblock_weights[a]) { + MEM_freeN(per_keyblock_weights[a]); + } + } + } + + MEM_freeN(per_keyblock_weights); +} + static void do_mesh_key(Scene *scene, Object *ob, Key *key, char *out, const int tot) { KeyBlock *k[4], *actkb = BKE_keyblock_from_object(ob); @@ -1144,17 +1203,11 @@ static void do_mesh_key(Scene *scene, Object *ob, Key *key, char *out, const int } else { if (key->type == KEY_RELATIVE) { - KeyBlock *kb; - for (kb = key->block.first; kb; kb = kb->next) { - kb->weights = get_weights_array(ob, kb->vgroup); - } - - BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, KEY_MODE_DUMMY); - - for (kb = key->block.first; kb; kb = kb->next) { - if (kb->weights) MEM_freeN(kb->weights); - kb->weights = NULL; - } + 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; @@ -1197,11 +1250,11 @@ static void do_rel_cu_key(Curve *cu, Key *key, KeyBlock *actkb, char *out, const for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) { if (nu->bp) { step = nu->pntsu * nu->pntsv; - BKE_key_evaluate_relative(a, a + step, tot, out, key, actkb, KEY_MODE_BPOINT); + BKE_key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BPOINT); } else if (nu->bezt) { step = 3 * nu->pntsu; - BKE_key_evaluate_relative(a, a + step, tot, out, key, actkb, KEY_MODE_BEZTRIPLE); + BKE_key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BEZTRIPLE); } else { step = 0; @@ -1315,17 +1368,10 @@ static void do_latt_key(Scene *scene, Object *ob, Key *key, char *out, const int } else { if (key->type == KEY_RELATIVE) { - KeyBlock *kb; - - for (kb = key->block.first; kb; kb = kb->next) - kb->weights = get_weights_array(ob, kb->vgroup); - - BKE_key_evaluate_relative(0, tot, tot, out, key, actkb, KEY_MODE_DUMMY); - - for (kb = key->block.first; kb; kb = kb->next) { - if (kb->weights) MEM_freeN(kb->weights); - kb->weights = NULL; - } + 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 { const float ctime_scaled = key->ctime / 100.0f; @@ -1415,7 +1461,7 @@ float *BKE_key_evaluate_object_ex(Scene *scene, Object *ob, int *r_totelem, } if (OB_TYPE_SUPPORT_VGROUP(ob->type)) { - float *weights = get_weights_array(ob, kb->vgroup); + float *weights = get_weights_array(ob, kb->vgroup, NULL); cp_key(0, tot, tot, out, key, actkb, kb, weights, 0); diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index a4892253c63..60b4db6aa9b 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -51,6 +51,7 @@ #include "BKE_animsys.h" #include "BKE_anim.h" #include "BKE_cdderivedmesh.h" +#include "BKE_curve.h" #include "BKE_displist.h" #include "BKE_global.h" #include "BKE_key.h" @@ -164,7 +165,7 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb) lt->typeu = lt->typev = lt->typew = KEY_LINEAR; /* prevent using deformed locations */ - BKE_displist_free(<Ob->disp); + BKE_displist_free(<Ob->curve_cache->disp); copy_m4_m4(mat, ltOb->obmat); unit_m4(ltOb->obmat); @@ -306,37 +307,46 @@ void BKE_lattice_make_local(Lattice *lt) } } -void init_latt_deform(Object *oblatt, Object *ob) +typedef struct LatticeDeformData { + Object *object; + float *latticedata; + float latmat[4][4]; +} LatticeDeformData; + +LatticeDeformData *init_latt_deform(Object *oblatt, Object *ob) { /* we make an array with all differences */ Lattice *lt = oblatt->data; BPoint *bp; - DispList *dl = BKE_displist_find(&oblatt->disp, DL_VERTS); + DispList *dl = oblatt->curve_cache ? BKE_displist_find(&oblatt->curve_cache->disp, DL_VERTS) : NULL; float *co = dl ? dl->verts : NULL; float *fp, imat[4][4]; float fu, fv, fw; int u, v, w; + float *latticedata; + float latmat[4][4]; + LatticeDeformData *lattice_deform_data; if (lt->editlatt) lt = lt->editlatt->latt; bp = lt->def; - fp = lt->latticedata = MEM_mallocN(sizeof(float) * 3 * lt->pntsu * lt->pntsv * lt->pntsw, "latticedata"); + fp = latticedata = MEM_mallocN(sizeof(float) * 3 * lt->pntsu * lt->pntsv * lt->pntsw, "latticedata"); /* for example with a particle system: (ob == NULL) */ if (ob == NULL) { /* in deformspace, calc matrix */ - invert_m4_m4(lt->latmat, oblatt->obmat); + invert_m4_m4(latmat, oblatt->obmat); /* back: put in deform array */ - invert_m4_m4(imat, lt->latmat); + invert_m4_m4(imat, latmat); } else { /* in deformspace, calc matrix */ invert_m4_m4(imat, oblatt->obmat); - mul_m4_m4m4(lt->latmat, imat, ob->obmat); + mul_m4_m4m4(latmat, imat, ob->obmat); /* back: put in deform array */ - invert_m4_m4(imat, lt->latmat); + invert_m4_m4(imat, latmat); } for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) { @@ -357,10 +367,18 @@ void init_latt_deform(Object *oblatt, Object *ob) } } } + + lattice_deform_data = MEM_mallocN(sizeof(LatticeDeformData), "Lattice Deform Data"); + lattice_deform_data->latticedata = latticedata; + lattice_deform_data->object = oblatt; + copy_m4_m4(lattice_deform_data->latmat, latmat); + + return lattice_deform_data; } -void calc_latt_deform(Object *ob, float co[3], float weight) +void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float weight) { + Object *ob = lattice_deform_data->object; Lattice *lt = ob->data; float u, v, w, tu[4], tv[4], tw[4]; float vec[3]; @@ -374,7 +392,7 @@ void calc_latt_deform(Object *ob, float co[3], float weight) if (lt->editlatt) lt = lt->editlatt->latt; - if (lt->latticedata == NULL) return; + if (lattice_deform_data->latticedata == NULL) return; if (lt->vgroup[0] && dvert) { defgrp_index = defgroup_name_index(ob, lt->vgroup); @@ -382,7 +400,7 @@ void calc_latt_deform(Object *ob, float co[3], float weight) } /* co is in local coords, treat with latmat */ - mul_v3_m4v3(vec, lt->latmat, co); + mul_v3_m4v3(vec, lattice_deform_data->latmat, co); /* u v w coords */ @@ -455,7 +473,7 @@ void calc_latt_deform(Object *ob, float co[3], float weight) idx_u = idx_v; } - madd_v3_v3fl(co, <->latticedata[idx_u * 3], u); + madd_v3_v3fl(co, &lattice_deform_data->latticedata[idx_u * 3], u); if (defgrp_index != -1) weight_blend += (u * defvert_find_weight(dvert + idx_u, defgrp_index)); @@ -471,15 +489,12 @@ void calc_latt_deform(Object *ob, float co[3], float weight) } -void end_latt_deform(Object *ob) +void end_latt_deform(LatticeDeformData *lattice_deform_data) { - Lattice *lt = ob->data; - - if (lt->editlatt) lt = lt->editlatt->latt; - - if (lt->latticedata) - MEM_freeN(lt->latticedata); - lt->latticedata = NULL; + if (lattice_deform_data->latticedata) + MEM_freeN(lattice_deform_data->latticedata); + + MEM_freeN(lattice_deform_data); } /* calculations is in local space of deformed object @@ -506,13 +521,12 @@ static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd) */ static int where_on_path_deform(Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius) { - Curve *cu = ob->data; BevList *bl; float ctime1; int cycl = 0; /* test for cyclic */ - bl = cu->bev.first; + bl = ob->curve_cache->bev.first; if (!bl->nr) return 0; if (bl->poly > -1) cycl = 1; @@ -527,7 +541,7 @@ static int where_on_path_deform(Object *ob, float ctime, float vec[4], float dir if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) { if (cycl == 0) { - Path *path = cu->path; + Path *path = ob->curve_cache->path; float dvec[3]; if (ctime < 0.0f) { @@ -565,9 +579,9 @@ static int calc_curve_deform(Scene *scene, Object *par, float co[3], const int is_neg_axis = (axis > 2); /* to be sure, mostly after file load */ - if (cu->path == NULL) { + if (ELEM(NULL, par->curve_cache, par->curve_cache->path)) { BKE_displist_make_curveTypes(scene, par, 0); - if (cu->path == NULL) return 0; // happens on append... + if (par->curve_cache->path == NULL) return 0; // happens on append... } /* options */ @@ -576,14 +590,14 @@ static int calc_curve_deform(Scene *scene, Object *par, float co[3], if (cu->flag & CU_STRETCH) fac = (-co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]); else - fac = -(co[index] - cd->dmax[index]) / (cu->path->totdist); + fac = -(co[index] - cd->dmax[index]) / (par->curve_cache->path->totdist); } else { index = axis; if (cu->flag & CU_STRETCH) fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]); else - fac = +(co[index] - cd->dmin[index]) / (cu->path->totdist); + fac = +(co[index] - cd->dmin[index]) / (par->curve_cache->path->totdist); } if (where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) { /* returns OK */ @@ -815,13 +829,14 @@ void curve_deform_vector(Scene *scene, Object *cuOb, Object *target, void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, const char *vgroup, float fac) { + LatticeDeformData *lattice_deform_data; int a; int use_vgroups; if (laOb->type != OB_LATTICE) return; - init_latt_deform(laOb, target); + lattice_deform_data = init_latt_deform(laOb, target); /* check whether to use vertex groups (only possible if target is a Mesh) * we want either a Mesh with no derived data, or derived data with @@ -855,16 +870,16 @@ void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm, weight = defvert_find_weight(dvert, defgrp_index); if (weight > 0.0f) - calc_latt_deform(laOb, vertexCos[a], weight * fac); + calc_latt_deform(lattice_deform_data, vertexCos[a], weight * fac); } } } else { for (a = 0; a < numVerts; a++) { - calc_latt_deform(laOb, vertexCos[a], fac); + calc_latt_deform(lattice_deform_data, vertexCos[a], fac); } } - end_latt_deform(laOb); + end_latt_deform(lattice_deform_data); } int object_deform_mball(Object *ob, ListBase *dispbase) @@ -991,11 +1006,17 @@ void BKE_lattice_vertexcos_apply(struct Object *ob, float (*vertexCos)[3]) void BKE_lattice_modifiers_calc(Scene *scene, Object *ob) { Lattice *lt = ob->data; - ModifierData *md = modifiers_getVirtualModifierList(ob); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); float (*vertexCos)[3] = NULL; int numVerts, editmode = (lt->editlatt != NULL); - BKE_displist_free(&ob->disp); + if (ob->curve_cache) { + BKE_displist_free(&ob->curve_cache->disp); + } + else { + ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice"); + } for (; md; md = md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); @@ -1021,7 +1042,7 @@ void BKE_lattice_modifiers_calc(Scene *scene, Object *ob) dl->nr = numVerts; dl->verts = (float *) vertexCos; - BLI_addtail(&ob->disp, dl); + BLI_addtail(&ob->curve_cache->disp, dl); } } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index c23fa097d3e..9b8d34e651d 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -269,7 +269,8 @@ bool id_make_local(ID *id, bool test) if (!test) BKE_action_make_local((bAction *)id); return true; case ID_NT: - return false; /* not implemented */ + if (!test) ntreeMakeLocal((bNodeTree *)id); + return true; case ID_BR: if (!test) BKE_brush_make_local((Brush *)id); return true; @@ -1410,7 +1411,7 @@ bool new_id(ListBase *lb, ID *id, const char *tname) /* This was in 2.43 and previous releases * however all data in blender should be sorted, not just duplicate names - * sorting should not hurt, but noting just incause it alters the way other + * sorting should not hurt, but noting just incase it alters the way other * functions work, so sort every time */ #if 0 if (result) diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 497554be113..d3c9250694c 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -81,6 +81,7 @@ static void default_linestyle_settings(FreestyleLineStyle *linestyle) linestyle->thickness = 3.0f; linestyle->thickness_position = LS_THICKNESS_CENTER; linestyle->thickness_ratio = 0.5f; + linestyle->flag = LS_SAME_OBJECT; linestyle->chaining = LS_CHAINING_PLAIN; linestyle->rounds = 3; linestyle->min_angle = DEG2RADF(0.0f); diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index e3f30bad5cf..c856d8cfea4 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -817,6 +817,19 @@ void BKE_mask_spline_free(MaskSpline *spline) MEM_freeN(spline); } +void BKE_mask_spline_free_list(ListBase *splines) +{ + MaskSpline *spline = splines->first; + while (spline) { + MaskSpline *next_spline = spline->next; + + BLI_remlink(splines, spline); + BKE_mask_spline_free(spline); + + spline = next_spline; + } +} + static MaskSplinePoint *mask_spline_points_copy(MaskSplinePoint *points, int tot_point) { MaskSplinePoint *npoints; @@ -891,20 +904,30 @@ void BKE_mask_layer_free_shapes(MaskLayer *masklay) } } -void BKE_mask_layer_free(MaskLayer *masklay) +void BKE_mask_layer_free_deform(MaskLayer *mask_layer) { - MaskSpline *spline; - - /* free splines */ - spline = masklay->splines.first; - while (spline) { - MaskSpline *next_spline = spline->next; + MaskSpline *mask_spline; - BLI_remlink(&masklay->splines, spline); - BKE_mask_spline_free(spline); - - spline = next_spline; + for (mask_spline = mask_layer->splines.first; + mask_spline; + mask_spline = mask_spline->next) + { + if (mask_spline->points_deform) { + int i; + MaskSplinePoint *points_deform = mask_spline->points_deform; + for (i = 0; i < mask_spline->tot_point; i++) { + BKE_mask_point_free(&points_deform[i]); + } + MEM_freeN(points_deform); + mask_spline->points_deform = NULL; + } } +} + +void BKE_mask_layer_free(MaskLayer *masklay) +{ + /* free splines */ + BKE_mask_spline_free_list(&masklay->splines); /* free animation data */ BKE_mask_layer_free_shapes(masklay); @@ -1072,10 +1095,15 @@ void BKE_mask_coord_to_image(Image *image, ImageUser *iuser, float r_co[2], cons BKE_mask_coord_to_frame(r_co, co, frame_size); } -static int BKE_mask_evaluate_parent(MaskParent *parent, float ctime, float r_co[2]) +void BKE_mask_point_parent_matrix_get(MaskSplinePoint *point, float ctime, float parent_matrix[3][3]) { - if (!parent) - return FALSE; + MaskParent *parent = &point->parent; + + unit_m3(parent_matrix); + + if (!parent) { + return; + } if (parent->id_type == ID_MC) { if (parent->id) { @@ -1084,38 +1112,66 @@ static int BKE_mask_evaluate_parent(MaskParent *parent, float ctime, float r_co[ MovieTrackingObject *ob = BKE_tracking_object_get_named(tracking, parent->parent); if (ob) { - MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, ob, parent->sub_parent); + MovieClipUser user = {0}; float clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime); + BKE_movieclip_user_set_frame(&user, ctime); - MovieClipUser user = {0}; - user.framenr = ctime; + if (parent->type == MASK_PARENT_POINT_TRACK) { + MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, ob, parent->sub_parent); + + if (track) { + float marker_position[2], parent_co[2]; + BKE_tracking_marker_get_subframe_position(track, clip_framenr, marker_position); + BKE_mask_coord_from_movieclip(clip, &user, parent_co, marker_position); + sub_v2_v2v2(parent_matrix[2], parent_co, parent->parent_orig); + } + } + else /* if (parent->type == MASK_PARENT_PLANE_TRACK) */ { + 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 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); - if (track) { - float marker_pos_ofs[2]; - BKE_tracking_marker_get_subframe_position(track, clip_framenr, marker_pos_ofs); - BKE_mask_coord_from_movieclip(clip, &user, r_co, marker_pos_ofs); + unit_m3(mask_from_clip_matrix); - return TRUE; + BKE_movieclip_get_size_fl(clip, &user, frame_size); + BKE_movieclip_get_aspect(clip, &aspx, &aspy); + + frame_size[1] *= (aspy / aspx); + if (frame_size[0] == frame_size[1]) { + /* pass */ + } + else if (frame_size[0] < frame_size[1]) { + mask_from_clip_matrix[0][0] = frame_size[1] / frame_size[0]; + mask_from_clip_matrix[2][0] = -0.5f * (frame_size[1] / frame_size[0]) + 0.5f; + } + else { /* (frame_size[0] > frame_size[1]) */ + mask_from_clip_matrix[1][1] = frame_size[1] / frame_size[0]; + mask_from_clip_matrix[2][1] = -0.5f * (frame_size[1] / frame_size[0]) + 0.5f; + } + + invert_m3_m3(mask_to_clip_matrix, mask_from_clip_matrix); + mul_serie_m3(parent_matrix, mask_to_clip_matrix, H, mask_from_clip_matrix, NULL, NULL, NULL, NULL, NULL); + } } } } } - - return FALSE; } -/* could make external but for now its only used internally */ -static int mask_evaluate_parent_delta(MaskParent *parent, float ctime, float r_delta[2]) +static void mask_evaluate_apply_point_parent(MaskSplinePoint *point, float ctime) { - float parent_co[2]; + float parent_matrix[3][3]; - if (BKE_mask_evaluate_parent(parent, ctime, parent_co)) { - sub_v2_v2v2(r_delta, parent_co, parent->parent_orig); - return TRUE; - } - else { - return FALSE; - } + BKE_mask_point_parent_matrix_get(point, ctime, parent_matrix); + + mul_m3_v2(parent_matrix, point->bezt.vec[0]); + mul_m3_v2(parent_matrix, point->bezt.vec[1]); + mul_m3_v2(parent_matrix, point->bezt.vec[2]); } static void mask_calc_point_handle(MaskSplinePoint *point, MaskSplinePoint *point_prev, MaskSplinePoint *point_next) @@ -1350,7 +1406,7 @@ void BKE_mask_update_deform(Mask *mask) int j; for (j = 0; j <= 2; j += 2) { /* (0, 2) */ - printf("--- %d %d, %d, %d\n", i, j, i_prev, i_next); + // printf("--- %d %d, %d, %d\n", i, j, i_prev, i_next); barycentric_weights_v2(bezt_prev->vec[1], bezt->vec[1], bezt_next->vec[1], bezt->vec[j], w_src); interp_v3_v3v3v3(bezt_def->vec[j], @@ -1438,18 +1494,13 @@ void BKE_mask_layer_evaluate(MaskLayer *masklay, const float ctime, const int do for (i = 0; i < spline->tot_point; i++) { MaskSplinePoint *point = &spline->points[i]; MaskSplinePoint *point_deform = &spline->points_deform[i]; - float delta[2]; BKE_mask_point_free(point_deform); *point_deform = *point; point_deform->uw = point->uw ? MEM_dupallocN(point->uw) : NULL; - if (mask_evaluate_parent_delta(&point->parent, ctime, delta)) { - add_v2_v2(point_deform->bezt.vec[0], delta); - add_v2_v2(point_deform->bezt.vec[1], delta); - add_v2_v2(point_deform->bezt.vec[2], delta); - } + mask_evaluate_apply_point_parent(point_deform, ctime); if (ELEM(point->bezt.h1, HD_AUTO, HD_VECT)) { need_handle_recalc = TRUE; diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index ac48eaa3185..874e60936d1 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -82,17 +82,10 @@ #include "BLI_rect.h" #include "BLI_listbase.h" #include "BLI_linklist.h" +#include "BLI_strict_flags.h" #include "BKE_mask.h" -#ifdef __GNUC__ -# pragma GCC diagnostic error "-Wsign-conversion" -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 /* gcc4.6+ only */ -# pragma GCC diagnostic error "-Wsign-compare" -# pragma GCC diagnostic error "-Wconversion" -# endif -#endif - /* this is rather and annoying hack, use define to isolate it. * problem is caused by scanfill removing edges on us. */ #define USE_SCANFILL_EDGE_WORKAROUND @@ -575,11 +568,14 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mas const float zvec[3] = {0.0f, 0.0f, 1.0f}; MaskLayer *masklay; unsigned int masklay_index; + MemArena *sf_arena; mr_handle->layers_tot = (unsigned int)BLI_countlist(&mask->masklayers); mr_handle->layers = MEM_mallocN(sizeof(MaskRasterLayer) * mr_handle->layers_tot, "MaskRasterLayer"); BLI_rctf_init_minmax(&mr_handle->bounds); + sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__); + for (masklay = mask->masklayers.first, masklay_index = 0; masklay; masklay = masklay->next, masklay_index++) { /* we need to store vertex ranges for open splines for filling */ @@ -613,7 +609,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mas tot_splines = (unsigned int)BLI_countlist(&masklay->splines); open_spline_ranges = MEM_callocN(sizeof(*open_spline_ranges) * tot_splines, __func__); - BLI_scanfill_begin(&sf_ctx); + BLI_scanfill_begin_arena(&sf_ctx, sf_arena); for (spline = masklay->splines.first; spline; spline = spline->next) { const unsigned int is_cyclic = (spline->flag & MASK_SPLINE_CYCLIC) != 0; @@ -1148,8 +1144,10 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mas } /* add trianges */ - BLI_scanfill_end(&sf_ctx); + BLI_scanfill_end_arena(&sf_ctx, sf_arena); } + + BLI_memarena_free(sf_arena); } diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 1bda662a8b0..f3dc64a7279 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -573,6 +573,34 @@ static void material_data_index_clear_id(ID *id) } } +void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user) +{ + Material ***matar = give_matarar_id(id); + short *totcolp = give_totcolp_id(id); + + if (matar == NULL) { + return; + } + + if (do_id_user && totcol < (*totcolp)) { + short i; + for (i = totcol; i < (*totcolp); i++) { + id_us_min((ID *)(*matar)[i]); + } + } + + if (totcol == 0) { + if (*totcolp) { + MEM_freeN(*matar); + *matar = NULL; + } + } + else { + *matar = MEM_recallocN(*matar, sizeof(void *) * totcol); + } + *totcolp = totcol; +} + void BKE_material_append_id(ID *id, Material *ma) { Material ***matar; @@ -708,11 +736,18 @@ Material *give_node_material(Material *ma) return NULL; } -void resize_object_material(Object *ob, const short totcol) +void BKE_material_resize_object(Object *ob, const short totcol, bool do_id_user) { Material **newmatar; char *newmatbits; + if (do_id_user && totcol < ob->totcol) { + short i; + for (i = totcol; i < ob->totcol; i++) { + id_us_min((ID *)ob->mat[i]); + } + } + if (totcol == 0) { if (ob->totcol) { MEM_freeN(ob->mat); @@ -733,6 +768,8 @@ void resize_object_material(Object *ob, const short totcol) ob->mat = newmatar; ob->matbits = newmatbits; } + /* XXX, why not realloc on shrink? - campbell */ + ob->totcol = totcol; if (ob->totcol && ob->actcol == 0) ob->actcol = 1; if (ob->actcol > ob->totcol) ob->actcol = ob->totcol; @@ -750,7 +787,7 @@ void test_object_materials(Main *bmain, ID *id) for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->data == id) { - resize_object_material(ob, *totcol); + BKE_material_resize_object(ob, *totcol, false); } } } @@ -1254,7 +1291,9 @@ int object_remove_material_slot(Object *ob) /* check indices from mesh */ if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { material_data_index_remove_id((ID *)ob->data, actcol - 1); - BKE_displist_free(&ob->disp); + if (ob->curve_cache) { + BKE_displist_free(&ob->curve_cache->disp); + } } return TRUE; diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 173b193b752..a4b59153e2b 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -56,6 +56,7 @@ /* #include "BKE_object.h" */ #include "BKE_animsys.h" +#include "BKE_curve.h" #include "BKE_scene.h" #include "BKE_library.h" #include "BKE_displist.h" @@ -199,7 +200,6 @@ void BKE_mball_free(MetaBall *mb) mb->adt = NULL; } if (mb->mat) MEM_freeN(mb->mat); - if (mb->bb) MEM_freeN(mb->bb); BLI_freelistN(&mb->elems); if (mb->disp.first) BKE_displist_free(&mb->disp); } @@ -233,7 +233,6 @@ MetaBall *BKE_mball_copy(MetaBall *mb) for (a = 0; a < mbn->totcol; a++) { id_us_plus((ID *)mbn->mat[a]); } - mbn->bb = MEM_dupallocN(mb->bb); mbn->editelems = NULL; mbn->lastelem = NULL; @@ -366,7 +365,7 @@ void BKE_mball_texspace_calc(Object *ob) (min)[0] = (min)[1] = (min)[2] = 1.0e30f; (max)[0] = (max)[1] = (max)[2] = -1.0e30f; - dl = ob->disp.first; + dl = ob->curve_cache->disp.first; while (dl) { tot = dl->nr; if (tot) do_it = TRUE; @@ -2281,7 +2280,7 @@ static void mball_count(PROCESS *process, Scene *scene, Object *basis) } } -void BKE_mball_polygonize(Scene *scene, Object *ob, ListBase *dispbase) +void BKE_mball_polygonize(Scene *scene, Object *ob, ListBase *dispbase, bool for_render) { MetaBall *mb; DispList *dl; @@ -2294,7 +2293,7 @@ void BKE_mball_polygonize(Scene *scene, Object *ob, ListBase *dispbase) mball_count(&process, scene, ob); if (process.totelem == 0) return; - if ((G.is_rendering == FALSE) && (mb->flag == MB_UPDATE_NEVER)) return; + if ((for_render == false) && (mb->flag == MB_UPDATE_NEVER)) return; if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return; process.thresh = mb->thresh; @@ -2332,7 +2331,7 @@ void BKE_mball_polygonize(Scene *scene, Object *ob, ListBase *dispbase) } /* width is size per polygonize cube */ - if (G.is_rendering) { + if (for_render) { width = mb->rendersize; } else { diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 0db1f92f70f..a77f768835a 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -27,12 +27,6 @@ * \ingroup bke */ - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <math.h> - #include "MEM_guardedalloc.h" #include "DNA_scene_types.h" @@ -40,22 +34,17 @@ #include "DNA_object_types.h" #include "DNA_key_types.h" #include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" #include "DNA_ipo_types.h" -#include "DNA_customdata_types.h" #include "BLI_utildefines.h" -#include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_listbase.h" #include "BLI_edgehash.h" -#include "BLI_bitmap.h" -#include "BLI_scanfill.h" -#include "BLI_array.h" -#include "BLI_alloca.h" +#include "BLI_string_utf8.h" +#include "BLI_string.h" #include "BKE_animsys.h" #include "BKE_main.h" -#include "BKE_customdata.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_mesh.h" @@ -70,9 +59,7 @@ /* -- */ #include "BKE_object.h" #include "BKE_editmesh.h" -#include "BLI_edgehash.h" -#include "bmesh.h" enum { MESHCMP_DVERT_WEIGHTMISMATCH = 1, @@ -177,8 +164,8 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2 if (l1->type == CD_MEDGE) { MEdge *e1 = l1->data; MEdge *e2 = l2->data; - EdgeHash *eh = BLI_edgehash_new(); int etot = m1->totedge; + EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot); for (j = 0; j < etot; j++, e1++) { BLI_edgehash_insert(eh, e1->v1, e1->v2, e1); @@ -274,7 +261,12 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2 return 0; } -/*used for testing. returns an error string the two meshes don't match*/ +/** + * Used for unit testing; compares two meshes, checking only + * differences we care about. should be usable with leaf's + * testing framework I get RNA work done, will use hackish + * testing code for now. + */ const char *BKE_mesh_cmp(Mesh *me1, Mesh *me2, float thresh) { int c; @@ -538,8 +530,9 @@ Mesh *BKE_mesh_copy(Mesh *me) BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob) { BMesh *bm; + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me); - bm = BM_mesh_create(&bm_mesh_allocsize_default); + bm = BM_mesh_create(&allocsize); BM_mesh_bm_from_me(bm, me, false, true, ob->shapenr); @@ -632,6 +625,113 @@ void BKE_mesh_make_local(Mesh *me) } } +bool BKE_mesh_uv_cdlayer_rename_index(Mesh *me, const int poly_index, const int loop_index, const int face_index, + const char *new_name, const bool do_tessface) +{ + CustomData *pdata, *ldata, *fdata; + CustomDataLayer *cdlp, *cdlu, *cdlf; + const int step = do_tessface ? 3 : 2; + int i; + + if (me->edit_btmesh) { + pdata = &me->edit_btmesh->bm->pdata; + ldata = &me->edit_btmesh->bm->ldata; + fdata = NULL; /* No tessellated data in BMesh! */ + } + else { + pdata = &me->pdata; + ldata = &me->ldata; + fdata = &me->fdata; + } + cdlp = &pdata->layers[poly_index]; + cdlu = &ldata->layers[loop_index]; + cdlf = fdata && do_tessface ? &fdata->layers[face_index] : NULL; + + BLI_strncpy(cdlp->name, new_name, sizeof(cdlp->name)); + CustomData_set_layer_unique_name(pdata, cdlp - pdata->layers); + + /* Loop until we do have exactly the same name for all layers! */ + for (i = 1; (strcmp(cdlp->name, cdlu->name) != 0 || (cdlf && strcmp(cdlp->name, cdlf->name) != 0)); i++) { + switch (i % step) { + case 0: + BLI_strncpy(cdlp->name, cdlu->name, sizeof(cdlp->name)); + CustomData_set_layer_unique_name(pdata, cdlp - pdata->layers); + break; + case 1: + BLI_strncpy(cdlu->name, cdlp->name, sizeof(cdlu->name)); + CustomData_set_layer_unique_name(ldata, cdlu - ldata->layers); + break; + case 2: + if (cdlf) { + BLI_strncpy(cdlf->name, cdlp->name, sizeof(cdlf->name)); + CustomData_set_layer_unique_name(fdata, cdlf - fdata->layers); + } + break; + } + } + + return true; +} + +bool BKE_mesh_uv_cdlayer_rename(Mesh *me, const char *old_name, const char *new_name, bool do_tessface) +{ + CustomData *pdata, *ldata, *fdata; + if (me->edit_btmesh) { + pdata = &me->edit_btmesh->bm->pdata; + ldata = &me->edit_btmesh->bm->ldata; + /* No tessellated data in BMesh! */ + fdata = NULL; + do_tessface = false; + } + else { + pdata = &me->pdata; + ldata = &me->ldata; + fdata = &me->fdata; + do_tessface = (do_tessface && fdata->totlayer); + } + + { + const int pidx_start = CustomData_get_layer_index(pdata, CD_MTEXPOLY); + const int lidx_start = CustomData_get_layer_index(ldata, CD_MLOOPUV); + const int fidx_start = do_tessface ? CustomData_get_layer_index(fdata, CD_MTFACE) : -1; + int pidx = CustomData_get_named_layer(pdata, CD_MTEXPOLY, old_name); + int lidx = CustomData_get_named_layer(ldata, CD_MLOOPUV, old_name); + int fidx = do_tessface ? CustomData_get_named_layer(fdata, CD_MTFACE, old_name) : -1; + + /* None of those cases should happen, in theory! + * Note this assume we have the same number of mtexpoly, mloopuv and mtface layers! + */ + if (pidx == -1) { + if (lidx == -1) { + if (fidx == -1) { + /* No layer found with this name! */ + return false; + } + else { + lidx = lidx_start + (fidx - fidx_start); + } + } + pidx = pidx_start + (lidx - lidx_start); + } + else { + if (lidx == -1) { + lidx = lidx_start + (pidx - pidx_start); + } + if (fidx == -1 && do_tessface) { + fidx = fidx_start + (pidx - pidx_start); + } + } +#if 0 + /* For now, we do not consider mismatch in indices (i.e. same name leading to (relative) different indices). */ + else if ((pidx - pidx_start) != (lidx - lidx_start)) { + lidx = lidx_start + (pidx - pidx_start); + } +#endif + + return BKE_mesh_uv_cdlayer_rename_index(me, pidx, lidx, fidx, new_name, do_tessface); + } +} + void BKE_mesh_boundbox_calc(Mesh *me, float r_loc[3], float r_size[3]) { BoundBox *bb; @@ -657,6 +757,8 @@ void BKE_mesh_boundbox_calc(Mesh *me, float r_loc[3], float r_size[3]) r_size[2] = (max[2] - min[2]) / 2.0f; BKE_boundbox_init_from_minmax(bb, min, max); + + bb->flag &= ~BOUNDBOX_DIRTY; } void BKE_mesh_texspace_calc(Mesh *me) @@ -686,15 +788,16 @@ BoundBox *BKE_mesh_boundbox_get(Object *ob) if (ob->bb) return ob->bb; - if (!me->bb) + if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { BKE_mesh_texspace_calc(me); + } return me->bb; } void BKE_mesh_texspace_get(Mesh *me, float r_loc[3], float r_rot[3], float r_size[3]) { - if (!me->bb) { + if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { BKE_mesh_texspace_calc(me); } @@ -862,308 +965,6 @@ void BKE_mesh_assign_object(Object *ob, Mesh *me) test_object_modifiers(ob); } -/* ************** make edges in a Mesh, for outside of editmode */ - -struct EdgeSort { - unsigned int v1, v2; - char is_loose, is_draw; -}; - -/* edges have to be added with lowest index first for sorting */ -static void to_edgesort(struct EdgeSort *ed, - unsigned int v1, unsigned int v2, - char is_loose, short is_draw) -{ - if (v1 < v2) { - ed->v1 = v1; ed->v2 = v2; - } - else { - ed->v1 = v2; ed->v2 = v1; - } - ed->is_loose = is_loose; - ed->is_draw = is_draw; -} - -static int vergedgesort(const void *v1, const void *v2) -{ - const struct EdgeSort *x1 = v1, *x2 = v2; - - if (x1->v1 > x2->v1) return 1; - else if (x1->v1 < x2->v1) return -1; - else if (x1->v2 > x2->v2) return 1; - else if (x1->v2 < x2->v2) return -1; - - return 0; -} - - -/* Create edges based on known verts and faces, - * this function is only used when loading very old blend files */ - -static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, MLoop *allloop, - MPoly *allpoly, int UNUSED(totvert), int totface, int UNUSED(totloop), int totpoly, - const bool use_old, - MEdge **r_medge, int *r_totedge) -{ - MPoly *mpoly; - MFace *mface; - MEdge *medge, *med; - EdgeHash *hash = BLI_edgehash_new(); - struct EdgeSort *edsort, *ed; - int a, totedge = 0; - unsigned int totedge_final = 0; - unsigned int edge_index; - - /* we put all edges in array, sort them, and detect doubles that way */ - - for (a = totface, mface = allface; a > 0; a--, mface++) { - if (mface->v4) totedge += 4; - else if (mface->v3) totedge += 3; - else totedge += 1; - } - - if (totedge == 0) { - /* flag that mesh has edges */ - (*r_medge) = MEM_callocN(0, __func__); - (*r_totedge) = 0; - return; - } - - ed = edsort = MEM_mallocN(totedge * sizeof(struct EdgeSort), "EdgeSort"); - - for (a = totface, mface = allface; a > 0; a--, mface++) { - to_edgesort(ed++, mface->v1, mface->v2, !mface->v3, mface->edcode & ME_V1V2); - if (mface->v4) { - to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3); - to_edgesort(ed++, mface->v3, mface->v4, 0, mface->edcode & ME_V3V4); - to_edgesort(ed++, mface->v4, mface->v1, 0, mface->edcode & ME_V4V1); - } - else if (mface->v3) { - to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3); - to_edgesort(ed++, mface->v3, mface->v1, 0, mface->edcode & ME_V3V1); - } - } - - qsort(edsort, totedge, sizeof(struct EdgeSort), vergedgesort); - - /* count final amount */ - for (a = totedge, ed = edsort; a > 1; a--, ed++) { - /* edge is unique when it differs from next edge, or is last */ - if (ed->v1 != (ed + 1)->v1 || ed->v2 != (ed + 1)->v2) totedge_final++; - } - totedge_final++; - - medge = MEM_callocN(sizeof(MEdge) * totedge_final, __func__); - - for (a = totedge, med = medge, ed = edsort; a > 1; a--, ed++) { - /* edge is unique when it differs from next edge, or is last */ - if (ed->v1 != (ed + 1)->v1 || ed->v2 != (ed + 1)->v2) { - med->v1 = ed->v1; - med->v2 = ed->v2; - if (use_old == false || ed->is_draw) med->flag = ME_EDGEDRAW | ME_EDGERENDER; - if (ed->is_loose) med->flag |= ME_LOOSEEDGE; - - /* order is swapped so extruding this edge as a surface wont flip face normals - * with cyclic curves */ - if (ed->v1 + 1 != ed->v2) { - SWAP(unsigned int, med->v1, med->v2); - } - med++; - } - else { - /* equal edge, we merge the drawflag */ - (ed + 1)->is_draw |= ed->is_draw; - } - } - /* last edge */ - med->v1 = ed->v1; - med->v2 = ed->v2; - med->flag = ME_EDGEDRAW; - if (ed->is_loose) med->flag |= ME_LOOSEEDGE; - med->flag |= ME_EDGERENDER; - - MEM_freeN(edsort); - - /* set edge members of mloops */ - for (edge_index = 0, med = medge; edge_index < totedge_final; edge_index++, med++) { - BLI_edgehash_insert(hash, med->v1, med->v2, SET_UINT_IN_POINTER(edge_index)); - } - - mpoly = allpoly; - for (a = 0; a < totpoly; a++, mpoly++) { - MLoop *ml, *ml_next; - int i = mpoly->totloop; - - ml_next = allloop + mpoly->loopstart; /* first loop */ - ml = &ml_next[i - 1]; /* last loop */ - - while (i-- != 0) { - ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(hash, ml->v, ml_next->v)); - ml = ml_next; - ml_next++; - } - } - - BLI_edgehash_free(hash, NULL); - - *r_medge = medge; - *r_totedge = totedge_final; -} - -void BKE_mesh_make_edges(Mesh *me, const bool use_old) -{ - MEdge *medge; - int totedge = 0; - - make_edges_mdata(me->mvert, me->mface, me->mloop, me->mpoly, - me->totvert, me->totface, me->totloop, me->totpoly, - use_old, &medge, &totedge); - - if (totedge == 0) { - /* flag that mesh has edges */ - me->medge = medge; - me->totedge = 0; - return; - } - - medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, totedge); - me->medge = medge; - me->totedge = totedge; - - BKE_mesh_strip_loose_faces(me); -} - -/* We need to keep this for edge creation (for now?), and some old readfile code... */ -void BKE_mesh_strip_loose_faces(Mesh *me) -{ - MFace *f; - int a, b; - - for (a = b = 0, f = me->mface; a < me->totface; a++, f++) { - if (f->v3) { - if (a != b) { - memcpy(&me->mface[b], f, sizeof(me->mface[b])); - CustomData_copy_data(&me->fdata, &me->fdata, a, b, 1); - } - b++; - } - } - if (a != b) { - CustomData_free_elem(&me->fdata, b, a - b); - me->totface = b; - } -} - -/* Works on both loops and polys! */ -/* Note: It won't try to guess which loops of an invalid poly to remove! - * this is the work of the caller, to mark those loops... - * See e.g. BKE_mesh_validate_arrays(). */ -void BKE_mesh_strip_loose_polysloops(Mesh *me) -{ - MPoly *p; - MLoop *l; - int a, b; - /* New loops idx! */ - int *new_idx = MEM_mallocN(sizeof(int) * me->totloop, __func__); - - for (a = b = 0, p = me->mpoly; a < me->totpoly; a++, p++) { - int invalid = FALSE; - int i = p->loopstart; - int stop = i + p->totloop; - - if (stop > me->totloop || stop < i) { - invalid = TRUE; - } - else { - l = &me->mloop[i]; - i = stop - i; - /* If one of the poly's loops is invalid, the whole poly is invalid! */ - for (; i--; l++) { - if (l->e == INVALID_LOOP_EDGE_MARKER) { - invalid = TRUE; - break; - } - } - } - - if (p->totloop >= 3 && !invalid) { - if (a != b) { - memcpy(&me->mpoly[b], p, sizeof(me->mpoly[b])); - CustomData_copy_data(&me->pdata, &me->pdata, a, b, 1); - } - b++; - } - } - if (a != b) { - CustomData_free_elem(&me->pdata, b, a - b); - me->totpoly = b; - } - - /* And now, get rid of invalid loops. */ - for (a = b = 0, l = me->mloop; a < me->totloop; a++, l++) { - if (l->e != INVALID_LOOP_EDGE_MARKER) { - if (a != b) { - memcpy(&me->mloop[b], l, sizeof(me->mloop[b])); - CustomData_copy_data(&me->ldata, &me->ldata, a, b, 1); - } - new_idx[a] = b; - b++; - } - else { - /* XXX Theoretically, we should be able to not do this, as no remaining poly - * should use any stripped loop. But for security's sake... */ - new_idx[a] = -a; - } - } - if (a != b) { - CustomData_free_elem(&me->ldata, b, a - b); - me->totloop = b; - } - - /* And now, update polys' start loop index. */ - /* Note: At this point, there should never be any poly using a striped loop! */ - for (a = 0, p = me->mpoly; a < me->totpoly; a++, p++) { - p->loopstart = new_idx[p->loopstart]; - } - - MEM_freeN(new_idx); -} - -void BKE_mesh_strip_loose_edges(Mesh *me) -{ - MEdge *e; - MLoop *l; - int a, b; - unsigned int *new_idx = MEM_mallocN(sizeof(int) * me->totedge, __func__); - - for (a = b = 0, e = me->medge; a < me->totedge; a++, e++) { - if (e->v1 != e->v2) { - if (a != b) { - memcpy(&me->medge[b], e, sizeof(me->medge[b])); - CustomData_copy_data(&me->edata, &me->edata, a, b, 1); - } - new_idx[a] = b; - b++; - } - else { - new_idx[a] = INVALID_LOOP_EDGE_MARKER; - } - } - if (a != b) { - CustomData_free_elem(&me->edata, b, a - b); - me->totedge = b; - } - - /* And now, update loops' edge indices. */ - /* XXX We hope no loop was pointing to a striped edge! - * Else, its e will be set to INVALID_LOOP_EDGE_MARKER :/ */ - for (a = 0, l = me->mloop; a < me->totloop; a++, l++) { - l->e = new_idx[l->e]; - } - - MEM_freeN(new_idx); -} - void BKE_mesh_from_metaball(ListBase *lb, Mesh *me) { DispList *dl; @@ -1237,10 +1038,12 @@ static void make_edges_mdata_extend(MEdge **r_alledge, int *r_totedge, int totedge = *r_totedge; int totedge_new; EdgeHash *eh; + unsigned int eh_reserve; const MPoly *mp; int i; - eh = BLI_edgehash_new(); + eh_reserve = max_ii(totedge, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totpoly)); + eh = BLI_edgehash_new_ex(__func__, eh_reserve); for (i = 0, mp = mpoly; i < totpoly; i++, mp++) { BKE_mesh_poly_edgehash_insert(eh, mp, mloop + mp->loopstart); @@ -1307,7 +1110,13 @@ int BKE_mesh_nurbs_to_mdata(Object *ob, MVert **allvert, int *totvert, MEdge **alledge, int *totedge, MLoop **allloop, MPoly **allpoly, int *totloop, int *totpoly) { - return BKE_mesh_nurbs_displist_to_mdata(ob, &ob->disp, + ListBase disp = {NULL, NULL}; + + if (ob->curve_cache) { + disp = ob->curve_cache->disp; + } + + return BKE_mesh_nurbs_displist_to_mdata(ob, &disp, allvert, totvert, alledge, totedge, allloop, allpoly, NULL, @@ -1653,8 +1462,13 @@ void BKE_mesh_from_nurbs(Object *ob) { Curve *cu = (Curve *) ob->data; bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0; + ListBase disp = {NULL, NULL}; + + if (ob->curve_cache) { + disp = ob->curve_cache->disp; + } - BKE_mesh_from_nurbs_displist(ob, &ob->disp, use_orco_uv); + BKE_mesh_from_nurbs_displist(ob, &disp, use_orco_uv); } typedef struct EdgeLink { @@ -1914,445 +1728,10 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth) } } -void BKE_mesh_calc_normals_mapping(MVert *mverts, int numVerts, - MLoop *mloop, MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3], - MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3]) -{ - BKE_mesh_calc_normals_mapping_ex(mverts, numVerts, mloop, mpolys, - numLoops, numPolys, polyNors_r, mfaces, numFaces, - origIndexFace, faceNors_r, FALSE); -} - -void BKE_mesh_calc_normals_mapping_ex(MVert *mverts, int numVerts, - MLoop *mloop, MPoly *mpolys, - int numLoops, int numPolys, float (*polyNors_r)[3], - MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3], - const bool only_face_normals) -{ - float (*pnors)[3] = polyNors_r, (*fnors)[3] = faceNors_r; - int i; - MFace *mf; - MPoly *mp; - - if (numPolys == 0) { - return; - } - - /* if we are not calculating verts and no verts were passes then we have nothing to do */ - if ((only_face_normals == TRUE) && (polyNors_r == NULL) && (faceNors_r == NULL)) { - printf("%s: called with nothing to do\n", __func__); - return; - } - - if (!pnors) pnors = MEM_callocN(sizeof(float) * 3 * numPolys, "poly_nors mesh.c"); - /* if (!fnors) fnors = MEM_callocN(sizeof(float) * 3 * numFaces, "face nors mesh.c"); */ /* NO NEED TO ALLOC YET */ - - - if (only_face_normals == FALSE) { - /* vertex normals are optional, they require some extra calculations, - * so make them optional */ - BKE_mesh_calc_normals_poly(mverts, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false); - } - else { - /* only calc poly normals */ - mp = mpolys; - for (i = 0; i < numPolys; i++, mp++) { - BKE_mesh_calc_poly_normal(mp, mloop + mp->loopstart, mverts, pnors[i]); - } - } - - if (origIndexFace && - /* fnors == faceNors_r */ /* NO NEED TO ALLOC YET */ - fnors != NULL && - numFaces) - { - mf = mfaces; - for (i = 0; i < numFaces; i++, mf++, origIndexFace++) { - if (*origIndexFace < numPolys) { - copy_v3_v3(fnors[i], pnors[*origIndexFace]); - } - else { - /* eek, we're not corresponding to polys */ - printf("error in %s: tessellation face indices are incorrect. normals may look bad.\n", __func__); - } - } - } - - if (pnors != polyNors_r) MEM_freeN(pnors); - /* if (fnors != faceNors_r) MEM_freeN(fnors); */ /* NO NEED TO ALLOC YET */ - - fnors = pnors = NULL; - -} - -static void mesh_calc_normals_poly_accum(MPoly *mp, MLoop *ml, - MVert *mvert, float polyno[3], float (*tnorms)[3]) -{ - const int nverts = mp->totloop; - float (*edgevecbuf)[3] = BLI_array_alloca(edgevecbuf, nverts); - int i; - - /* Polygon Normal and edge-vector */ - /* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */ - { - int i_prev = nverts - 1; - float const *v_prev = mvert[ml[i_prev].v].co; - float const *v_curr; - - zero_v3(polyno); - /* Newell's Method */ - for (i = 0; i < nverts; i++) { - v_curr = mvert[ml[i].v].co; - add_newell_cross_v3_v3v3(polyno, v_prev, v_curr); - - /* Unrelated to normalize, calcualte edge-vector */ - sub_v3_v3v3(edgevecbuf[i_prev], v_prev, v_curr); - normalize_v3(edgevecbuf[i_prev]); - i_prev = i; - - v_prev = v_curr; - } - if (UNLIKELY(normalize_v3(polyno) == 0.0f)) { - polyno[2] = 1.0f; /* other axis set to 0.0 */ - } - } - - /* accumulate angle weighted face normal */ - /* inline version of #accumulate_vertex_normals_poly */ - { - const float *prev_edge = edgevecbuf[nverts - 1]; - - for (i = 0; i < nverts; i++) { - const float *cur_edge = edgevecbuf[i]; - - /* calculate angle between the two poly edges incident on - * this vertex */ - const float fac = saacos(-dot_v3v3(cur_edge, prev_edge)); - - /* accumulate */ - madd_v3_v3fl(tnorms[ml[i].v], polyno, fac); - prev_edge = cur_edge; - } - } - -} - -void BKE_mesh_calc_normals_poly(MVert *mverts, int numVerts, MLoop *mloop, MPoly *mpolys, - int UNUSED(numLoops), int numPolys, float (*r_polynors)[3], - const bool only_face_normals) -{ - float (*pnors)[3] = r_polynors; - float (*tnorms)[3]; - int i; - MPoly *mp; - - if (only_face_normals) { - BLI_assert(pnors != NULL); - -#pragma omp parallel for if (numPolys > BM_OMP_LIMIT) - for (i = 0; i < numPolys; i++) { - BKE_mesh_calc_poly_normal(&mpolys[i], mloop + mpolys[i].loopstart, mverts, pnors[i]); - } - return; - } - - /* first go through and calculate normals for all the polys */ - tnorms = MEM_callocN(sizeof(*tnorms) * numVerts, __func__); - - if (pnors) { - mp = mpolys; - for (i = 0; i < numPolys; i++, mp++) { - mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, pnors[i], tnorms); - } - } - else { - float tpnor[3]; /* temp poly normal */ - mp = mpolys; - for (i = 0; i < numPolys; i++, mp++) { - mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, tpnor, tnorms); - } - } - - /* following Mesh convention; we use vertex coordinate itself for normal in this case */ - for (i = 0; i < numVerts; i++) { - MVert *mv = &mverts[i]; - float *no = tnorms[i]; - - if (UNLIKELY(normalize_v3(no) == 0.0f)) { - normalize_v3_v3(no, mv->co); - } - - normal_float_to_short_v3(mv->no, no); - } - - MEM_freeN(tnorms); -} - -void BKE_mesh_calc_normals(Mesh *mesh) -{ - BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, - mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, - NULL, false); -} - -void BKE_mesh_calc_normals_tessface(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float (*faceNors_r)[3]) -{ - float (*tnorms)[3] = MEM_callocN(numVerts * sizeof(*tnorms), "tnorms"); - float (*fnors)[3] = (faceNors_r) ? faceNors_r : MEM_callocN(sizeof(*fnors) * numFaces, "meshnormals"); - int i; - - for (i = 0; i < numFaces; i++) { - MFace *mf = &mfaces[i]; - float *f_no = fnors[i]; - float *n4 = (mf->v4) ? tnorms[mf->v4] : NULL; - float *c4 = (mf->v4) ? mverts[mf->v4].co : NULL; - - if (mf->v4) - normal_quad_v3(f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, mverts[mf->v4].co); - else - normal_tri_v3(f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co); - - accumulate_vertex_normals(tnorms[mf->v1], tnorms[mf->v2], tnorms[mf->v3], n4, - f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, c4); - } - - /* following Mesh convention; we use vertex coordinate itself for normal in this case */ - for (i = 0; i < numVerts; i++) { - MVert *mv = &mverts[i]; - float *no = tnorms[i]; - - if (UNLIKELY(normalize_v3(no) == 0.0f)) { - normalize_v3_v3(no, mv->co); - } - - normal_float_to_short_v3(mv->no, no); - } - - MEM_freeN(tnorms); - - if (fnors != faceNors_r) - MEM_freeN(fnors); -} - -static void bm_corners_to_loops_ex(ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata, - MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol) -{ - MTFace *texface; - MTexPoly *texpoly; - MCol *mcol; - MLoopCol *mloopcol; - MLoopUV *mloopuv; - MFace *mf; - int i; - - mf = mface + findex; - - for (i = 0; i < numTex; i++) { - texface = CustomData_get_n(fdata, CD_MTFACE, findex, i); - texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, findex, i); - - ME_MTEXFACE_CPY(texpoly, texface); - - mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i); - copy_v2_v2(mloopuv->uv, texface->uv[0]); mloopuv++; - copy_v2_v2(mloopuv->uv, texface->uv[1]); mloopuv++; - copy_v2_v2(mloopuv->uv, texface->uv[2]); mloopuv++; - - if (mf->v4) { - copy_v2_v2(mloopuv->uv, texface->uv[3]); mloopuv++; - } - } - - for (i = 0; i < numCol; i++) { - mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, loopstart, i); - mcol = CustomData_get_n(fdata, CD_MCOL, findex, i); - - MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[0]); mloopcol++; - MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[1]); mloopcol++; - MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[2]); mloopcol++; - if (mf->v4) { - MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[3]); mloopcol++; - } - } - - if (CustomData_has_layer(fdata, CD_MDISPS)) { - MDisps *ld = CustomData_get(ldata, loopstart, CD_MDISPS); - MDisps *fd = CustomData_get(fdata, findex, CD_MDISPS); - float (*disps)[3] = fd->disps; - int tot = mf->v4 ? 4 : 3; - int side, corners; - - if (CustomData_external_test(fdata, CD_MDISPS)) { - if (id && fdata->external) { - CustomData_external_add(ldata, id, CD_MDISPS, - totloop, fdata->external->filename); - } - } - - corners = multires_mdisp_corners(fd); - - if (corners == 0) { - /* Empty MDisp layers appear in at least one of the sintel.blend files. - * Not sure why this happens, but it seems fine to just ignore them here. - * If (corners == 0) for a non-empty layer though, something went wrong. */ - BLI_assert(fd->totdisp == 0); - } - else { - side = sqrt(fd->totdisp / corners); - - for (i = 0; i < tot; i++, disps += side * side, ld++) { - ld->totdisp = side * side; - ld->level = (int)(logf(side - 1.0f) / (float)M_LN2) + 1; - - if (ld->disps) - MEM_freeN(ld->disps); - - ld->disps = MEM_mallocN(sizeof(float) * 3 * side * side, "converted loop mdisps"); - if (fd->disps) { - memcpy(ld->disps, disps, sizeof(float) * 3 * side * side); - } - else { - memset(ld->disps, 0, sizeof(float) * 3 * side * side); - } - } - } - } -} - -void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh) -{ - BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id, &mesh->fdata, &mesh->ldata, &mesh->pdata, - mesh->totedge, mesh->totface, mesh->totloop, mesh->totpoly, - mesh->medge, mesh->mface, - &mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly); - - BKE_mesh_update_customdata_pointers(mesh, true); -} - -/* the same as BKE_mesh_convert_mfaces_to_mpolys but oriented to be used in do_versions from readfile.c - * the difference is how active/render/clone/stencil indices are handled here - * - * normally thay're being set from pdata which totally makes sense for meshes which are already - * converted to bmesh structures, but when loading older files indices shall be updated in other - * way around, so newly added pdata and ldata would have this indices set based on fdata layer - * - * this is normally only needed when reading older files, in all other cases BKE_mesh_convert_mfaces_to_mpolys - * shall be always used +/** + * Return a newly MEM_malloc'd array of all the mesh vertex locations + * \note \a numVerts_r may be NULL */ -void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh) -{ - BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id, &mesh->fdata, &mesh->ldata, &mesh->pdata, - mesh->totedge, mesh->totface, mesh->totloop, mesh->totpoly, - mesh->medge, mesh->mface, - &mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly); - - CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->pdata, &mesh->ldata); - - BKE_mesh_update_customdata_pointers(mesh, true); -} - -void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata, - int totedge_i, int totface_i, int totloop_i, int totpoly_i, - MEdge *medge, MFace *mface, - int *totloop_r, int *totpoly_r, - MLoop **mloop_r, MPoly **mpoly_r) -{ - MFace *mf; - MLoop *ml, *mloop; - MPoly *mp, *mpoly; - MEdge *me; - EdgeHash *eh; - int numTex, numCol; - int i, j, totloop, totpoly, *polyindex; - - /* just in case some of these layers are filled in (can happen with python created meshes) */ - CustomData_free(ldata, totloop_i); - CustomData_free(pdata, totpoly_i); - - totpoly = totface_i; - mpoly = MEM_callocN(sizeof(MPoly) * totpoly, "mpoly converted"); - CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, totpoly); - - numTex = CustomData_number_of_layers(fdata, CD_MTFACE); - numCol = CustomData_number_of_layers(fdata, CD_MCOL); - - totloop = 0; - mf = mface; - for (i = 0; i < totface_i; i++, mf++) { - totloop += mf->v4 ? 4 : 3; - } - - mloop = MEM_callocN(sizeof(MLoop) * totloop, "mloop converted"); - - CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop); - - CustomData_to_bmeshpoly(fdata, pdata, ldata, totloop, totpoly); - - if (id) { - /* ensure external data is transferred */ - CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i); - } - - eh = BLI_edgehash_new(); - - /* build edge hash */ - me = medge; - for (i = 0; i < totedge_i; i++, me++) { - BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i)); - - /* unrelated but avoid having the FGON flag enabled, so we can reuse it later for something else */ - me->flag &= ~ME_FGON; - } - - polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX); - - j = 0; /* current loop index */ - ml = mloop; - mf = mface; - mp = mpoly; - for (i = 0; i < totface_i; i++, mf++, mp++) { - mp->loopstart = j; - - mp->totloop = mf->v4 ? 4 : 3; - - mp->mat_nr = mf->mat_nr; - mp->flag = mf->flag; - -# define ML(v1, v2) { \ - ml->v = mf->v1; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); ml++; j++; \ - } (void)0 - - ML(v1, v2); - ML(v2, v3); - if (mf->v4) { - ML(v3, v4); - ML(v4, v1); - } - else { - ML(v3, v1); - } - -# undef ML - - bm_corners_to_loops_ex(id, fdata, ldata, pdata, mface, totloop, i, mp->loopstart, numTex, numCol); - - if (polyindex) { - *polyindex = i; - polyindex++; - } - } - - /* note, we don't convert NGons at all, these are not even real ngons, - * they have their own UV's, colors etc - its more an editing feature. */ - - BLI_edgehash_free(eh, NULL); - - *totpoly_r = totpoly; - *totloop_r = totloop; - *mpoly_r = mpoly; - *mloop_r = mloop; -} - float (*BKE_mesh_vertexCos_get(Mesh *me, int *r_numVerts))[3] { int i, numVerts = me->totvert; @@ -2365,1069 +1744,10 @@ float (*BKE_mesh_vertexCos_get(Mesh *me, int *r_numVerts))[3] return cos; } - -/* ngon version wip, based on EDBM_uv_vert_map_create */ -/* this replaces the non bmesh function (in trunk) which takes MTFace's, if we ever need it back we could - * but for now this replaces it because its unused. */ - -UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, - unsigned int totpoly, unsigned int totvert, int selected, float *limit) -{ - UvVertMap *vmap; - UvMapVert *buf; - MPoly *mp; - unsigned int a; - int i, totuv, nverts; - - totuv = 0; - - /* generate UvMapVert array */ - mp = mpoly; - for (a = 0; a < totpoly; a++, mp++) - if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) - totuv += mp->totloop; - - if (totuv == 0) - return NULL; - - vmap = (UvVertMap *)MEM_callocN(sizeof(*vmap), "UvVertMap"); - if (!vmap) - return NULL; - - vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totvert, "UvMapVert*"); - buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * totuv, "UvMapVert"); - - if (!vmap->vert || !vmap->buf) { - BKE_mesh_uv_vert_map_free(vmap); - return NULL; - } - - mp = mpoly; - for (a = 0; a < totpoly; a++, mp++) { - if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) { - nverts = mp->totloop; - - for (i = 0; i < nverts; i++) { - buf->tfindex = i; - buf->f = a; - buf->separate = 0; - buf->next = vmap->vert[mloop[mp->loopstart + i].v]; - vmap->vert[mloop[mp->loopstart + i].v] = buf; - buf++; - } - } - } - - /* sort individual uvs for each vert */ - for (a = 0; a < totvert; a++) { - UvMapVert *newvlist = NULL, *vlist = vmap->vert[a]; - UvMapVert *iterv, *v, *lastv, *next; - float *uv, *uv2, uvdiff[2]; - - while (vlist) { - v = vlist; - vlist = vlist->next; - v->next = newvlist; - newvlist = v; - - uv = mloopuv[mpoly[v->f].loopstart + v->tfindex].uv; - lastv = NULL; - iterv = vlist; - - while (iterv) { - next = iterv->next; - - uv2 = mloopuv[mpoly[iterv->f].loopstart + iterv->tfindex].uv; - sub_v2_v2v2(uvdiff, uv2, uv); - - - if (fabsf(uv[0] - uv2[0]) < limit[0] && fabsf(uv[1] - uv2[1]) < limit[1]) { - if (lastv) lastv->next = next; - else vlist = next; - iterv->next = newvlist; - newvlist = iterv; - } - else - lastv = iterv; - - iterv = next; - } - - newvlist->separate = 1; - } - - vmap->vert[a] = newvlist; - } - - return vmap; -} - -UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v) -{ - return vmap->vert[v]; -} - -void BKE_mesh_uv_vert_map_free(UvVertMap *vmap) -{ - if (vmap) { - if (vmap->vert) MEM_freeN(vmap->vert); - if (vmap->buf) MEM_freeN(vmap->buf); - MEM_freeN(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) -{ - MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * totvert, "vert poly map"); - int *indices, *index_iter; - int i, j; - - indices = index_iter = MEM_mallocN(sizeof(int) * totloop, "vert poly map mem"); - - /* Count number of polys for each vertex */ - for (i = 0; i < totpoly; i++) { - const MPoly *p = &mpoly[i]; - - for (j = 0; j < p->totloop; j++) - map[mloop[p->loopstart + j].v].count++; - } - - /* Assign indices mem */ - for (i = 0; i < totvert; i++) { - map[i].indices = index_iter; - index_iter += map[i].count; - - /* Reset 'count' for use as index in last loop */ - map[i].count = 0; - } - - /* Find the users */ - for (i = 0; i < totpoly; i++) { - const MPoly *p = &mpoly[i]; - - for (j = 0; j < p->totloop; j++) { - int v = mloop[p->loopstart + j].v; - - map[v].indices[map[v].count] = i; - map[v].count++; - } - } - - *r_map = map; - *r_mem = indices; -} - -/* 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. */ -void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem, - const MEdge *medge, int totvert, int totedge) -{ - MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * totvert, "vert-edge map"); - int *indices = MEM_mallocN(sizeof(int) * totedge * 2, "vert-edge map mem"); - int *i_pt = indices; - - int i; - - /* Count number of edges for each vertex */ - for (i = 0; i < totedge; i++) { - map[medge[i].v1].count++; - map[medge[i].v2].count++; - } - - /* Assign indices mem */ - for (i = 0; i < totvert; i++) { - map[i].indices = i_pt; - i_pt += map[i].count; - - /* Reset 'count' for use as index in last loop */ - map[i].count = 0; - } - - /* Find the users */ - for (i = 0; i < totedge; i++) { - const int v[2] = {medge[i].v1, medge[i].v2}; - - map[v[0]].indices[map[v[0]].count] = i; - map[v[1]].indices[map[v[1]].count] = i; - - map[v[0]].count++; - map[v[1]].count++; - } - - *r_map = map; - *r_mem = indices; -} - -void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map, int **r_mem, - const MEdge *UNUSED(medge), const int totedge, - const MPoly *mpoly, const int totpoly, - const MLoop *mloop, const int totloop) -{ - MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * totedge, "edge-poly map"); - int *indices = MEM_mallocN(sizeof(int) * totloop, "edge-poly map mem"); - int *index_step; - const MPoly *mp; - int i; - - /* count face users */ - for (i = 0, mp = mpoly; i < totpoly; mp++, i++) { - const MLoop *ml; - int j = mp->totloop; - for (ml = &mloop[mp->loopstart]; j--; ml++) { - map[ml->e].count++; - } - } - - /* create offsets */ - index_step = indices; - for (i = 0; i < totedge; i++) { - map[i].indices = index_step; - index_step += map[i].count; - - /* re-count, using this as an index below */ - map[i].count = 0; - - } - - /* assign poly-edge users */ - for (i = 0, mp = mpoly; i < totpoly; mp++, i++) { - const MLoop *ml; - int j = mp->totloop; - for (ml = &mloop[mp->loopstart]; j--; ml++) { - MeshElemMap *map_ele = &map[ml->e]; - map_ele->indices[map_ele->count++] = i; - } - } - - *r_map = map; - *r_mem = indices; -} - -void BKE_mesh_loops_to_mface_corners(CustomData *fdata, CustomData *ldata, - CustomData *pdata, int lindex[4], int findex, - const int polyindex, - const int mf_len, /* 3 or 4 */ - - /* cache values to avoid lookups every time */ - const int numTex, /* CustomData_number_of_layers(pdata, CD_MTEXPOLY) */ - const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */ - const int hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */ - const int hasOrigSpace /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */ - ) -{ - MTFace *texface; - MTexPoly *texpoly; - MCol *mcol; - MLoopCol *mloopcol; - MLoopUV *mloopuv; - int i, j; - - for (i = 0; i < numTex; i++) { - texface = CustomData_get_n(fdata, CD_MTFACE, findex, i); - texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i); - - ME_MTEXFACE_CPY(texface, texpoly); - - for (j = 0; j < mf_len; j++) { - mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, lindex[j], i); - copy_v2_v2(texface->uv[j], mloopuv->uv); - } - } - - for (i = 0; i < numCol; i++) { - mcol = CustomData_get_n(fdata, CD_MCOL, findex, i); - - for (j = 0; j < mf_len; j++) { - mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, lindex[j], i); - MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]); - } - } - - if (hasPCol) { - mcol = CustomData_get(fdata, findex, CD_PREVIEW_MCOL); - - for (j = 0; j < mf_len; j++) { - mloopcol = CustomData_get(ldata, lindex[j], CD_PREVIEW_MLOOPCOL); - MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]); - } - } - - if (hasOrigSpace) { - OrigSpaceFace *of = CustomData_get(fdata, findex, CD_ORIGSPACE); - OrigSpaceLoop *lof; - - for (j = 0; j < mf_len; j++) { - lof = CustomData_get(ldata, lindex[j], CD_ORIGSPACE_MLOOP); - copy_v2_v2(of->uv[j], lof->uv); - } - } -} - -/* - * this function recreates a tessellation. - * returns number of tessellation faces. - */ -int BKE_mesh_recalc_tessellation(CustomData *fdata, - CustomData *ldata, CustomData *pdata, - MVert *mvert, int totface, int totloop, - int totpoly, - /* when tessellating to recalculate normals after - * we can skip copying here */ - const bool do_face_nor_cpy) -{ - /* use this to avoid locking pthread for _every_ polygon - * and calling the fill function */ - -#define USE_TESSFACE_SPEEDUP -#define USE_TESSFACE_QUADS // NEEDS FURTHER TESTING - -#define TESSFACE_SCANFILL (1 << 0) -#define TESSFACE_IS_QUAD (1 << 1) - - const int looptris_tot = poly_to_tri_count(totpoly, totloop); - - MPoly *mp, *mpoly; - MLoop *ml, *mloop; - MFace *mface, *mf; - ScanFillContext sf_ctx; - ScanFillVert *sf_vert, *sf_vert_last, *sf_vert_first; - ScanFillFace *sf_tri; - int *mface_to_poly_map; - int lindex[4]; /* only ever use 3 in this case */ - int poly_index, j, mface_index; - - const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY); - const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL); - const int hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL); - const int hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP); - - mpoly = CustomData_get_layer(pdata, CD_MPOLY); - mloop = CustomData_get_layer(ldata, CD_MLOOP); - - /* allocate the length of totfaces, avoid many small reallocs, - * if all faces are tri's it will be correct, quads == 2x allocs */ - /* take care. we are _not_ calloc'ing so be sure to initialize each field */ - mface_to_poly_map = MEM_mallocN(sizeof(*mface_to_poly_map) * looptris_tot, __func__); - mface = MEM_mallocN(sizeof(*mface) * looptris_tot, __func__); - - mface_index = 0; - mp = mpoly; - for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) { - if (mp->totloop < 3) { - /* do nothing */ - } - -#ifdef USE_TESSFACE_SPEEDUP - -#define ML_TO_MF(i1, i2, i3) \ - mface_to_poly_map[mface_index] = poly_index; \ - mf = &mface[mface_index]; \ - /* set loop indices, transformed to vert indices later */ \ - mf->v1 = mp->loopstart + i1; \ - mf->v2 = mp->loopstart + i2; \ - mf->v3 = mp->loopstart + i3; \ - mf->v4 = 0; \ - mf->mat_nr = mp->mat_nr; \ - mf->flag = mp->flag; \ - mf->edcode = 0; \ - (void)0 - -/* ALMOST IDENTICAL TO DEFINE ABOVE (see EXCEPTION) */ -#define ML_TO_MF_QUAD() \ - mface_to_poly_map[mface_index] = poly_index; \ - mf = &mface[mface_index]; \ - /* set loop indices, transformed to vert indices later */ \ - mf->v1 = mp->loopstart + 0; /* EXCEPTION */ \ - mf->v2 = mp->loopstart + 1; /* EXCEPTION */ \ - mf->v3 = mp->loopstart + 2; /* EXCEPTION */ \ - mf->v4 = mp->loopstart + 3; /* EXCEPTION */ \ - mf->mat_nr = mp->mat_nr; \ - mf->flag = mp->flag; \ - mf->edcode = TESSFACE_IS_QUAD; /* EXCEPTION */ \ - (void)0 - - - else if (mp->totloop == 3) { - ML_TO_MF(0, 1, 2); - mface_index++; - } - else if (mp->totloop == 4) { -#ifdef USE_TESSFACE_QUADS - ML_TO_MF_QUAD(); - mface_index++; -#else - ML_TO_MF(0, 1, 2); - mface_index++; - ML_TO_MF(0, 2, 3); - mface_index++; -#endif - } -#endif /* USE_TESSFACE_SPEEDUP */ - else { -#define USE_TESSFACE_CALCNORMAL - - int totfilltri; - -#ifdef USE_TESSFACE_CALCNORMAL - float normal[3]; - zero_v3(normal); -#endif - ml = mloop + mp->loopstart; - - BLI_scanfill_begin(&sf_ctx); - sf_vert_first = NULL; - sf_vert_last = NULL; - for (j = 0; j < mp->totloop; j++, ml++) { - sf_vert = BLI_scanfill_vert_add(&sf_ctx, mvert[ml->v].co); - - sf_vert->keyindex = mp->loopstart + j; - - if (sf_vert_last) { - BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert); -#ifdef USE_TESSFACE_CALCNORMAL - add_newell_cross_v3_v3v3(normal, sf_vert_last->co, sf_vert->co); -#endif - } - - if (!sf_vert_first) - sf_vert_first = sf_vert; - sf_vert_last = sf_vert; - } - BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert_first); -#ifdef USE_TESSFACE_CALCNORMAL - add_newell_cross_v3_v3v3(normal, sf_vert_last->co, sf_vert_first->co); - if (UNLIKELY(normalize_v3(normal) == 0.0f)) { - normal[2] = 1.0f; - } - totfilltri = BLI_scanfill_calc_ex(&sf_ctx, 0, normal); -#else - totfilltri = BLI_scanfill_calc(&sf_ctx, 0); -#endif - BLI_assert(totfilltri <= mp->totloop - 2); - (void)totfilltri; - - for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next, mf++) { - mface_to_poly_map[mface_index] = poly_index; - mf = &mface[mface_index]; - - /* set loop indices, transformed to vert indices later */ - mf->v1 = sf_tri->v1->keyindex; - mf->v2 = sf_tri->v2->keyindex; - mf->v3 = sf_tri->v3->keyindex; - mf->v4 = 0; - - mf->mat_nr = mp->mat_nr; - mf->flag = mp->flag; - -#ifdef USE_TESSFACE_SPEEDUP - mf->edcode = TESSFACE_SCANFILL; /* tag for sorting loop indices */ -#endif - - mface_index++; - } - - BLI_scanfill_end(&sf_ctx); - -#undef USE_TESSFACE_CALCNORMAL - } - } - - CustomData_free(fdata, totface); - totface = mface_index; - - BLI_assert(totface <= looptris_tot); - - /* not essential but without this we store over-alloc'd memory in the CustomData layers */ - if (LIKELY(looptris_tot != totface)) { - mface = MEM_reallocN(mface, sizeof(*mface) * totface); - mface_to_poly_map = MEM_reallocN(mface_to_poly_map, sizeof(*mface_to_poly_map) * totface); - } - - CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface); - - /* CD_ORIGINDEX will contain an array of indices from tessfaces to the polygons - * they are directly tessellated from */ - CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface); - CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); - - if (do_face_nor_cpy) { - /* If polys have a normals layer, copying that to faces can help - * avoid the need to recalculate normals later */ - if (CustomData_has_layer(pdata, CD_NORMAL)) { - float (*pnors)[3] = CustomData_get_layer(pdata, CD_NORMAL); - float (*fnors)[3] = CustomData_add_layer(fdata, CD_NORMAL, CD_CALLOC, NULL, totface); - for (mface_index = 0; mface_index < totface; mface_index++) { - copy_v3_v3(fnors[mface_index], pnors[mface_to_poly_map[mface_index]]); - } - } - } - - mf = mface; - for (mface_index = 0; mface_index < totface; mface_index++, mf++) { - -#ifdef USE_TESSFACE_QUADS - const int mf_len = mf->edcode & TESSFACE_IS_QUAD ? 4 : 3; -#endif - -#ifdef USE_TESSFACE_SPEEDUP - /* skip sorting when not using ngons */ - if (UNLIKELY(mf->edcode & TESSFACE_SCANFILL)) -#endif - { - /* sort loop indices to ensure winding is correct */ - if (mf->v1 > mf->v2) SWAP(unsigned int, mf->v1, mf->v2); - if (mf->v2 > mf->v3) SWAP(unsigned int, mf->v2, mf->v3); - if (mf->v1 > mf->v2) SWAP(unsigned int, mf->v1, mf->v2); - - if (mf->v1 > mf->v2) SWAP(unsigned int, mf->v1, mf->v2); - if (mf->v2 > mf->v3) SWAP(unsigned int, mf->v2, mf->v3); - if (mf->v1 > mf->v2) SWAP(unsigned int, mf->v1, mf->v2); - } - - /* end abusing the edcode */ -#if defined(USE_TESSFACE_QUADS) || defined(USE_TESSFACE_SPEEDUP) - mf->edcode = 0; -#endif - - - lindex[0] = mf->v1; - lindex[1] = mf->v2; - lindex[2] = mf->v3; -#ifdef USE_TESSFACE_QUADS - if (mf_len == 4) lindex[3] = mf->v4; -#endif - - /*transform loop indices to vert indices*/ - mf->v1 = mloop[mf->v1].v; - mf->v2 = mloop[mf->v2].v; - mf->v3 = mloop[mf->v3].v; -#ifdef USE_TESSFACE_QUADS - if (mf_len == 4) mf->v4 = mloop[mf->v4].v; -#endif - - BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata, - lindex, mface_index, mface_to_poly_map[mface_index], -#ifdef USE_TESSFACE_QUADS - mf_len, -#else - 3, -#endif - numTex, numCol, hasPCol, hasOrigSpace); - - -#ifdef USE_TESSFACE_QUADS - test_index_face(mf, fdata, mface_index, mf_len); -#endif - - } - - return totface; - -#undef USE_TESSFACE_SPEEDUP - -} - - -#ifdef USE_BMESH_SAVE_AS_COMPAT - -/* - * this function recreates a tessellation. - * returns number of tessellation faces. - */ -int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata, - struct CustomData *pdata, int totface, int UNUSED(totloop), int totpoly) -{ - MLoop *mloop; - - int lindex[4]; - int i; - int k; - - MPoly *mp, *mpoly; - MFace *mface = NULL, *mf; - BLI_array_declare(mface); - - const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY); - const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL); - const int hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL); - const int hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP); - - mpoly = CustomData_get_layer(pdata, CD_MPOLY); - mloop = CustomData_get_layer(ldata, CD_MLOOP); - - mp = mpoly; - k = 0; - for (i = 0; i < totpoly; i++, mp++) { - if (ELEM(mp->totloop, 3, 4)) { - BLI_array_grow_one(mface); - mf = &mface[k]; - - mf->mat_nr = mp->mat_nr; - mf->flag = mp->flag; - - mf->v1 = mp->loopstart + 0; - mf->v2 = mp->loopstart + 1; - mf->v3 = mp->loopstart + 2; - mf->v4 = (mp->totloop == 4) ? (mp->loopstart + 3) : 0; - - /* abuse edcode for temp storage and clear next loop */ - mf->edcode = (char)mp->totloop; /* only ever 3 or 4 */ - - k++; - } - } - - CustomData_free(fdata, totface); - - totface = k; - - CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface); - - CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); - - mp = mpoly; - k = 0; - for (i = 0; i < totpoly; i++, mp++) { - if (ELEM(mp->totloop, 3, 4)) { - mf = &mface[k]; - - if (mf->edcode == 3) { - /* sort loop indices to ensure winding is correct */ - /* NO SORT - looks like we can skip this */ - - lindex[0] = mf->v1; - lindex[1] = mf->v2; - lindex[2] = mf->v3; - lindex[3] = 0; /* unused */ - - /* transform loop indices to vert indices */ - mf->v1 = mloop[mf->v1].v; - mf->v2 = mloop[mf->v2].v; - mf->v3 = mloop[mf->v3].v; - - BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata, - lindex, k, i, 3, - numTex, numCol, hasPCol, hasOrigSpace); - test_index_face(mf, fdata, k, 3); - } - else { - /* sort loop indices to ensure winding is correct */ - /* NO SORT - looks like we can skip this */ - - lindex[0] = mf->v1; - lindex[1] = mf->v2; - lindex[2] = mf->v3; - lindex[3] = mf->v4; - - /* transform loop indices to vert indices */ - mf->v1 = mloop[mf->v1].v; - mf->v2 = mloop[mf->v2].v; - mf->v3 = mloop[mf->v3].v; - mf->v4 = mloop[mf->v4].v; - - BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata, - lindex, k, i, 4, - numTex, numCol, hasPCol, hasOrigSpace); - test_index_face(mf, fdata, k, 4); - } - - mf->edcode = 0; - - k++; - } - } - - return k; -} -#endif /* USE_BMESH_SAVE_AS_COMPAT */ - -/* - * COMPUTE POLY NORMAL - * - * Computes the normal of a planar - * polygon See Graphics Gems for - * computing newell normal. - * - */ -static void mesh_calc_ngon_normal(MPoly *mpoly, MLoop *loopstart, - MVert *mvert, float normal[3]) -{ - const int nverts = mpoly->totloop; - float const *v_prev = mvert[loopstart[nverts - 1].v].co; - float const *v_curr; - int i; - - zero_v3(normal); - - /* Newell's Method */ - for (i = 0; i < nverts; i++) { - v_curr = mvert[loopstart[i].v].co; - add_newell_cross_v3_v3v3(normal, v_prev, v_curr); - v_prev = v_curr; - } - - if (UNLIKELY(normalize_v3(normal) == 0.0f)) { - normal[2] = 1.0f; /* other axis set to 0.0 */ - } -} - -void BKE_mesh_calc_poly_normal(MPoly *mpoly, MLoop *loopstart, - MVert *mvarray, float no[3]) -{ - if (mpoly->totloop > 4) { - mesh_calc_ngon_normal(mpoly, loopstart, mvarray, no); - } - else if (mpoly->totloop == 3) { - normal_tri_v3(no, - mvarray[loopstart[0].v].co, - mvarray[loopstart[1].v].co, - mvarray[loopstart[2].v].co - ); - } - else if (mpoly->totloop == 4) { - normal_quad_v3(no, - mvarray[loopstart[0].v].co, - mvarray[loopstart[1].v].co, - mvarray[loopstart[2].v].co, - mvarray[loopstart[3].v].co - ); - } - else { /* horrible, two sided face! */ - no[0] = 0.0; - no[1] = 0.0; - no[2] = 1.0; - } -} -/* duplicate of function above _but_ takes coords rather then mverts */ -static void mesh_calc_ngon_normal_coords(MPoly *mpoly, MLoop *loopstart, - const float (*vertex_coords)[3], float normal[3]) -{ - const int nverts = mpoly->totloop; - float const *v_prev = vertex_coords[loopstart[nverts - 1].v]; - float const *v_curr; - int i; - - zero_v3(normal); - - /* Newell's Method */ - for (i = 0; i < nverts; i++) { - v_curr = vertex_coords[loopstart[i].v]; - add_newell_cross_v3_v3v3(normal, v_prev, v_curr); - v_prev = v_curr; - } - - if (UNLIKELY(normalize_v3(normal) == 0.0f)) { - normal[2] = 1.0f; /* other axis set to 0.0 */ - } -} - -void BKE_mesh_calc_poly_normal_coords(MPoly *mpoly, MLoop *loopstart, - const float (*vertex_coords)[3], float no[3]) -{ - if (mpoly->totloop > 4) { - mesh_calc_ngon_normal_coords(mpoly, loopstart, vertex_coords, no); - } - else if (mpoly->totloop == 3) { - normal_tri_v3(no, - vertex_coords[loopstart[0].v], - vertex_coords[loopstart[1].v], - vertex_coords[loopstart[2].v] - ); - } - else if (mpoly->totloop == 4) { - normal_quad_v3(no, - vertex_coords[loopstart[0].v], - vertex_coords[loopstart[1].v], - vertex_coords[loopstart[2].v], - vertex_coords[loopstart[3].v] - ); - } - else { /* horrible, two sided face! */ - no[0] = 0.0; - no[1] = 0.0; - no[2] = 1.0; - } -} - -static void mesh_calc_ngon_center(MPoly *mpoly, MLoop *loopstart, - MVert *mvert, float cent[3]) -{ - const float w = 1.0f / (float)mpoly->totloop; - int i; - - zero_v3(cent); - - for (i = 0; i < mpoly->totloop; i++) { - madd_v3_v3fl(cent, mvert[(loopstart++)->v].co, w); - } -} - -void BKE_mesh_calc_poly_center(MPoly *mpoly, MLoop *loopstart, - MVert *mvarray, float cent[3]) -{ - if (mpoly->totloop == 3) { - cent_tri_v3(cent, - mvarray[loopstart[0].v].co, - mvarray[loopstart[1].v].co, - mvarray[loopstart[2].v].co - ); - } - else if (mpoly->totloop == 4) { - cent_quad_v3(cent, - mvarray[loopstart[0].v].co, - mvarray[loopstart[1].v].co, - mvarray[loopstart[2].v].co, - mvarray[loopstart[3].v].co - ); - } - else { - mesh_calc_ngon_center(mpoly, loopstart, mvarray, cent); - } -} - -/* note, passing polynormal is only a speedup so we can skip calculating it */ -float BKE_mesh_calc_poly_area(MPoly *mpoly, MLoop *loopstart, - MVert *mvarray, const float polynormal[3]) -{ - if (mpoly->totloop == 3) { - return area_tri_v3(mvarray[loopstart[0].v].co, - mvarray[loopstart[1].v].co, - 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; - float area, polynorm_local[3]; - float (*vertexcos)[3] = BLI_array_alloca(vertexcos, mpoly->totloop); - const float *no = polynormal ? polynormal : polynorm_local; - - /* pack vertex cos into an array for area_poly_v3 */ - for (i = 0; i < mpoly->totloop; i++, l_iter++) { - copy_v3_v3(vertexcos[i], mvarray[l_iter->v].co); - } - - /* need normal for area_poly_v3 as well */ - if (polynormal == NULL) { - BKE_mesh_calc_poly_normal(mpoly, loopstart, mvarray, polynorm_local); - } - - /* finally calculate the area */ - area = area_poly_v3(mpoly->totloop, vertexcos, no); - - return area; - } -} - -/* note, results won't be correct if polygon is non-planar */ -static float mesh_calc_poly_planar_area_centroid(MPoly *mpoly, MLoop *loopstart, MVert *mvarray, float cent[3]) -{ - int i; - float tri_area; - float total_area = 0.0f; - float v1[3], v2[3], v3[3], normal[3], tri_cent[3]; - - BKE_mesh_calc_poly_normal(mpoly, loopstart, mvarray, normal); - copy_v3_v3(v1, mvarray[loopstart[0].v].co); - copy_v3_v3(v2, mvarray[loopstart[1].v].co); - zero_v3(cent); - - for (i = 2; i < mpoly->totloop; i++) { - copy_v3_v3(v3, mvarray[loopstart[i].v].co); - - tri_area = area_tri_signed_v3(v1, v2, v3, normal); - total_area += tri_area; - - cent_tri_v3(tri_cent, v1, v2, v3); - madd_v3_v3fl(cent, tri_cent, tri_area); - - copy_v3_v3(v2, v3); - } - - mul_v3_fl(cent, 1.0f / total_area); - - return total_area; -} - /** - * 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 (starting at 1) + * Find the index of the loop in 'poly' which references vertex, + * returns -1 if not found */ -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) -{ - int *poly_groups; - int *poly_stack; - STACK_DECLARE(poly_stack); - - int poly_prev = 0; - int poly_group_id = 0; - - /* map vars */ - MeshElemMap *edge_poly_map; - int *edge_poly_mem; - - if (totpoly == 0) { - *r_totgroup = 0; - return NULL; - } - - BKE_mesh_edge_poly_map_create(&edge_poly_map, &edge_poly_mem, - medge, totedge, - mpoly, totpoly, - mloop, totloop); - - poly_groups = MEM_callocN(sizeof(int) * totpoly, __func__); - poly_stack = MEM_mallocN(sizeof(int) * totpoly, __func__); - - STACK_INIT(poly_stack); - - while (true) { - int poly; - - for (poly = poly_prev; poly < totpoly; poly++) { - if (poly_groups[poly] == 0) { - break; - } - } - - if (poly == totpoly) { - /* all done */ - break; - } - - /* start searching from here next time */ - poly_prev = poly + 1; - - /* group starts at 1 */ - poly_group_id++; - - poly_groups[poly] = poly_group_id; - STACK_PUSH(poly_stack, poly); - - while ((poly = STACK_POP_ELSE(poly_stack, -1)) != -1) { - - const MPoly *mp = &mpoly[poly]; - const MLoop *ml; - int j = mp->totloop; - - BLI_assert(poly_groups[poly] == poly_group_id); - - for (ml = &mloop[mp->loopstart]; j--; ml++) { - if (!(medge[ml->e].flag & ME_SHARP)) { - /* loop over poly users */ - const MeshElemMap *map_ele = &edge_poly_map[ml->e]; - int *p = map_ele->indices; - int i = map_ele->count; - - for (; i--; p++) { - /* if we meet other non initialized its a bug */ - BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id)); - - if (poly_groups[*p] == 0) { - poly_groups[*p] = poly_group_id; - STACK_PUSH(poly_stack, *p); - } - } - } - } - } - } - - MEM_freeN(edge_poly_map); - MEM_freeN(edge_poly_mem); - MEM_freeN(poly_stack); - - STACK_FREE(poly_stack); - - *r_totgroup = poly_group_id; - - return poly_groups; -} - - - -/** - * This function takes the difference between 2 vertex-coord-arrays - * (\a vert_cos_src, \a vert_cos_dst), - * and applies the difference to \a vert_cos_new relative to \a vert_cos_org. - * - * \param vert_cos_src reference deform source. - * \param vert_cos_dst reference deform destination. - * - * \param vert_cos_org reference for the output location. - * \param vert_cos_new resulting coords. - */ -void BKE_mesh_calc_relative_deform( - const MPoly *mpoly, const int totpoly, - const MLoop *mloop, const int totvert, - - const float (*vert_cos_src)[3], - const float (*vert_cos_dst)[3], - - const float (*vert_cos_org)[3], - float (*vert_cos_new)[3]) -{ - const MPoly *mp; - int i; - - int *vert_accum = MEM_callocN(sizeof(*vert_accum) * totvert, __func__); - - memset(vert_cos_new, '\0', sizeof(*vert_cos_new) * totvert); - - for (i = 0, mp = mpoly; i < totpoly; i++, mp++) { - const MLoop *loopstart = mloop + mp->loopstart; - int j; - - for (j = 0; j < mp->totloop; j++) { - int v_prev = (loopstart + ((mp->totloop + (j - 1)) % mp->totloop))->v; - int v_curr = (loopstart + j)->v; - int v_next = (loopstart + ((j + 1) % mp->totloop))->v; - - float tvec[3]; - - barycentric_transform( - tvec, vert_cos_dst[v_curr], - vert_cos_org[v_prev], vert_cos_org[v_curr], vert_cos_org[v_next], - vert_cos_src[v_prev], vert_cos_src[v_curr], vert_cos_src[v_next] - ); - - add_v3_v3(vert_cos_new[v_curr], tvec); - vert_accum[v_curr] += 1; - } - } - - for (i = 0; i < totvert; i++) { - if (vert_accum[i]) { - mul_v3_fl(vert_cos_new[i], 1.0f / (float)vert_accum[i]); - } - else { - copy_v3_v3(vert_cos_new[i], vert_cos_org[i]); - } - } - - MEM_freeN(vert_accum); -} - -/* Find the index of the loop in 'poly' which references vertex, - * returns -1 if not found */ int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, unsigned vert) { @@ -3440,9 +1760,11 @@ int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, return -1; } -/* Fill 'adj_r' with the loop indices in 'poly' adjacent to the +/** + * Fill \a adj_r with the loop indices in \a poly adjacent to the * vertex. Returns the index of the loop matching vertex, or -1 if the - * vertex is not in 'poly' */ + * vertex is not in \a poly + */ int poly_get_adj_loops_from_vert(unsigned adj_r[3], const MPoly *poly, const MLoop *mloop, unsigned vert) { @@ -3462,8 +1784,10 @@ int poly_get_adj_loops_from_vert(unsigned adj_r[3], const MPoly *poly, return corner; } -/* Return the index of the edge vert that is not equal to 'v'. If - * neither edge vertex is equal to 'v', returns -1. */ +/** + * Return the index of the edge vert that is not equal to \a v. If + * neither edge vertex is equal to \a v, returns -1. + */ int BKE_mesh_edge_other_vert(const MEdge *e, int v) { if (e->v1 == v) @@ -3474,186 +1798,8 @@ int BKE_mesh_edge_other_vert(const MEdge *e, int v) return -1; } -/* update the hide flag for edges and faces from the corresponding - * flag in verts */ -void BKE_mesh_flush_hidden_from_verts_ex(const MVert *mvert, - const MLoop *mloop, - MEdge *medge, const int totedge, - MPoly *mpoly, const int totpoly) -{ - int i, j; - - for (i = 0; i < totedge; i++) { - MEdge *e = &medge[i]; - if (mvert[e->v1].flag & ME_HIDE || - mvert[e->v2].flag & ME_HIDE) - { - e->flag |= ME_HIDE; - } - else { - e->flag &= ~ME_HIDE; - } - } - for (i = 0; i < totpoly; i++) { - MPoly *p = &mpoly[i]; - p->flag &= ~ME_HIDE; - for (j = 0; j < p->totloop; j++) { - if (mvert[mloop[p->loopstart + j].v].flag & ME_HIDE) - p->flag |= ME_HIDE; - } - } -} -void BKE_mesh_flush_hidden_from_verts(Mesh *me) -{ - BKE_mesh_flush_hidden_from_verts_ex(me->mvert, me->mloop, - me->medge, me->totedge, - me->mpoly, me->totpoly); -} - -void BKE_mesh_flush_hidden_from_polys_ex(MVert *mvert, - const MLoop *mloop, - MEdge *medge, const int UNUSED(totedge), - const MPoly *mpoly, const int totpoly) -{ - const MPoly *mp; - int i; - - i = totpoly; - for (mp = mpoly; i--; mp++) { - if (mp->flag & ME_HIDE) { - const MLoop *ml; - int j; - j = mp->totloop; - for (ml = &mloop[mp->loopstart]; j--; ml++) { - mvert[ml->v].flag |= ME_HIDE; - medge[ml->e].flag |= ME_HIDE; - } - } - } - - i = totpoly; - for (mp = mpoly; i--; mp++) { - if ((mp->flag & ME_HIDE) == 0) { - const MLoop *ml; - int j; - j = mp->totloop; - for (ml = &mloop[mp->loopstart]; j--; ml++) { - mvert[ml->v].flag &= ~ME_HIDE; - medge[ml->e].flag &= ~ME_HIDE; - } - } - } -} -void BKE_mesh_flush_hidden_from_polys(Mesh *me) -{ - BKE_mesh_flush_hidden_from_polys_ex(me->mvert, me->mloop, - me->medge, me->totedge, - me->mpoly, me->totpoly); -} - -/** - * simple poly -> vert/edge selection. - */ -void BKE_mesh_flush_select_from_polys_ex(MVert *mvert, const int totvert, - const MLoop *mloop, - MEdge *medge, const int totedge, - const MPoly *mpoly, const int totpoly) -{ - MVert *mv; - MEdge *med; - const MPoly *mp; - int i; - - i = totvert; - for (mv = mvert; i--; mv++) { - mv->flag &= ~SELECT; - } - - i = totedge; - for (med = medge; i--; med++) { - med->flag &= ~SELECT; - } - - i = totpoly; - for (mp = mpoly; i--; mp++) { - /* assume if its selected its not hidden and none of its verts/edges are hidden - * (a common assumption)*/ - if (mp->flag & ME_FACE_SEL) { - const MLoop *ml; - int j; - j = mp->totloop; - for (ml = &mloop[mp->loopstart]; j--; ml++) { - mvert[ml->v].flag |= SELECT; - medge[ml->e].flag |= SELECT; - } - } - } -} -void BKE_mesh_flush_select_from_polys(Mesh *me) -{ - BKE_mesh_flush_select_from_polys_ex(me->mvert, me->totvert, - me->mloop, - me->medge, me->totedge, - me->mpoly, me->totpoly); -} - -void BKE_mesh_flush_select_from_verts_ex(const MVert *mvert, const int UNUSED(totvert), - const MLoop *mloop, - MEdge *medge, const int totedge, - MPoly *mpoly, const int totpoly) -{ - MEdge *med; - MPoly *mp; - int i; - - /* edges */ - i = totedge; - for (med = medge; i--; med++) { - if ((med->flag & ME_HIDE) == 0) { - if ((mvert[med->v1].flag & SELECT) && (mvert[med->v2].flag & SELECT)) { - med->flag |= SELECT; - } - else { - med->flag &= ~SELECT; - } - } - } - - /* polys */ - i = totpoly; - for (mp = mpoly; i--; mp++) { - if ((mp->flag & ME_HIDE) == 0) { - int ok = TRUE; - const MLoop *ml; - int j; - j = mp->totloop; - for (ml = &mloop[mp->loopstart]; j--; ml++) { - if ((mvert[ml->v].flag & SELECT) == 0) { - ok = FALSE; - break; - } - } - - if (ok) { - mp->flag |= ME_FACE_SEL; - } - else { - mp->flag &= ~ME_FACE_SEL; - } - } - } -} -void BKE_mesh_flush_select_from_verts(Mesh *me) -{ - BKE_mesh_flush_select_from_verts_ex(me->mvert, me->totvert, - me->mloop, - me->medge, me->totedge, - me->mpoly, me->totpoly); -} - - /* basic vertex data functions */ -int BKE_mesh_minmax(Mesh *me, float r_min[3], float r_max[3]) +bool BKE_mesh_minmax(Mesh *me, float r_min[3], float r_max[3]) { int i = me->totvert; MVert *mvert; @@ -3664,59 +1810,6 @@ int BKE_mesh_minmax(Mesh *me, float r_min[3], float r_max[3]) return (me->totvert != 0); } -int BKE_mesh_center_median(Mesh *me, float cent[3]) -{ - int i = me->totvert; - MVert *mvert; - zero_v3(cent); - for (mvert = me->mvert; i--; mvert++) { - add_v3_v3(cent, mvert->co); - } - /* otherwise we get NAN for 0 verts */ - if (me->totvert) { - mul_v3_fl(cent, 1.0f / (float)me->totvert); - } - - return (me->totvert != 0); -} - -int BKE_mesh_center_bounds(Mesh *me, float cent[3]) -{ - float min[3], max[3]; - INIT_MINMAX(min, max); - if (BKE_mesh_minmax(me, min, max)) { - mid_v3_v3v3(cent, min, max); - return 1; - } - - return 0; -} - -int BKE_mesh_center_centroid(Mesh *me, float cent[3]) -{ - int i = me->totpoly; - MPoly *mpoly; - float poly_area; - float total_area = 0.0f; - float poly_cent[3]; - - zero_v3(cent); - - /* calculate a weighted average of polygon centroids */ - for (mpoly = me->mpoly; i--; mpoly++) { - poly_area = mesh_calc_poly_planar_area_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent); - - madd_v3_v3fl(cent, poly_cent, poly_area); - total_area += poly_area; - } - /* otherwise we get NAN for 0 polys */ - if (me->totpoly) { - mul_v3_fl(cent, 1.0f / total_area); - } - - return (me->totpoly != 0); -} - void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) { int i = me->totvert; @@ -3773,85 +1866,6 @@ void BKE_mesh_tessface_clear(Mesh *mesh) mesh_tessface_clear_intern(mesh, TRUE); } -#if 0 /* slow version of the function below */ -void BKE_mesh_calc_poly_angles(MPoly *mpoly, MLoop *loopstart, - MVert *mvarray, float angles[]) -{ - MLoop *ml; - MLoop *mloop = &loopstart[-mpoly->loopstart]; - - int j; - for (j = 0, ml = loopstart; j < mpoly->totloop; j++, ml++) { - MLoop *ml_prev = ME_POLY_LOOP_PREV(mloop, mpoly, j); - MLoop *ml_next = ME_POLY_LOOP_NEXT(mloop, mpoly, j); - - float e1[3], e2[3]; - - sub_v3_v3v3(e1, mvarray[ml_next->v].co, mvarray[ml->v].co); - sub_v3_v3v3(e2, mvarray[ml_prev->v].co, mvarray[ml->v].co); - - angles[j] = (float)M_PI - angle_v3v3(e1, e2); - } -} - -#else /* equivalent the function above but avoid multiple subtractions + normalize */ - -void BKE_mesh_calc_poly_angles(MPoly *mpoly, MLoop *loopstart, - MVert *mvarray, float angles[]) -{ - float nor_prev[3]; - float nor_next[3]; - - int i_this = mpoly->totloop - 1; - int i_next = 0; - - sub_v3_v3v3(nor_prev, mvarray[loopstart[i_this - 1].v].co, mvarray[loopstart[i_this].v].co); - normalize_v3(nor_prev); - - while (i_next < mpoly->totloop) { - sub_v3_v3v3(nor_next, mvarray[loopstart[i_this].v].co, mvarray[loopstart[i_next].v].co); - normalize_v3(nor_next); - angles[i_this] = angle_normalized_v3v3(nor_prev, nor_next); - - /* step */ - copy_v3_v3(nor_prev, nor_next); - i_this = i_next; - i_next++; - } -} -#endif - -void BKE_mesh_poly_edgehash_insert(EdgeHash *ehash, const MPoly *mp, const MLoop *mloop) -{ - const MLoop *ml, *ml_next; - int i = mp->totloop; - - ml_next = mloop; /* first loop */ - ml = &ml_next[i - 1]; /* last loop */ - - while (i-- != 0) { - if (!BLI_edgehash_haskey(ehash, ml->v, ml_next->v)) { - BLI_edgehash_insert(ehash, ml->v, ml_next->v, NULL); - } - - ml = ml_next; - ml_next++; - } -} - -void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap, const MPoly *mp, const MLoop *mloop) -{ - const MLoop *ml; - int i = mp->totloop; - - ml = mloop; - - while (i-- != 0) { - BLI_BITMAP_SET(edge_bitmap, ml->e); - ml++; - } -} - void BKE_mesh_do_versions_cd_flag_init(Mesh *mesh) { if (UNLIKELY(mesh->cd_flag)) { diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c new file mode 100644 index 00000000000..07dfae2f28a --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -0,0 +1,2301 @@ +/* + * ***** 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 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/mesh_evaluate.c + * \ingroup bke + * + * Functions to evaluate mesh data. + */ + +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BLI_utildefines.h" +#include "BLI_memarena.h" +#include "BLI_math.h" +#include "BLI_edgehash.h" +#include "BLI_bitmap.h" +#include "BLI_scanfill.h" +#include "BLI_linklist.h" +#include "BLI_linklist_stack.h" +#include "BLI_alloca.h" + +#include "BKE_customdata.h" +#include "BKE_mesh.h" +#include "BKE_multires.h" + +#include "BLI_strict_flags.h" + + +// #define DEBUG_TIME + +#ifdef DEBUG_TIME +# include "PIL_time.h" +# include "PIL_time_utildefines.h" +#endif + +/* -------------------------------------------------------------------- */ + +/** \name Mesh Normal Calculation + * \{ */ + +/** + * Call when there are no polygons. + */ +static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts) +{ + int i; + for (i = 0; i < numVerts; i++) { + MVert *mv = &mverts[i]; + float no[3]; + + normalize_v3_v3(no, mv->co); + normal_float_to_short_v3(mv->no, no); + } +} + +/* Calculate vertex and face normals, face normals are returned in *faceNors_r if non-NULL + * and vertex normals are stored in actual mverts. + */ +void BKE_mesh_calc_normals_mapping(MVert *mverts, int numVerts, + MLoop *mloop, MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3], + MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3]) +{ + BKE_mesh_calc_normals_mapping_ex(mverts, numVerts, mloop, mpolys, + numLoops, numPolys, polyNors_r, mfaces, numFaces, + origIndexFace, faceNors_r, FALSE); +} +/* extended version of 'BKE_mesh_calc_normals_poly' with option not to calc vertex normals */ +void BKE_mesh_calc_normals_mapping_ex( + MVert *mverts, int numVerts, + MLoop *mloop, MPoly *mpolys, + int numLoops, int numPolys, float (*polyNors_r)[3], + MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3], + const bool only_face_normals) +{ + float (*pnors)[3] = polyNors_r, (*fnors)[3] = faceNors_r; + int i; + MFace *mf; + MPoly *mp; + + if (numPolys == 0) { + if (only_face_normals == FALSE) { + mesh_calc_normals_vert_fallback(mverts, numVerts); + } + return; + } + + /* if we are not calculating verts and no verts were passes then we have nothing to do */ + if ((only_face_normals == TRUE) && (polyNors_r == NULL) && (faceNors_r == NULL)) { + printf("%s: called with nothing to do\n", __func__); + return; + } + + if (!pnors) pnors = MEM_callocN(sizeof(float[3]) * (size_t)numPolys, __func__); + /* if (!fnors) fnors = MEM_callocN(sizeof(float[3]) * numFaces, "face nors mesh.c"); */ /* NO NEED TO ALLOC YET */ + + + if (only_face_normals == FALSE) { + /* vertex normals are optional, they require some extra calculations, + * so make them optional */ + BKE_mesh_calc_normals_poly(mverts, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false); + } + else { + /* only calc poly normals */ + mp = mpolys; + for (i = 0; i < numPolys; i++, mp++) { + BKE_mesh_calc_poly_normal(mp, mloop + mp->loopstart, mverts, pnors[i]); + } + } + + if (origIndexFace && + /* fnors == faceNors_r */ /* NO NEED TO ALLOC YET */ + fnors != NULL && + numFaces) + { + mf = mfaces; + for (i = 0; i < numFaces; i++, mf++, origIndexFace++) { + if (*origIndexFace < numPolys) { + copy_v3_v3(fnors[i], pnors[*origIndexFace]); + } + else { + /* eek, we're not corresponding to polys */ + printf("error in %s: tessellation face indices are incorrect. normals may look bad.\n", __func__); + } + } + } + + if (pnors != polyNors_r) MEM_freeN(pnors); + /* if (fnors != faceNors_r) MEM_freeN(fnors); */ /* NO NEED TO ALLOC YET */ + + fnors = pnors = NULL; + +} + +static void mesh_calc_normals_poly_accum(MPoly *mp, MLoop *ml, + MVert *mvert, float polyno[3], float (*tnorms)[3]) +{ + const int nverts = mp->totloop; + float (*edgevecbuf)[3] = BLI_array_alloca(edgevecbuf, (size_t)nverts); + int i; + + /* Polygon Normal and edge-vector */ + /* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */ + { + int i_prev = nverts - 1; + float const *v_prev = mvert[ml[i_prev].v].co; + float const *v_curr; + + zero_v3(polyno); + /* Newell's Method */ + for (i = 0; i < nverts; i++) { + v_curr = mvert[ml[i].v].co; + add_newell_cross_v3_v3v3(polyno, v_prev, v_curr); + + /* Unrelated to normalize, calculate edge-vector */ + sub_v3_v3v3(edgevecbuf[i_prev], v_prev, v_curr); + normalize_v3(edgevecbuf[i_prev]); + i_prev = i; + + v_prev = v_curr; + } + if (UNLIKELY(normalize_v3(polyno) == 0.0f)) { + polyno[2] = 1.0f; /* other axis set to 0.0 */ + } + } + + /* accumulate angle weighted face normal */ + /* inline version of #accumulate_vertex_normals_poly */ + { + const float *prev_edge = edgevecbuf[nverts - 1]; + + for (i = 0; i < nverts; i++) { + const float *cur_edge = edgevecbuf[i]; + + /* calculate angle between the two poly edges incident on + * this vertex */ + const float fac = saacos(-dot_v3v3(cur_edge, prev_edge)); + + /* accumulate */ + madd_v3_v3fl(tnorms[ml[i].v], polyno, fac); + prev_edge = cur_edge; + } + } + +} + +void BKE_mesh_calc_normals_poly(MVert *mverts, int numVerts, MLoop *mloop, MPoly *mpolys, + int UNUSED(numLoops), int numPolys, float (*r_polynors)[3], + const bool only_face_normals) +{ + float (*pnors)[3] = r_polynors; + float (*tnorms)[3]; + int i; + MPoly *mp; + + if (only_face_normals) { + BLI_assert(pnors != NULL); + +#pragma omp parallel for if (numPolys > BKE_MESH_OMP_LIMIT) + for (i = 0; i < numPolys; i++) { + BKE_mesh_calc_poly_normal(&mpolys[i], mloop + mpolys[i].loopstart, mverts, pnors[i]); + } + return; + } + + /* first go through and calculate normals for all the polys */ + tnorms = MEM_callocN(sizeof(*tnorms) * (size_t)numVerts, __func__); + + if (pnors) { + mp = mpolys; + for (i = 0; i < numPolys; i++, mp++) { + mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, pnors[i], tnorms); + } + } + else { + float tpnor[3]; /* temp poly normal */ + mp = mpolys; + for (i = 0; i < numPolys; i++, mp++) { + mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, tpnor, tnorms); + } + } + + /* following Mesh convention; we use vertex coordinate itself for normal in this case */ + for (i = 0; i < numVerts; i++) { + MVert *mv = &mverts[i]; + float *no = tnorms[i]; + + if (UNLIKELY(normalize_v3(no) == 0.0f)) { + normalize_v3_v3(no, mv->co); + } + + normal_float_to_short_v3(mv->no, no); + } + + MEM_freeN(tnorms); +} + +void BKE_mesh_calc_normals(Mesh *mesh) +{ +#ifdef DEBUG_TIME + TIMEIT_START(BKE_mesh_calc_normals); +#endif + BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, + mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, + NULL, false); +#ifdef DEBUG_TIME + TIMEIT_END(BKE_mesh_calc_normals); +#endif +} + +void BKE_mesh_calc_normals_tessface(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float (*faceNors_r)[3]) +{ + float (*tnorms)[3] = MEM_callocN(sizeof(*tnorms) * (size_t)numVerts, "tnorms"); + float (*fnors)[3] = (faceNors_r) ? faceNors_r : MEM_callocN(sizeof(*fnors) * (size_t)numFaces, "meshnormals"); + int i; + + for (i = 0; i < numFaces; i++) { + MFace *mf = &mfaces[i]; + float *f_no = fnors[i]; + float *n4 = (mf->v4) ? tnorms[mf->v4] : NULL; + float *c4 = (mf->v4) ? mverts[mf->v4].co : NULL; + + if (mf->v4) + normal_quad_v3(f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, mverts[mf->v4].co); + else + normal_tri_v3(f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co); + + accumulate_vertex_normals(tnorms[mf->v1], tnorms[mf->v2], tnorms[mf->v3], n4, + f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, c4); + } + + /* following Mesh convention; we use vertex coordinate itself for normal in this case */ + for (i = 0; i < numVerts; i++) { + MVert *mv = &mverts[i]; + float *no = tnorms[i]; + + if (UNLIKELY(normalize_v3(no) == 0.0f)) { + normalize_v3_v3(no, mv->co); + } + + normal_float_to_short_v3(mv->no, no); + } + + MEM_freeN(tnorms); + + if (fnors != faceNors_r) + MEM_freeN(fnors); +} + +/** + * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals'). + * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry (splitting edges). + */ +void BKE_mesh_normals_loop_split(MVert *mverts, int UNUSED(numVerts), MEdge *medges, int numEdges, + MLoop *mloops, float (*r_loopnors)[3], int numLoops, + MPoly *mpolys, float (*polynors)[3], int numPolys, float split_angle) +{ +#define INDEX_UNSET INT_MIN +#define INDEX_INVALID -1 +/* See comment about edge_to_loops below. */ +#define IS_EDGE_SHARP(_e2l) (ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID)) + + /* Mapping edge -> loops. + * If that edge is used by more than two loops (polys), it is always sharp (and tagged as such, see below). + * We also use the second loop index as a kind of flag: smooth edge: > 0, + * sharp edge: < 0 (INDEX_INVALID || INDEX_UNSET), + * unset: INDEX_UNSET + * Note that currently we only have two values for second loop of sharp edges. However, if needed, we can + * store the negated value of loop index instead of INDEX_INVALID to retrieve th real value later in code). + * Note also that lose edges always have both values set to 0! + */ + int (*edge_to_loops)[2] = MEM_callocN(sizeof(int[2]) * (size_t)numEdges, __func__); + + /* Simple mapping from a loop to its polygon index. */ + int *loop_to_poly = MEM_mallocN(sizeof(int) * (size_t)numLoops, __func__); + + MPoly *mp; + int mp_index; + const bool check_angle = (split_angle < (float)M_PI); + + /* Temp normal stack. */ + BLI_SMALLSTACK_DECLARE(normal, float *); + +#ifdef DEBUG_TIME + TIMEIT_START(BKE_mesh_normals_loop_split); +#endif + + if (check_angle) { + split_angle = cosf(split_angle); + } + + /* This first loop check which edges are actually smooth, and compute edge vectors. */ + for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { + MLoop *ml_curr; + int *e2l; + int ml_curr_index = mp->loopstart; + const int ml_last_index = (ml_curr_index + mp->totloop) - 1; + + ml_curr = &mloops[ml_curr_index]; + + for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++) { + e2l = edge_to_loops[ml_curr->e]; + + loop_to_poly[ml_curr_index] = mp_index; + + /* Pre-populate all loop normals as if their verts were all-smooth, this way we don't have to compute + * those later! + */ + normal_short_to_float_v3(r_loopnors[ml_curr_index], mverts[ml_curr->v].no); + + /* Check whether current edge might be smooth or sharp */ + if ((e2l[0] | e2l[1]) == 0) { + /* 'Empty' edge until now, set e2l[0] (and e2l[1] to INT_MIN to tag it as unset). */ + e2l[0] = ml_curr_index; + e2l[1] = INDEX_UNSET; + } + else if (e2l[1] == INDEX_UNSET) { + /* Second loop using this edge, time to test its sharpness. + * An edge is sharp if it is tagged as such, or its face is not smooth, or angle between + * both its polys' normals is above split_angle value... + */ + if (!(mp->flag & ME_SMOOTH) || (medges[ml_curr->e].flag & ME_SHARP) || + (check_angle && dot_v3v3(polynors[loop_to_poly[e2l[0]]], polynors[mp_index]) < split_angle)) + { + /* Note: we are sure that loop != 0 here ;) */ + e2l[1] = INDEX_INVALID; + } + else { + e2l[1] = ml_curr_index; + } + } + else if (!IS_EDGE_SHARP(e2l)) { + /* More that two loops using this edge, tag as sharp if not yet done. */ + e2l[1] = INDEX_INVALID; + } + /* Else, edge is already 'disqualified' (i.e. sharp)! */ + } + } + + /* We now know edges that can be smoothed (with their vector, and their two loops), and edges that will be hard! + * Now, time to generate the normals. + */ + for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) { + MLoop *ml_curr, *ml_prev; + float (*lnors)[3]; + const int ml_last_index = (mp->loopstart + mp->totloop) - 1; + int ml_curr_index = mp->loopstart; + int ml_prev_index = ml_last_index; + + ml_curr = &mloops[ml_curr_index]; + ml_prev = &mloops[ml_prev_index]; + lnors = &r_loopnors[ml_curr_index]; + + for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++, lnors++) { + const int *e2l_curr = edge_to_loops[ml_curr->e]; + const int *e2l_prev = edge_to_loops[ml_prev->e]; + + if (!IS_EDGE_SHARP(e2l_curr)) { + /* A smooth edge. + * We skip it because it is either: + * - in the middle of a 'smooth fan' already computed (or that will be as soon as we hit + * one of its ends, i.e. one of its two sharp edges), or... + * - the related vertex is a "full smooth" one, in which case pre-populated normals from vertex + * are just fine! + */ + } + else if (IS_EDGE_SHARP(e2l_prev)) { + /* Simple case (both edges around that vertex are sharp in current polygon), + * this vertex just takes its poly normal. + */ + copy_v3_v3(*lnors, polynors[mp_index]); + /* No need to mark loop as done here, we won't run into it again anyway! */ + } + /* This loop may have been already computed, in which case its 'to_poly' map is set to -1... */ + else if (loop_to_poly[ml_curr_index] != -1) { + /* Gah... We have to fan around current vertex, until we find the other non-smooth edge, + * and accumulate face normals into the vertex! + * Note in case this vertex has only one sharp edges, this is a waste because the normal is the same as + * the vertex normal, but I do not see any easy way to detect that (would need to count number + * of sharp edges per vertex, I doubt the additional memory usage would be worth it, especially as + * it should not be a common case in real-life meshes anyway). + */ + const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */ + const int *e2lfan_curr; + float vec_curr[3], vec_prev[3]; + MLoop *mlfan_curr, *mlfan_next; + MPoly *mpfan_next; + float lnor[3] = {0.0f, 0.0f, 0.0f}; + /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */ + int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index; + + e2lfan_curr = e2l_prev; + mlfan_curr = ml_prev; + mlfan_curr_index = ml_prev_index; + mlfan_vert_index = ml_curr_index; + mpfan_curr_index = mp_index; + + /* Only need to compute previous edge's vector once, then we can just reuse old current one! */ + { + const MEdge *me_prev = &medges[ml_prev->e]; + const MVert *mv_1 = &mverts[mv_pivot_index]; + const MVert *mv_2 = (me_prev->v1 == mv_pivot_index) ? &mverts[me_prev->v2] : &mverts[me_prev->v1]; + + sub_v3_v3v3(vec_prev, mv_2->co, mv_1->co); + normalize_v3(vec_prev); + } + + while (true) { + /* Compute edge vectors. + * NOTE: We could pre-compute those into an array, in the first iteration, instead of computing them + * twice (or more) here. However, time gained is not worth memory and time lost, + * given the fact that this code should not be called that much in real-life meshes... + */ + { + const MEdge *me_curr = &medges[ml_curr->e]; + const MVert *mv_1 = &mverts[mv_pivot_index]; + const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] : + &mverts[me_curr->v1]; + + sub_v3_v3v3(vec_curr, mv_2->co, mv_1->co); + normalize_v3(vec_curr); + } + + { + /* Code similar to accumulate_vertex_normals_poly. */ + /* Calculate angle between the two poly edges incident on this vertex. */ + const float fac = saacos(dot_v3v3(vec_curr, vec_prev)); + /* Accumulate */ + madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac); + } + + /* We store here a pointer to all loop-normals processed. */ + BLI_SMALLSTACK_PUSH(normal, &(r_loopnors[mlfan_vert_index][0])); + + /* And we are done with this loop, mark it as such! */ + loop_to_poly[mlfan_vert_index] = -1; + + if (IS_EDGE_SHARP(e2lfan_curr)) { + /* Current edge is sharp, we have finished with this fan of faces around this vert! */ + break; + } + + copy_v3_v3(vec_prev, vec_curr); + + /* Warning! This is rather complex! + * We have to find our next edge around the vertex (fan mode). + * First we find the next loop, which is either previous or next to mlfan_curr_index, depending + * whether both loops using current edge are in the same direction or not, and whether + * mlfan_curr_index actually uses the vertex we are fanning around! + * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one + * (i.e. not the future mlfan_curr)... + */ + mlfan_curr_index = (e2lfan_curr[0] == mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0]; + mpfan_curr_index = loop_to_poly[mlfan_curr_index]; + mlfan_next = &mloops[mlfan_curr_index]; + mpfan_next = &mpolys[mpfan_curr_index]; + if ((mlfan_curr->v == mlfan_next->v && mlfan_curr->v == mv_pivot_index) || + (mlfan_curr->v != mlfan_next->v && mlfan_curr->v != mv_pivot_index)) + { + /* We need the previous loop, but current one is our vertex's loop. */ + mlfan_vert_index = mlfan_curr_index; + if (--mlfan_curr_index < mpfan_next->loopstart) { + mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1; + } + } + else { + /* We need the next loop, which is also our vertex's loop. */ + if (++mlfan_curr_index >= mpfan_next->loopstart + mpfan_next->totloop) { + mlfan_curr_index = mpfan_next->loopstart; + } + mlfan_vert_index = mlfan_curr_index; + } + mlfan_curr = &mloops[mlfan_curr_index]; + /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */ + + e2lfan_curr = edge_to_loops[mlfan_curr->e]; + } + + /* In case we get a zero normal here, just use vertex normal already set! */ + if (LIKELY(normalize_v3(lnor) != 0.0f)) { + /* Copy back the final computed normal into all related loop-normals. */ + float *nor; + while ((nor = BLI_SMALLSTACK_POP(normal))) { + copy_v3_v3(nor, lnor); + } + } + } + + ml_prev = ml_curr; + ml_prev_index = ml_curr_index; + } + } + + BLI_SMALLSTACK_FREE(normal); + + MEM_freeN(edge_to_loops); + MEM_freeN(loop_to_poly); + +#ifdef DEBUG_TIME + TIMEIT_END(BKE_mesh_normals_loop_split); +#endif + +#undef INDEX_UNSET +#undef INDEX_INVALID +#undef IS_EDGE_SHARP +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Polygon Calculations + * \{ */ + +/* + * COMPUTE POLY NORMAL + * + * Computes the normal of a planar + * polygon See Graphics Gems for + * computing newell normal. + * + */ +static void mesh_calc_ngon_normal(MPoly *mpoly, MLoop *loopstart, + MVert *mvert, float normal[3]) +{ + const int nverts = mpoly->totloop; + float const *v_prev = mvert[loopstart[nverts - 1].v].co; + float const *v_curr; + int i; + + zero_v3(normal); + + /* Newell's Method */ + for (i = 0; i < nverts; i++) { + v_curr = mvert[loopstart[i].v].co; + add_newell_cross_v3_v3v3(normal, v_prev, v_curr); + v_prev = v_curr; + } + + if (UNLIKELY(normalize_v3(normal) == 0.0f)) { + normal[2] = 1.0f; /* other axis set to 0.0 */ + } +} + +void BKE_mesh_calc_poly_normal(MPoly *mpoly, MLoop *loopstart, + MVert *mvarray, float no[3]) +{ + if (mpoly->totloop > 4) { + mesh_calc_ngon_normal(mpoly, loopstart, mvarray, no); + } + else if (mpoly->totloop == 3) { + normal_tri_v3(no, + mvarray[loopstart[0].v].co, + mvarray[loopstart[1].v].co, + mvarray[loopstart[2].v].co + ); + } + else if (mpoly->totloop == 4) { + normal_quad_v3(no, + mvarray[loopstart[0].v].co, + mvarray[loopstart[1].v].co, + mvarray[loopstart[2].v].co, + mvarray[loopstart[3].v].co + ); + } + else { /* horrible, two sided face! */ + no[0] = 0.0; + no[1] = 0.0; + no[2] = 1.0; + } +} +/* duplicate of function above _but_ takes coords rather then mverts */ +static void mesh_calc_ngon_normal_coords(MPoly *mpoly, MLoop *loopstart, + const float (*vertex_coords)[3], float normal[3]) +{ + const int nverts = mpoly->totloop; + float const *v_prev = vertex_coords[loopstart[nverts - 1].v]; + float const *v_curr; + int i; + + zero_v3(normal); + + /* Newell's Method */ + for (i = 0; i < nverts; i++) { + v_curr = vertex_coords[loopstart[i].v]; + add_newell_cross_v3_v3v3(normal, v_prev, v_curr); + v_prev = v_curr; + } + + if (UNLIKELY(normalize_v3(normal) == 0.0f)) { + normal[2] = 1.0f; /* other axis set to 0.0 */ + } +} + +void BKE_mesh_calc_poly_normal_coords(MPoly *mpoly, MLoop *loopstart, + const float (*vertex_coords)[3], float no[3]) +{ + if (mpoly->totloop > 4) { + mesh_calc_ngon_normal_coords(mpoly, loopstart, vertex_coords, no); + } + else if (mpoly->totloop == 3) { + normal_tri_v3(no, + vertex_coords[loopstart[0].v], + vertex_coords[loopstart[1].v], + vertex_coords[loopstart[2].v] + ); + } + else if (mpoly->totloop == 4) { + normal_quad_v3(no, + vertex_coords[loopstart[0].v], + vertex_coords[loopstart[1].v], + vertex_coords[loopstart[2].v], + vertex_coords[loopstart[3].v] + ); + } + else { /* horrible, two sided face! */ + no[0] = 0.0; + no[1] = 0.0; + no[2] = 1.0; + } +} + +static void mesh_calc_ngon_center(MPoly *mpoly, MLoop *loopstart, + MVert *mvert, float cent[3]) +{ + const float w = 1.0f / (float)mpoly->totloop; + int i; + + zero_v3(cent); + + for (i = 0; i < mpoly->totloop; i++) { + madd_v3_v3fl(cent, mvert[(loopstart++)->v].co, w); + } +} + +void BKE_mesh_calc_poly_center(MPoly *mpoly, MLoop *loopstart, + MVert *mvarray, float cent[3]) +{ + if (mpoly->totloop == 3) { + cent_tri_v3(cent, + mvarray[loopstart[0].v].co, + mvarray[loopstart[1].v].co, + mvarray[loopstart[2].v].co + ); + } + else if (mpoly->totloop == 4) { + cent_quad_v3(cent, + mvarray[loopstart[0].v].co, + mvarray[loopstart[1].v].co, + mvarray[loopstart[2].v].co, + mvarray[loopstart[3].v].co + ); + } + else { + mesh_calc_ngon_center(mpoly, loopstart, mvarray, cent); + } +} + +/* note, passing polynormal is only a speedup so we can skip calculating it */ +float BKE_mesh_calc_poly_area(MPoly *mpoly, MLoop *loopstart, + MVert *mvarray, const float polynormal[3]) +{ + if (mpoly->totloop == 3) { + return area_tri_v3(mvarray[loopstart[0].v].co, + mvarray[loopstart[1].v].co, + 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; + float area, polynorm_local[3]; + float (*vertexcos)[3] = BLI_array_alloca(vertexcos, (size_t)mpoly->totloop); + const float *no = polynormal ? polynormal : polynorm_local; + + /* pack vertex cos into an array for area_poly_v3 */ + for (i = 0; i < mpoly->totloop; i++, l_iter++) { + copy_v3_v3(vertexcos[i], mvarray[l_iter->v].co); + } + + /* need normal for area_poly_v3 as well */ + if (polynormal == NULL) { + BKE_mesh_calc_poly_normal(mpoly, loopstart, mvarray, polynorm_local); + } + + /* finally calculate the area */ + area = area_poly_v3(mpoly->totloop, vertexcos, no); + + return area; + } +} + +/* note, results won't be correct if polygon is non-planar */ +static float mesh_calc_poly_planar_area_centroid(MPoly *mpoly, MLoop *loopstart, MVert *mvarray, float cent[3]) +{ + int i; + float tri_area; + float total_area = 0.0f; + float v1[3], v2[3], v3[3], normal[3], tri_cent[3]; + + BKE_mesh_calc_poly_normal(mpoly, loopstart, mvarray, normal); + copy_v3_v3(v1, mvarray[loopstart[0].v].co); + copy_v3_v3(v2, mvarray[loopstart[1].v].co); + zero_v3(cent); + + for (i = 2; i < mpoly->totloop; i++) { + copy_v3_v3(v3, mvarray[loopstart[i].v].co); + + tri_area = area_tri_signed_v3(v1, v2, v3, normal); + total_area += tri_area; + + cent_tri_v3(tri_cent, v1, v2, v3); + madd_v3_v3fl(cent, tri_cent, tri_area); + + copy_v3_v3(v2, v3); + } + + mul_v3_fl(cent, 1.0f / total_area); + + return total_area; +} + +#if 0 /* slow version of the function below */ +void BKE_mesh_calc_poly_angles(MPoly *mpoly, MLoop *loopstart, + MVert *mvarray, float angles[]) +{ + MLoop *ml; + MLoop *mloop = &loopstart[-mpoly->loopstart]; + + int j; + for (j = 0, ml = loopstart; j < mpoly->totloop; j++, ml++) { + MLoop *ml_prev = ME_POLY_LOOP_PREV(mloop, mpoly, j); + MLoop *ml_next = ME_POLY_LOOP_NEXT(mloop, mpoly, j); + + float e1[3], e2[3]; + + sub_v3_v3v3(e1, mvarray[ml_next->v].co, mvarray[ml->v].co); + sub_v3_v3v3(e2, mvarray[ml_prev->v].co, mvarray[ml->v].co); + + angles[j] = (float)M_PI - angle_v3v3(e1, e2); + } +} + +#else /* equivalent the function above but avoid multiple subtractions + normalize */ + +void BKE_mesh_calc_poly_angles(MPoly *mpoly, MLoop *loopstart, + MVert *mvarray, float angles[]) +{ + float nor_prev[3]; + float nor_next[3]; + + int i_this = mpoly->totloop - 1; + int i_next = 0; + + sub_v3_v3v3(nor_prev, mvarray[loopstart[i_this - 1].v].co, mvarray[loopstart[i_this].v].co); + normalize_v3(nor_prev); + + while (i_next < mpoly->totloop) { + sub_v3_v3v3(nor_next, mvarray[loopstart[i_this].v].co, mvarray[loopstart[i_next].v].co); + normalize_v3(nor_next); + angles[i_this] = angle_normalized_v3v3(nor_prev, nor_next); + + /* step */ + copy_v3_v3(nor_prev, nor_next); + i_this = i_next; + i_next++; + } +} +#endif + +void BKE_mesh_poly_edgehash_insert(EdgeHash *ehash, const MPoly *mp, const MLoop *mloop) +{ + const MLoop *ml, *ml_next; + int i = mp->totloop; + + ml_next = mloop; /* first loop */ + ml = &ml_next[i - 1]; /* last loop */ + + while (i-- != 0) { + BLI_edgehash_reinsert(ehash, ml->v, ml_next->v, NULL); + + ml = ml_next; + ml_next++; + } +} + +void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap, const MPoly *mp, const MLoop *mloop) +{ + const MLoop *ml; + int i = mp->totloop; + + ml = mloop; + + while (i-- != 0) { + BLI_BITMAP_SET(edge_bitmap, ml->e); + ml++; + } +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Mesh Center Calculation + * \{ */ + +bool BKE_mesh_center_median(Mesh *me, float cent[3]) +{ + int i = me->totvert; + MVert *mvert; + zero_v3(cent); + for (mvert = me->mvert; i--; mvert++) { + add_v3_v3(cent, mvert->co); + } + /* otherwise we get NAN for 0 verts */ + if (me->totvert) { + mul_v3_fl(cent, 1.0f / (float)me->totvert); + } + + return (me->totvert != 0); +} + +bool BKE_mesh_center_bounds(Mesh *me, float cent[3]) +{ + float min[3], max[3]; + INIT_MINMAX(min, max); + if (BKE_mesh_minmax(me, min, max)) { + mid_v3_v3v3(cent, min, max); + return true; + } + + return false; +} + +bool BKE_mesh_center_centroid(Mesh *me, float cent[3]) +{ + int i = me->totpoly; + MPoly *mpoly; + float poly_area; + float total_area = 0.0f; + float poly_cent[3]; + + zero_v3(cent); + + /* calculate a weighted average of polygon centroids */ + for (mpoly = me->mpoly; i--; mpoly++) { + poly_area = mesh_calc_poly_planar_area_centroid(mpoly, me->mloop + mpoly->loopstart, me->mvert, poly_cent); + + madd_v3_v3fl(cent, poly_cent, poly_area); + total_area += poly_area; + } + /* otherwise we get NAN for 0 polys */ + if (me->totpoly) { + mul_v3_fl(cent, 1.0f / total_area); + } + + /* zero area faces cause this, fallback to median */ + if (UNLIKELY(!is_finite_v3(cent))) { + return BKE_mesh_center_median(me, cent); + } + + return (me->totpoly != 0); +} +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Mesh Connectivity Mapping + * \{ */ + + +/* ngon version wip, based on EDBM_uv_vert_map_create */ +/* this replaces the non bmesh function (in trunk) which takes MTFace's, if we ever need it back we could + * but for now this replaces it because its unused. */ + +UvVertMap *BKE_mesh_uv_vert_map_create(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, + unsigned int totpoly, unsigned int totvert, int selected, float *limit) +{ + UvVertMap *vmap; + UvMapVert *buf; + MPoly *mp; + unsigned int a; + int i, totuv, nverts; + + totuv = 0; + + /* generate UvMapVert array */ + mp = mpoly; + for (a = 0; a < totpoly; a++, mp++) + if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) + totuv += mp->totloop; + + if (totuv == 0) + return NULL; + + vmap = (UvVertMap *)MEM_callocN(sizeof(*vmap), "UvVertMap"); + if (!vmap) + return NULL; + + vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totvert, "UvMapVert*"); + buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * (size_t)totuv, "UvMapVert"); + + if (!vmap->vert || !vmap->buf) { + BKE_mesh_uv_vert_map_free(vmap); + return NULL; + } + + mp = mpoly; + for (a = 0; a < totpoly; a++, mp++) { + if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) { + nverts = mp->totloop; + + for (i = 0; i < nverts; i++) { + buf->tfindex = (unsigned char)i; + buf->f = a; + buf->separate = 0; + buf->next = vmap->vert[mloop[mp->loopstart + i].v]; + vmap->vert[mloop[mp->loopstart + i].v] = buf; + buf++; + } + } + } + + /* sort individual uvs for each vert */ + for (a = 0; a < totvert; a++) { + UvMapVert *newvlist = NULL, *vlist = vmap->vert[a]; + UvMapVert *iterv, *v, *lastv, *next; + float *uv, *uv2, uvdiff[2]; + + while (vlist) { + v = vlist; + vlist = vlist->next; + v->next = newvlist; + newvlist = v; + + uv = mloopuv[mpoly[v->f].loopstart + v->tfindex].uv; + lastv = NULL; + iterv = vlist; + + while (iterv) { + next = iterv->next; + + uv2 = mloopuv[mpoly[iterv->f].loopstart + iterv->tfindex].uv; + sub_v2_v2v2(uvdiff, uv2, uv); + + + if (fabsf(uv[0] - uv2[0]) < limit[0] && fabsf(uv[1] - uv2[1]) < limit[1]) { + if (lastv) lastv->next = next; + else vlist = next; + iterv->next = newvlist; + newvlist = iterv; + } + else + lastv = iterv; + + iterv = next; + } + + newvlist->separate = 1; + } + + vmap->vert[a] = newvlist; + } + + return vmap; +} + +UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v) +{ + return vmap->vert[v]; +} + +void BKE_mesh_uv_vert_map_free(UvVertMap *vmap) +{ + if (vmap) { + if (vmap->vert) MEM_freeN(vmap->vert); + if (vmap->buf) MEM_freeN(vmap->buf); + MEM_freeN(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) +{ + MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, "vert poly map"); + int *indices, *index_iter; + int i, j; + + indices = index_iter = MEM_mallocN(sizeof(int) * (size_t)totloop, "vert poly map mem"); + + /* Count number of polys for each vertex */ + for (i = 0; i < totpoly; i++) { + const MPoly *p = &mpoly[i]; + + for (j = 0; j < p->totloop; j++) + map[mloop[p->loopstart + j].v].count++; + } + + /* Assign indices mem */ + for (i = 0; i < totvert; i++) { + map[i].indices = index_iter; + index_iter += map[i].count; + + /* Reset 'count' for use as index in last loop */ + map[i].count = 0; + } + + /* Find the users */ + for (i = 0; i < totpoly; i++) { + const MPoly *p = &mpoly[i]; + + for (j = 0; j < p->totloop; j++) { + unsigned int v = mloop[p->loopstart + j].v; + + map[v].indices[map[v].count] = i; + map[v].count++; + } + } + + *r_map = map; + *r_mem = indices; +} + +/* 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. */ +void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem, + const MEdge *medge, int totvert, int totedge) +{ + MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, "vert-edge map"); + int *indices = MEM_mallocN(sizeof(int[2]) * (size_t)totedge, "vert-edge map mem"); + int *i_pt = indices; + + int i; + + /* Count number of edges for each vertex */ + for (i = 0; i < totedge; i++) { + map[medge[i].v1].count++; + map[medge[i].v2].count++; + } + + /* Assign indices mem */ + for (i = 0; i < totvert; i++) { + map[i].indices = i_pt; + i_pt += map[i].count; + + /* Reset 'count' for use as index in last loop */ + map[i].count = 0; + } + + /* Find the users */ + for (i = 0; i < totedge; i++) { + const unsigned int v[2] = {medge[i].v1, medge[i].v2}; + + map[v[0]].indices[map[v[0]].count] = i; + map[v[1]].indices[map[v[1]].count] = i; + + map[v[0]].count++; + map[v[1]].count++; + } + + *r_map = map; + *r_mem = indices; +} + +void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map, int **r_mem, + const MEdge *UNUSED(medge), const int totedge, + const MPoly *mpoly, const int totpoly, + const MLoop *mloop, const int totloop) +{ + MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totedge, "edge-poly map"); + int *indices = MEM_mallocN(sizeof(int) * (size_t)totloop, "edge-poly map mem"); + int *index_step; + const MPoly *mp; + int i; + + /* count face users */ + for (i = 0, mp = mpoly; i < totpoly; mp++, i++) { + const MLoop *ml; + int j = mp->totloop; + for (ml = &mloop[mp->loopstart]; j--; ml++) { + map[ml->e].count++; + } + } + + /* create offsets */ + index_step = indices; + for (i = 0; i < totedge; i++) { + map[i].indices = index_step; + index_step += map[i].count; + + /* re-count, using this as an index below */ + map[i].count = 0; + + } + + /* assign poly-edge users */ + for (i = 0, mp = mpoly; i < totpoly; mp++, i++) { + const MLoop *ml; + int j = mp->totloop; + for (ml = &mloop[mp->loopstart]; j--; ml++) { + MeshElemMap *map_ele = &map[ml->e]; + map_ele->indices[map_ele->count++] = i; + } + } + + *r_map = map; + *r_mem = indices; +} + + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name NGon Tessellation (NGon/Tessface Conversion) + * \{ */ + +/** + * Convert a triangle or quadrangle of loop/poly data to tessface data + */ +void BKE_mesh_loops_to_mface_corners( + CustomData *fdata, CustomData *ldata, + CustomData *pdata, int lindex[4], int findex, + const int polyindex, + const int mf_len, /* 3 or 4 */ + + /* cache values to avoid lookups every time */ + const int numTex, /* CustomData_number_of_layers(pdata, CD_MTEXPOLY) */ + const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */ + const bool hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */ + const bool hasOrigSpace /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */ +) +{ + MTFace *texface; + MTexPoly *texpoly; + MCol *mcol; + MLoopCol *mloopcol; + MLoopUV *mloopuv; + int i, j; + + for (i = 0; i < numTex; i++) { + texface = CustomData_get_n(fdata, CD_MTFACE, findex, i); + texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i); + + ME_MTEXFACE_CPY(texface, texpoly); + + for (j = 0; j < mf_len; j++) { + mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, lindex[j], i); + copy_v2_v2(texface->uv[j], mloopuv->uv); + } + } + + for (i = 0; i < numCol; i++) { + mcol = CustomData_get_n(fdata, CD_MCOL, findex, i); + + for (j = 0; j < mf_len; j++) { + mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, lindex[j], i); + MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]); + } + } + + if (hasPCol) { + mcol = CustomData_get(fdata, findex, CD_PREVIEW_MCOL); + + for (j = 0; j < mf_len; j++) { + mloopcol = CustomData_get(ldata, lindex[j], CD_PREVIEW_MLOOPCOL); + MESH_MLOOPCOL_TO_MCOL(mloopcol, &mcol[j]); + } + } + + if (hasOrigSpace) { + OrigSpaceFace *of = CustomData_get(fdata, findex, CD_ORIGSPACE); + OrigSpaceLoop *lof; + + for (j = 0; j < mf_len; j++) { + lof = CustomData_get(ldata, lindex[j], CD_ORIGSPACE_MLOOP); + copy_v2_v2(of->uv[j], lof->uv); + } + } +} + +/** + * Recreate tessellation. + * + * use_poly_origindex sets whether or not the tessellation faces' origindex + * layer should point to original poly indices or real poly indices. + * + * use_face_origindex sets the tessellation faces' origindex layer + * to point to the tessellation faces themselves, not the polys. + * + * if both of the above are 0, it'll use the indices of the mpolys of the MPoly + * data in pdata, and ignore the origindex layer altogether. + * + * \return number of tessellation faces. + */ +int BKE_mesh_recalc_tessellation(CustomData *fdata, + CustomData *ldata, CustomData *pdata, + MVert *mvert, int totface, int totloop, + int totpoly, + /* when tessellating to recalculate normals after + * we can skip copying here */ + const bool do_face_nor_cpy) +{ + /* use this to avoid locking pthread for _every_ polygon + * and calling the fill function */ + +#define USE_TESSFACE_SPEEDUP +#define USE_TESSFACE_QUADS // NEEDS FURTHER TESTING + +#define TESSFACE_SCANFILL (1 << 0) +#define TESSFACE_IS_QUAD (1 << 1) + + const int looptris_tot = poly_to_tri_count(totpoly, totloop); + + MPoly *mp, *mpoly; + MLoop *ml, *mloop; + MFace *mface, *mf; + ScanFillContext sf_ctx; + ScanFillVert *sf_vert, *sf_vert_last, *sf_vert_first; + ScanFillFace *sf_tri; + MemArena *sf_arena = NULL; + int *mface_to_poly_map; + int lindex[4]; /* only ever use 3 in this case */ + int poly_index, j, mface_index; + + const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY); + const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL); + const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL); + const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP); + + mpoly = CustomData_get_layer(pdata, CD_MPOLY); + mloop = CustomData_get_layer(ldata, CD_MLOOP); + + /* allocate the length of totfaces, avoid many small reallocs, + * if all faces are tri's it will be correct, quads == 2x allocs */ + /* take care. we are _not_ calloc'ing so be sure to initialize each field */ + mface_to_poly_map = MEM_mallocN(sizeof(*mface_to_poly_map) * (size_t)looptris_tot, __func__); + mface = MEM_mallocN(sizeof(*mface) * (size_t)looptris_tot, __func__); + + mface_index = 0; + mp = mpoly; + for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) { + const unsigned int mp_loopstart = (unsigned int)mp->loopstart; + if (mp->totloop < 3) { + /* do nothing */ + } + +#ifdef USE_TESSFACE_SPEEDUP + +#define ML_TO_MF(i1, i2, i3) \ + mface_to_poly_map[mface_index] = poly_index; \ + mf = &mface[mface_index]; \ + /* set loop indices, transformed to vert indices later */ \ + mf->v1 = mp_loopstart + i1; \ + mf->v2 = mp_loopstart + i2; \ + mf->v3 = mp_loopstart + i3; \ + mf->v4 = 0; \ + mf->mat_nr = mp->mat_nr; \ + mf->flag = mp->flag; \ + mf->edcode = 0; \ + (void)0 + +/* ALMOST IDENTICAL TO DEFINE ABOVE (see EXCEPTION) */ +#define ML_TO_MF_QUAD() \ + mface_to_poly_map[mface_index] = poly_index; \ + mf = &mface[mface_index]; \ + /* set loop indices, transformed to vert indices later */ \ + mf->v1 = mp_loopstart + 0; /* EXCEPTION */ \ + mf->v2 = mp_loopstart + 1; /* EXCEPTION */ \ + mf->v3 = mp_loopstart + 2; /* EXCEPTION */ \ + mf->v4 = mp_loopstart + 3; /* EXCEPTION */ \ + mf->mat_nr = mp->mat_nr; \ + mf->flag = mp->flag; \ + mf->edcode = TESSFACE_IS_QUAD; /* EXCEPTION */ \ + (void)0 + + + else if (mp->totloop == 3) { + ML_TO_MF(0, 1, 2); + mface_index++; + } + else if (mp->totloop == 4) { +#ifdef USE_TESSFACE_QUADS + ML_TO_MF_QUAD(); + mface_index++; +#else + ML_TO_MF(0, 1, 2); + mface_index++; + ML_TO_MF(0, 2, 3); + mface_index++; +#endif + } +#endif /* USE_TESSFACE_SPEEDUP */ + else { +#define USE_TESSFACE_CALCNORMAL + + unsigned int totfilltri; + +#ifdef USE_TESSFACE_CALCNORMAL + float normal[3]; + zero_v3(normal); +#endif + ml = mloop + mp->loopstart; + + if (UNLIKELY(sf_arena == NULL)) { + sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__); + } + + BLI_scanfill_begin_arena(&sf_ctx, sf_arena); + sf_vert_first = NULL; + sf_vert_last = NULL; + for (j = 0; j < mp->totloop; j++, ml++) { + sf_vert = BLI_scanfill_vert_add(&sf_ctx, mvert[ml->v].co); + + sf_vert->keyindex = (unsigned int)(mp->loopstart + j); + + if (sf_vert_last) { + BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert); +#ifdef USE_TESSFACE_CALCNORMAL + add_newell_cross_v3_v3v3(normal, sf_vert_last->co, sf_vert->co); +#endif + } + + if (!sf_vert_first) + sf_vert_first = sf_vert; + sf_vert_last = sf_vert; + } + BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert_first); +#ifdef USE_TESSFACE_CALCNORMAL + add_newell_cross_v3_v3v3(normal, sf_vert_last->co, sf_vert_first->co); + if (UNLIKELY(normalize_v3(normal) == 0.0f)) { + normal[2] = 1.0f; + } + totfilltri = BLI_scanfill_calc_ex(&sf_ctx, 0, normal); +#else + totfilltri = BLI_scanfill_calc(&sf_ctx, 0); +#endif + BLI_assert(totfilltri <= (unsigned int)(mp->totloop - 2)); + (void)totfilltri; + + for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next, mf++) { + mface_to_poly_map[mface_index] = poly_index; + mf = &mface[mface_index]; + + /* set loop indices, transformed to vert indices later */ + mf->v1 = sf_tri->v1->keyindex; + mf->v2 = sf_tri->v2->keyindex; + mf->v3 = sf_tri->v3->keyindex; + mf->v4 = 0; + + mf->mat_nr = mp->mat_nr; + mf->flag = mp->flag; + +#ifdef USE_TESSFACE_SPEEDUP + mf->edcode = TESSFACE_SCANFILL; /* tag for sorting loop indices */ +#endif + + mface_index++; + } + + BLI_scanfill_end_arena(&sf_ctx, sf_arena); + +#undef USE_TESSFACE_CALCNORMAL + } + } + + if (sf_arena) { + BLI_memarena_free(sf_arena); + sf_arena = NULL; + } + + CustomData_free(fdata, totface); + totface = mface_index; + + BLI_assert(totface <= looptris_tot); + + /* not essential but without this we store over-alloc'd memory in the CustomData layers */ + if (LIKELY(looptris_tot != totface)) { + mface = MEM_reallocN(mface, sizeof(*mface) * (size_t)totface); + mface_to_poly_map = MEM_reallocN(mface_to_poly_map, sizeof(*mface_to_poly_map) * (size_t)totface); + } + + CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface); + + /* CD_ORIGINDEX will contain an array of indices from tessfaces to the polygons + * they are directly tessellated from */ + CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface); + CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); + + if (do_face_nor_cpy) { + /* If polys have a normals layer, copying that to faces can help + * avoid the need to recalculate normals later */ + if (CustomData_has_layer(pdata, CD_NORMAL)) { + float (*pnors)[3] = CustomData_get_layer(pdata, CD_NORMAL); + float (*fnors)[3] = CustomData_add_layer(fdata, CD_NORMAL, CD_CALLOC, NULL, totface); + for (mface_index = 0; mface_index < totface; mface_index++) { + copy_v3_v3(fnors[mface_index], pnors[mface_to_poly_map[mface_index]]); + } + } + } + + mf = mface; + for (mface_index = 0; mface_index < totface; mface_index++, mf++) { + +#ifdef USE_TESSFACE_QUADS + const int mf_len = mf->edcode & TESSFACE_IS_QUAD ? 4 : 3; +#endif + +#ifdef USE_TESSFACE_SPEEDUP + /* skip sorting when not using ngons */ + if (UNLIKELY(mf->edcode & TESSFACE_SCANFILL)) +#endif + { + /* sort loop indices to ensure winding is correct */ + if (mf->v1 > mf->v2) SWAP(unsigned int, mf->v1, mf->v2); + if (mf->v2 > mf->v3) SWAP(unsigned int, mf->v2, mf->v3); + if (mf->v1 > mf->v2) SWAP(unsigned int, mf->v1, mf->v2); + + if (mf->v1 > mf->v2) SWAP(unsigned int, mf->v1, mf->v2); + if (mf->v2 > mf->v3) SWAP(unsigned int, mf->v2, mf->v3); + if (mf->v1 > mf->v2) SWAP(unsigned int, mf->v1, mf->v2); + } + + /* end abusing the edcode */ +#if defined(USE_TESSFACE_QUADS) || defined(USE_TESSFACE_SPEEDUP) + mf->edcode = 0; +#endif + + + lindex[0] = (int)mf->v1; + lindex[1] = (int)mf->v2; + lindex[2] = (int)mf->v3; +#ifdef USE_TESSFACE_QUADS + if (mf_len == 4) lindex[3] = (int)mf->v4; +#endif + + /*transform loop indices to vert indices*/ + mf->v1 = mloop[mf->v1].v; + mf->v2 = mloop[mf->v2].v; + mf->v3 = mloop[mf->v3].v; +#ifdef USE_TESSFACE_QUADS + if (mf_len == 4) mf->v4 = mloop[mf->v4].v; +#endif + + BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata, + lindex, mface_index, mface_to_poly_map[mface_index], +#ifdef USE_TESSFACE_QUADS + mf_len, +#else + 3, +#endif + numTex, numCol, hasPCol, hasOrigSpace); + + +#ifdef USE_TESSFACE_QUADS + test_index_face(mf, fdata, mface_index, mf_len); +#endif + + } + + return totface; + +#undef USE_TESSFACE_SPEEDUP + +} + + +#ifdef USE_BMESH_SAVE_AS_COMPAT + +/** + * This function recreates a tessellation. + * returns number of tessellation faces. + * + * for forwards compat only quad->tri polys to mface, skip ngons. + */ +int BKE_mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata, + struct CustomData *pdata, int totface, int UNUSED(totloop), int totpoly) +{ + MLoop *mloop; + + int lindex[4]; + int i; + int k; + + MPoly *mp, *mpoly; + MFace *mface, *mf; + + const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY); + const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL); + const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL); + const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP); + + /* over-alloc, ngons will be skipped */ + mface = MEM_mallocN(sizeof(*mface) * (size_t)totpoly, __func__); + + mpoly = CustomData_get_layer(pdata, CD_MPOLY); + mloop = CustomData_get_layer(ldata, CD_MLOOP); + + mp = mpoly; + k = 0; + for (i = 0; i < totpoly; i++, mp++) { + if (ELEM(mp->totloop, 3, 4)) { + const unsigned int mp_loopstart = (unsigned int)mp->loopstart; + mf = &mface[k]; + + mf->mat_nr = mp->mat_nr; + mf->flag = mp->flag; + + mf->v1 = mp_loopstart + 0; + mf->v2 = mp_loopstart + 1; + mf->v3 = mp_loopstart + 2; + mf->v4 = (mp->totloop == 4) ? (mp_loopstart + 3) : 0; + + /* abuse edcode for temp storage and clear next loop */ + mf->edcode = (char)mp->totloop; /* only ever 3 or 4 */ + + k++; + } + } + + CustomData_free(fdata, totface); + + totface = k; + + CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface); + + CustomData_from_bmeshpoly(fdata, pdata, ldata, totface); + + mp = mpoly; + k = 0; + for (i = 0; i < totpoly; i++, mp++) { + if (ELEM(mp->totloop, 3, 4)) { + mf = &mface[k]; + + if (mf->edcode == 3) { + /* sort loop indices to ensure winding is correct */ + /* NO SORT - looks like we can skip this */ + + lindex[0] = (int)mf->v1; + lindex[1] = (int)mf->v2; + lindex[2] = (int)mf->v3; + lindex[3] = 0; /* unused */ + + /* transform loop indices to vert indices */ + mf->v1 = mloop[mf->v1].v; + mf->v2 = mloop[mf->v2].v; + mf->v3 = mloop[mf->v3].v; + + BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata, + lindex, k, i, 3, + numTex, numCol, hasPCol, hasOrigSpace); + test_index_face(mf, fdata, k, 3); + } + else { + /* sort loop indices to ensure winding is correct */ + /* NO SORT - looks like we can skip this */ + + lindex[0] = (int)mf->v1; + lindex[1] = (int)mf->v2; + lindex[2] = (int)mf->v3; + lindex[3] = (int)mf->v4; + + /* transform loop indices to vert indices */ + mf->v1 = mloop[mf->v1].v; + mf->v2 = mloop[mf->v2].v; + mf->v3 = mloop[mf->v3].v; + mf->v4 = mloop[mf->v4].v; + + BKE_mesh_loops_to_mface_corners(fdata, ldata, pdata, + lindex, k, i, 4, + numTex, numCol, hasPCol, hasOrigSpace); + test_index_face(mf, fdata, k, 4); + } + + mf->edcode = 0; + + k++; + } + } + + return k; +} +#endif /* USE_BMESH_SAVE_AS_COMPAT */ + + +static void bm_corners_to_loops_ex(ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata, + MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol) +{ + MTFace *texface; + MTexPoly *texpoly; + MCol *mcol; + MLoopCol *mloopcol; + MLoopUV *mloopuv; + MFace *mf; + int i; + + mf = mface + findex; + + for (i = 0; i < numTex; i++) { + texface = CustomData_get_n(fdata, CD_MTFACE, findex, i); + texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, findex, i); + + ME_MTEXFACE_CPY(texpoly, texface); + + mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i); + copy_v2_v2(mloopuv->uv, texface->uv[0]); mloopuv++; + copy_v2_v2(mloopuv->uv, texface->uv[1]); mloopuv++; + copy_v2_v2(mloopuv->uv, texface->uv[2]); mloopuv++; + + if (mf->v4) { + copy_v2_v2(mloopuv->uv, texface->uv[3]); mloopuv++; + } + } + + for (i = 0; i < numCol; i++) { + mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, loopstart, i); + mcol = CustomData_get_n(fdata, CD_MCOL, findex, i); + + MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[0]); mloopcol++; + MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[1]); mloopcol++; + MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[2]); mloopcol++; + if (mf->v4) { + MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[3]); mloopcol++; + } + } + + if (CustomData_has_layer(fdata, CD_MDISPS)) { + MDisps *ld = CustomData_get(ldata, loopstart, CD_MDISPS); + MDisps *fd = CustomData_get(fdata, findex, CD_MDISPS); + float (*disps)[3] = fd->disps; + int tot = mf->v4 ? 4 : 3; + int corners; + + if (CustomData_external_test(fdata, CD_MDISPS)) { + if (id && fdata->external) { + CustomData_external_add(ldata, id, CD_MDISPS, + totloop, fdata->external->filename); + } + } + + corners = multires_mdisp_corners(fd); + + if (corners == 0) { + /* Empty MDisp layers appear in at least one of the sintel.blend files. + * Not sure why this happens, but it seems fine to just ignore them here. + * If (corners == 0) for a non-empty layer though, something went wrong. */ + BLI_assert(fd->totdisp == 0); + } + else { + const int side = (int)sqrtf((float)(fd->totdisp / corners)); + const int side_sq = side * side; + const size_t disps_size = sizeof(float[3]) * (size_t)side_sq; + + for (i = 0; i < tot; i++, disps += side_sq, ld++) { + ld->totdisp = side_sq; + ld->level = (int)(logf((float)side - 1.0f) / (float)M_LN2) + 1; + + if (ld->disps) + MEM_freeN(ld->disps); + + ld->disps = MEM_mallocN(disps_size, "converted loop mdisps"); + if (fd->disps) { + memcpy(ld->disps, disps, disps_size); + } + else { + memset(ld->disps, 0, disps_size); + } + } + } + } +} + + +void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh) +{ + BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id, &mesh->fdata, &mesh->ldata, &mesh->pdata, + mesh->totedge, mesh->totface, mesh->totloop, mesh->totpoly, + mesh->medge, mesh->mface, + &mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly); + + BKE_mesh_update_customdata_pointers(mesh, true); +} + +/* the same as BKE_mesh_convert_mfaces_to_mpolys but oriented to be used in do_versions from readfile.c + * the difference is how active/render/clone/stencil indices are handled here + * + * normally thay're being set from pdata which totally makes sense for meshes which are already + * converted to bmesh structures, but when loading older files indices shall be updated in other + * way around, so newly added pdata and ldata would have this indices set based on fdata layer + * + * this is normally only needed when reading older files, in all other cases BKE_mesh_convert_mfaces_to_mpolys + * shall be always used + */ +void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh) +{ + BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id, &mesh->fdata, &mesh->ldata, &mesh->pdata, + mesh->totedge, mesh->totface, mesh->totloop, mesh->totpoly, + mesh->medge, mesh->mface, + &mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly); + + CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->pdata, &mesh->ldata); + + BKE_mesh_update_customdata_pointers(mesh, true); +} + +void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata, + int totedge_i, int totface_i, int totloop_i, int totpoly_i, + MEdge *medge, MFace *mface, + int *totloop_r, int *totpoly_r, + MLoop **mloop_r, MPoly **mpoly_r) +{ + MFace *mf; + MLoop *ml, *mloop; + MPoly *mp, *mpoly; + MEdge *me; + EdgeHash *eh; + int numTex, numCol; + int i, j, totloop, totpoly, *polyindex; + + /* just in case some of these layers are filled in (can happen with python created meshes) */ + CustomData_free(ldata, totloop_i); + CustomData_free(pdata, totpoly_i); + + totpoly = totface_i; + mpoly = MEM_callocN(sizeof(MPoly) * (size_t)totpoly, "mpoly converted"); + CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, totpoly); + + numTex = CustomData_number_of_layers(fdata, CD_MTFACE); + numCol = CustomData_number_of_layers(fdata, CD_MCOL); + + totloop = 0; + mf = mface; + for (i = 0; i < totface_i; i++, mf++) { + totloop += mf->v4 ? 4 : 3; + } + + mloop = MEM_callocN(sizeof(MLoop) * (size_t)totloop, "mloop converted"); + + CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop); + + CustomData_to_bmeshpoly(fdata, pdata, ldata, totloop, totpoly); + + if (id) { + /* ensure external data is transferred */ + CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i); + } + + eh = BLI_edgehash_new_ex(__func__, (unsigned int)totedge_i); + + /* build edge hash */ + me = medge; + for (i = 0; i < totedge_i; i++, me++) { + BLI_edgehash_insert(eh, me->v1, me->v2, SET_UINT_IN_POINTER(i)); + + /* unrelated but avoid having the FGON flag enabled, so we can reuse it later for something else */ + me->flag &= ~ME_FGON; + } + + polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX); + + j = 0; /* current loop index */ + ml = mloop; + mf = mface; + mp = mpoly; + for (i = 0; i < totface_i; i++, mf++, mp++) { + mp->loopstart = j; + + mp->totloop = mf->v4 ? 4 : 3; + + mp->mat_nr = mf->mat_nr; + mp->flag = mf->flag; + +# define ML(v1, v2) { \ + ml->v = mf->v1; \ + ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); \ + ml++; j++; \ + } (void)0 + + ML(v1, v2); + ML(v2, v3); + if (mf->v4) { + ML(v3, v4); + ML(v4, v1); + } + else { + ML(v3, v1); + } + +# undef ML + + bm_corners_to_loops_ex(id, fdata, ldata, pdata, mface, totloop, i, mp->loopstart, numTex, numCol); + + if (polyindex) { + *polyindex = i; + polyindex++; + } + } + + /* note, we don't convert NGons at all, these are not even real ngons, + * they have their own UV's, colors etc - its more an editing feature. */ + + BLI_edgehash_free(eh, NULL); + + *totpoly_r = totpoly; + *totloop_r = totloop; + *mpoly_r = mpoly; + *mloop_r = mloop; +} +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Mesh Flag Flushing + * \{ */ + +/* update the hide flag for edges and faces from the corresponding + * flag in verts */ +void BKE_mesh_flush_hidden_from_verts_ex(const MVert *mvert, + const MLoop *mloop, + MEdge *medge, const int totedge, + MPoly *mpoly, const int totpoly) +{ + int i, j; + + for (i = 0; i < totedge; i++) { + MEdge *e = &medge[i]; + if (mvert[e->v1].flag & ME_HIDE || + mvert[e->v2].flag & ME_HIDE) + { + e->flag |= ME_HIDE; + } + else { + e->flag &= ~ME_HIDE; + } + } + for (i = 0; i < totpoly; i++) { + MPoly *p = &mpoly[i]; + p->flag &= (char)~ME_HIDE; + for (j = 0; j < p->totloop; j++) { + if (mvert[mloop[p->loopstart + j].v].flag & ME_HIDE) + p->flag |= ME_HIDE; + } + } +} +void BKE_mesh_flush_hidden_from_verts(Mesh *me) +{ + BKE_mesh_flush_hidden_from_verts_ex(me->mvert, me->mloop, + me->medge, me->totedge, + me->mpoly, me->totpoly); +} + +void BKE_mesh_flush_hidden_from_polys_ex(MVert *mvert, + const MLoop *mloop, + MEdge *medge, const int UNUSED(totedge), + const MPoly *mpoly, const int totpoly) +{ + const MPoly *mp; + int i; + + i = totpoly; + for (mp = mpoly; i--; mp++) { + if (mp->flag & ME_HIDE) { + const MLoop *ml; + int j; + j = mp->totloop; + for (ml = &mloop[mp->loopstart]; j--; ml++) { + mvert[ml->v].flag |= ME_HIDE; + medge[ml->e].flag |= ME_HIDE; + } + } + } + + i = totpoly; + for (mp = mpoly; i--; mp++) { + if ((mp->flag & ME_HIDE) == 0) { + const MLoop *ml; + int j; + j = mp->totloop; + for (ml = &mloop[mp->loopstart]; j--; ml++) { + mvert[ml->v].flag &= (char)~ME_HIDE; + medge[ml->e].flag &= (char)~ME_HIDE; + } + } + } +} +void BKE_mesh_flush_hidden_from_polys(Mesh *me) +{ + BKE_mesh_flush_hidden_from_polys_ex(me->mvert, me->mloop, + me->medge, me->totedge, + me->mpoly, me->totpoly); +} + +/** + * simple poly -> vert/edge selection. + */ +void BKE_mesh_flush_select_from_polys_ex(MVert *mvert, const int totvert, + const MLoop *mloop, + MEdge *medge, const int totedge, + const MPoly *mpoly, const int totpoly) +{ + MVert *mv; + MEdge *med; + const MPoly *mp; + int i; + + i = totvert; + for (mv = mvert; i--; mv++) { + mv->flag &= (char)~SELECT; + } + + i = totedge; + for (med = medge; i--; med++) { + med->flag &= ~SELECT; + } + + i = totpoly; + for (mp = mpoly; i--; mp++) { + /* assume if its selected its not hidden and none of its verts/edges are hidden + * (a common assumption)*/ + if (mp->flag & ME_FACE_SEL) { + const MLoop *ml; + int j; + j = mp->totloop; + for (ml = &mloop[mp->loopstart]; j--; ml++) { + mvert[ml->v].flag |= SELECT; + medge[ml->e].flag |= SELECT; + } + } + } +} +void BKE_mesh_flush_select_from_polys(Mesh *me) +{ + BKE_mesh_flush_select_from_polys_ex(me->mvert, me->totvert, + me->mloop, + me->medge, me->totedge, + me->mpoly, me->totpoly); +} + +void BKE_mesh_flush_select_from_verts_ex(const MVert *mvert, const int UNUSED(totvert), + const MLoop *mloop, + MEdge *medge, const int totedge, + MPoly *mpoly, const int totpoly) +{ + MEdge *med; + MPoly *mp; + int i; + + /* edges */ + i = totedge; + for (med = medge; i--; med++) { + if ((med->flag & ME_HIDE) == 0) { + if ((mvert[med->v1].flag & SELECT) && (mvert[med->v2].flag & SELECT)) { + med->flag |= SELECT; + } + else { + med->flag &= ~SELECT; + } + } + } + + /* polys */ + i = totpoly; + for (mp = mpoly; i--; mp++) { + if ((mp->flag & ME_HIDE) == 0) { + int ok = TRUE; + const MLoop *ml; + int j; + j = mp->totloop; + for (ml = &mloop[mp->loopstart]; j--; ml++) { + if ((mvert[ml->v].flag & SELECT) == 0) { + ok = FALSE; + break; + } + } + + if (ok) { + mp->flag |= ME_FACE_SEL; + } + else { + mp->flag &= (char)~ME_FACE_SEL; + } + } + } +} +void BKE_mesh_flush_select_from_verts(Mesh *me) +{ + BKE_mesh_flush_select_from_verts_ex(me->mvert, me->totvert, + me->mloop, + me->medge, me->totedge, + me->mpoly, me->totpoly); +} +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Mesh 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. + */ +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; + int *poly_stack; + + 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 */ + int tot_group = 0; + bool group_id_overflow = false; + + /* map vars */ + MeshElemMap *edge_poly_map; + int *edge_poly_mem; + + if (totpoly == 0) { + *r_totgroup = 0; + return NULL; + } + + 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__); + + while (true) { + int poly; + int bit_poly_group_mask = 0; + int poly_group_id; + int ps_curr_idx = 0, ps_end_idx = 0; /* stack indices */ + + for (poly = poly_prev; poly < totpoly; poly++) { + if (poly_groups[poly] == 0) { + break; + } + } + + if (poly == totpoly) { + /* all done */ + break; + } + + poly_group_id = use_bitflags ? temp_poly_group_id : ++tot_group; + + /* start searching from here next time */ + poly_prev = poly + 1; + + poly_groups[poly] = poly_group_id; + poly_stack[ps_end_idx++] = poly; + + while (ps_curr_idx != ps_end_idx) { + const MPoly *mp; + const MLoop *ml; + int j; + + poly = poly_stack[ps_curr_idx++]; + BLI_assert(poly_groups[poly] == poly_group_id); + + mp = &mpoly[poly]; + for (ml = &mloop[mp->loopstart], j = mp->totloop; j--; ml++) { + /* loop over poly users */ + const MeshElemMap *map_ele = &edge_poly_map[ml->e]; + int *p = map_ele->indices; + int i = map_ele->count; + if (!(medge[ml->e].flag & ME_SHARP)) { + for (; i--; p++) { + /* if we meet other non initialized its a bug */ + BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id)); + + if (poly_groups[*p] == 0) { + poly_groups[*p] = poly_group_id; + poly_stack[ps_end_idx++] = *p; + } + } + } + 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 (!ELEM3(bit, 0, poly_group_id, poly_group_id_overflowed) && + !(bit_poly_group_mask & bit)) + { + bit_poly_group_mask |= bit; + } + } + } + } + } + /* And now, we have all our poly from current group in poly_stack (from 0 to (ps_end_idx - 1)), as well as + * all smoothgroups bits we can't use in bit_poly_group_mask. + */ + if (use_bitflags) { + int i, *p, gid_bit = 0; + poly_group_id = 1; + + /* Find first bit available! */ + for (; (poly_group_id & bit_poly_group_mask) && (gid_bit < 32); gid_bit++) { + poly_group_id <<= 1; /* will 'overflow' on last possible iteration. */ + } + if (UNLIKELY(gid_bit > 31)) { + /* All bits used in contiguous smooth groups, we can't do much! + * Note: this is *very* unlikely - theoretically, four groups are enough, I don't think we can reach + * this goal with such a simple algo, but I don't think either we'll never need all 32 groups! + */ + printf("Warning, could not find an available id for current smooth group, faces will me marked " + "as out of any smooth group...\n"); + poly_group_id = poly_group_id_overflowed; /* Can't use 0, will have to set them to this value later. */ + group_id_overflow = true; + } + if (gid_bit > tot_group) { + tot_group = gid_bit; + } + /* And assign the final smooth group id to that poly group! */ + for (i = ps_end_idx, p = poly_stack; i--; p++) { + poly_groups[*p] = poly_group_id; + } + } + } + + if (UNLIKELY(group_id_overflow)) { + int i = totpoly, *gid = poly_groups; + for (; i--; gid++) { + if (*gid == poly_group_id_overflowed) { + *gid = 0; + } + } + } + + MEM_freeN(edge_poly_map); + MEM_freeN(edge_poly_mem); + MEM_freeN(poly_stack); + + *r_totgroup = tot_group + 1; + + return poly_groups; +} +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Mesh Spatial Calculation + * \{ */ + +/** + * This function takes the difference between 2 vertex-coord-arrays + * (\a vert_cos_src, \a vert_cos_dst), + * and applies the difference to \a vert_cos_new relative to \a vert_cos_org. + * + * \param vert_cos_src reference deform source. + * \param vert_cos_dst reference deform destination. + * + * \param vert_cos_org reference for the output location. + * \param vert_cos_new resulting coords. + */ +void BKE_mesh_calc_relative_deform( + const MPoly *mpoly, const int totpoly, + const MLoop *mloop, const int totvert, + + const float (*vert_cos_src)[3], + const float (*vert_cos_dst)[3], + + const float (*vert_cos_org)[3], + float (*vert_cos_new)[3]) +{ + const MPoly *mp; + int i; + + int *vert_accum = MEM_callocN(sizeof(*vert_accum) * (size_t)totvert, __func__); + + memset(vert_cos_new, '\0', sizeof(*vert_cos_new) * (size_t)totvert); + + for (i = 0, mp = mpoly; i < totpoly; i++, mp++) { + const MLoop *loopstart = mloop + mp->loopstart; + int j; + + for (j = 0; j < mp->totloop; j++) { + unsigned int v_prev = loopstart[(mp->totloop + (j - 1)) % mp->totloop].v; + unsigned int v_curr = loopstart[j].v; + unsigned int v_next = loopstart[(j + 1) % mp->totloop].v; + + float tvec[3]; + + barycentric_transform( + tvec, vert_cos_dst[v_curr], + vert_cos_org[v_prev], vert_cos_org[v_curr], vert_cos_org[v_next], + vert_cos_src[v_prev], vert_cos_src[v_curr], vert_cos_src[v_next] + ); + + add_v3_v3(vert_cos_new[v_curr], tvec); + vert_accum[v_curr] += 1; + } + } + + for (i = 0; i < totvert; i++) { + if (vert_accum[i]) { + mul_v3_fl(vert_cos_new[i], 1.0f / (float)vert_accum[i]); + } + else { + copy_v3_v3(vert_cos_new[i], vert_cos_org[i]); + } + } + + MEM_freeN(vert_accum); +} +/** \} */ diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index 2eced15a147..1c9576d74d0 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -49,7 +49,12 @@ #include "MEM_guardedalloc.h" -#define SELECT 1 +/* loop v/e are unsigned, so using max uint_32 value as invalid marker... */ +#define INVALID_LOOP_EDGE_MARKER 4294967295u + + +/** \name Internal functions + * \{ */ typedef union { uint32_t verts[2]; @@ -181,17 +186,37 @@ static int search_polyloop_cmp(const void *v1, const void *v2) /* Else, sort on loopstart. */ return sp1->loopstart > sp2->loopstart ? 1 : sp1->loopstart < sp2->loopstart ? -1 : 0; } +/** \} */ + + + +/* -------------------------------------------------------------------- */ -#define PRINT if (do_verbose) printf +/** \name Mesh Validation + * \{ */ -int BKE_mesh_validate_arrays(Mesh *mesh, - MVert *mverts, unsigned int totvert, - MEdge *medges, unsigned int totedge, - MFace *mfaces, unsigned int totface, - MLoop *mloops, unsigned int totloop, - MPoly *mpolys, unsigned int totpoly, - MDeformVert *dverts, /* assume totvert length */ - const bool do_verbose, const bool do_fixes) +#define PRINT_MSG(...) (void) \ + ( \ + ((do_verbose) ? printf(__VA_ARGS__) : 0)) + +#define PRINT_ERR(...) (void) \ + (is_valid = false, \ + ((do_verbose) ? printf(__VA_ARGS__) : 0)) + +/** + * Validate the mesh, \a do_fixes requires \a mesh to be non-null. + * + * \return false if no changes needed to be made. + */ +bool BKE_mesh_validate_arrays(Mesh *mesh, + MVert *mverts, unsigned int totvert, + MEdge *medges, unsigned int totedge, + MFace *mfaces, unsigned int totface, + MLoop *mloops, unsigned int totloop, + MPoly *mpolys, unsigned int totpoly, + MDeformVert *dverts, /* assume totvert length */ + const bool do_verbose, const bool do_fixes, + bool *r_change) { # define REMOVE_EDGE_TAG(_me) { _me->v2 = _me->v1; do_edge_free = true; } (void)0 # define IS_REMOVED_EDGE(_me) (_me->v2 == _me->v1) @@ -206,6 +231,8 @@ int BKE_mesh_validate_arrays(Mesh *mesh, unsigned int i, j; int *v; + bool is_valid = true; + bool do_edge_free = false; bool do_face_free = false; bool do_polyloop_free = false; /* This regroups loops and polys! */ @@ -216,15 +243,15 @@ int BKE_mesh_validate_arrays(Mesh *mesh, bool do_edge_recalc = false; - EdgeHash *edge_hash = BLI_edgehash_new(); + EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, totedge); BLI_assert(!(do_fixes && mesh == NULL)); - PRINT("%s: verts(%u), edges(%u), loops(%u), polygons(%u)\n", - __func__, totvert, totedge, totloop, totpoly); + PRINT_MSG("%s: verts(%u), edges(%u), loops(%u), polygons(%u)\n", + __func__, totvert, totedge, totloop, totpoly); if (totedge == 0 && totpoly != 0) { - PRINT("\tLogical error, %u polygons and 0 edges\n", totpoly); + PRINT_ERR("\tLogical error, %u polygons and 0 edges\n", totpoly); do_edge_recalc = do_fixes; } @@ -233,7 +260,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh, for (j = 0; j < 3; j++) { if (!finite(mv->co[j])) { - PRINT("\tVertex %u: has invalid coordinate\n", i); + PRINT_ERR("\tVertex %u: has invalid coordinate\n", i); if (do_fixes) { zero_v3(mv->co); @@ -247,7 +274,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh, } if (fix_normal) { - PRINT("\tVertex %u: has zero normal, assuming Z-up normal\n", i); + PRINT_ERR("\tVertex %u: has zero normal, assuming Z-up normal\n", i); if (do_fixes) { mv->no[2] = SHRT_MAX; verts_fixed = TRUE; @@ -258,21 +285,21 @@ int BKE_mesh_validate_arrays(Mesh *mesh, for (i = 0, me = medges; i < totedge; i++, me++) { int remove = FALSE; if (me->v1 == me->v2) { - PRINT("\tEdge %u: has matching verts, both %u\n", i, me->v1); + PRINT_ERR("\tEdge %u: has matching verts, both %u\n", i, me->v1); remove = do_fixes; } if (me->v1 >= totvert) { - PRINT("\tEdge %u: v1 index out of range, %u\n", i, me->v1); + PRINT_ERR("\tEdge %u: v1 index out of range, %u\n", i, me->v1); remove = do_fixes; } if (me->v2 >= totvert) { - PRINT("\tEdge %u: v2 index out of range, %u\n", i, me->v2); + PRINT_ERR("\tEdge %u: v2 index out of range, %u\n", i, me->v2); remove = do_fixes; } if (BLI_edgehash_haskey(edge_hash, me->v1, me->v2)) { - PRINT("\tEdge %u: is a duplicate of %d\n", i, - GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, me->v1, me->v2))); + PRINT_ERR("\tEdge %u: is a duplicate of %d\n", i, + GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, me->v1, me->v2))); remove = do_fixes; } @@ -288,13 +315,13 @@ int BKE_mesh_validate_arrays(Mesh *mesh, # define REMOVE_FACE_TAG(_mf) { _mf->v3 = 0; do_face_free = TRUE; } (void)0 # define CHECK_FACE_VERT_INDEX(a, b) \ if (mf->a == mf->b) { \ - PRINT(" face %u: verts invalid, " STRINGIFY(a) "/" STRINGIFY(b) " both %u\n", i, mf->a); \ + PRINT_ERR(" face %u: verts invalid, " STRINGIFY(a) "/" STRINGIFY(b) " both %u\n", i, mf->a); \ remove = do_fixes; \ } (void)0 # define CHECK_FACE_EDGE(a, b) \ if (!BLI_edgehash_haskey(edge_hash, mf->a, mf->b)) { \ - PRINT(" face %u: edge " STRINGIFY(a) "/" STRINGIFY(b) \ - " (%u,%u) is missing edge data\n", i, mf->a, mf->b); \ + PRINT_ERR(" face %u: edge " STRINGIFY(a) "/" STRINGIFY(b) \ + " (%u,%u) is missing edge data\n", i, mf->a, mf->b); \ do_edge_recalc = TRUE; \ } (void)0 @@ -306,7 +333,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh, SortFace *sf_prev; unsigned int totsortface = 0; - PRINT("No Polys, only tesselated Faces\n"); + PRINT_ERR("No Polys, only tesselated Faces\n"); for (i = 0, mf = mfaces, sf = sort_faces; i < totface; i++, mf++) { int remove = FALSE; @@ -317,7 +344,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh, do { fv[fidx] = *(&(mf->v1) + fidx); if (fv[fidx] >= totvert) { - PRINT("\tFace %u: 'v%d' index out of range, %u\n", i, fidx + 1, fv[fidx]); + PRINT_ERR("\tFace %u: 'v%d' index out of range, %u\n", i, fidx + 1, fv[fidx]); remove = do_fixes; } } while (fidx--); @@ -394,14 +421,14 @@ int BKE_mesh_validate_arrays(Mesh *mesh, mf_prev = mfaces + sf_prev->index; if (mf->v4) { - PRINT("\tFace %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)\n", - sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf->v4, - mf_prev->v1, mf_prev->v2, mf_prev->v3, mf_prev->v4); + PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u,%u) (%u,%u,%u,%u)\n", + sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, mf->v4, + mf_prev->v1, mf_prev->v2, mf_prev->v3, mf_prev->v4); } else { - PRINT("\tFace %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)\n", - sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, - mf_prev->v1, mf_prev->v2, mf_prev->v3); + PRINT_ERR("\tFace %u & %u: are duplicates (%u,%u,%u) (%u,%u,%u)\n", + sf->index, sf_prev->index, mf->v1, mf->v2, mf->v3, + mf_prev->v1, mf_prev->v2, mf_prev->v3); } } @@ -446,13 +473,14 @@ int BKE_mesh_validate_arrays(Mesh *mesh, if (mp->loopstart < 0 || mp->totloop < 3) { /* Invalid loop data. */ - PRINT("\tPoly %u is invalid (loopstart: %u, totloop: %u)\n", sp->index, mp->loopstart, mp->totloop); + PRINT_ERR("\tPoly %u is invalid (loopstart: %u, totloop: %u)\n", + sp->index, mp->loopstart, mp->totloop); sp->invalid = TRUE; } else if (mp->loopstart + mp->totloop > totloop) { /* Invalid loop data. */ - PRINT("\tPoly %u uses loops out of range (loopstart: %u, loopend: %u, max nbr of loops: %u)\n", - sp->index, mp->loopstart, mp->loopstart + mp->totloop - 1, totloop - 1); + PRINT_ERR("\tPoly %u uses loops out of range (loopstart: %u, loopend: %u, max nbr of loops: %u)\n", + sp->index, mp->loopstart, mp->loopstart + mp->totloop - 1, totloop - 1); sp->invalid = TRUE; } else { @@ -467,7 +495,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh, for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++, v++) { if (ml->v >= totvert) { /* Invalid vert idx. */ - PRINT("\tLoop %u has invalid vert reference (%u)\n", sp->loopstart + j, ml->v); + PRINT_ERR("\tLoop %u has invalid vert reference (%u)\n", sp->loopstart + j, ml->v); sp->invalid = TRUE; } @@ -480,7 +508,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh, v = sp->verts; for (j = 0; j < mp->totloop; j++, v++) { if ((mverts[*v].flag & ME_VERT_TMP_TAG) == 0) { - PRINT("\tPoly %u has duplicate vert reference at corner (%u)\n", i, j); + PRINT_ERR("\tPoly %u has duplicate vert reference at corner (%u)\n", i, j); sp->invalid = TRUE; } mverts[*v].flag &= ~ME_VERT_TMP_TAG; @@ -496,7 +524,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh, v2 = mloops[sp->loopstart + (j + 1) % mp->totloop].v; if (!BLI_edgehash_haskey(edge_hash, v1, v2)) { /* Edge not existing. */ - PRINT("\tPoly %u needs missing edge (%u, %u)\n", sp->index, v1, v2); + PRINT_ERR("\tPoly %u needs missing edge (%u, %u)\n", sp->index, v1, v2); if (do_fixes) do_edge_recalc = TRUE; else @@ -508,11 +536,11 @@ int BKE_mesh_validate_arrays(Mesh *mesh, if (do_fixes) { int prev_e = ml->e; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2)); - PRINT("\tLoop %u has invalid edge reference (%u), fixed using edge %u\n", - sp->loopstart + j, prev_e, ml->e); + PRINT_ERR("\tLoop %u has invalid edge reference (%u), fixed using edge %u\n", + sp->loopstart + j, prev_e, ml->e); } else { - PRINT("\tLoop %u has invalid edge reference (%u)\n", sp->loopstart + j, ml->e); + PRINT_ERR("\tLoop %u has invalid edge reference (%u)\n", sp->loopstart + j, ml->e); sp->invalid = TRUE; } } @@ -524,11 +552,11 @@ int BKE_mesh_validate_arrays(Mesh *mesh, if (do_fixes) { int prev_e = ml->e; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2)); - PRINT("\tPoly %u has invalid edge reference (%u), fixed using edge %u\n", - sp->index, prev_e, ml->e); + PRINT_ERR("\tPoly %u has invalid edge reference (%u), fixed using edge %u\n", + sp->index, prev_e, ml->e); } else { - PRINT("\tPoly %u has invalid edge reference (%u)\n", sp->index, ml->e); + PRINT_ERR("\tPoly %u has invalid edge reference (%u)\n", sp->index, ml->e); sp->invalid = TRUE; } } @@ -546,16 +574,16 @@ int BKE_mesh_validate_arrays(Mesh *mesh, if (*v != *prev_v) { int dlt = v - prev_v; if (dlt > 1) { - PRINT("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n", - sp->index, *prev_v, dlt); + PRINT_ERR("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n", + sp->index, *prev_v, dlt); sp->invalid = TRUE; } prev_v = v; } } if (v - prev_v > 1) { /* Don't forget final verts! */ - PRINT("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n", - sp->index, *prev_v, (int)(v - prev_v)); + PRINT_ERR("\tPoly %u is invalid, it multi-uses vertex %u (%u times)\n", + sp->index, *prev_v, (int)(v - prev_v)); sp->invalid = TRUE; } } @@ -633,11 +661,14 @@ int BKE_mesh_validate_arrays(Mesh *mesh, } if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv * sizeof(*p1_v)) == 0)) { if (do_verbose) { - PRINT("\tPolys %u and %u use same vertices (%u", - prev_sp->index, sp->index, *p1_v); + PRINT_ERR("\tPolys %u and %u use same vertices (%u", + prev_sp->index, sp->index, *p1_v); for (j = 1; j < p1_nv; j++) - PRINT(", %u", p1_v[j]); - PRINT("), considering poly %u as invalid.\n", sp->index); + PRINT_ERR(", %u", p1_v[j]); + PRINT_ERR("), considering poly %u as invalid.\n", sp->index); + } + else { + is_valid = false; } sp->invalid = TRUE; } @@ -673,7 +704,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh, /* Unused loops. */ if (prev_end < sp->loopstart) { for (j = prev_end, ml = &mloops[prev_end]; j < sp->loopstart; j++, ml++) { - PRINT("\tLoop %u is unused.\n", j); + PRINT_ERR("\tLoop %u is unused.\n", j); if (do_fixes) REMOVE_LOOP_TAG(ml); } @@ -682,8 +713,8 @@ int BKE_mesh_validate_arrays(Mesh *mesh, } /* Multi-used loops. */ else if (prev_end > sp->loopstart) { - PRINT("\tPolys %u and %u share loops from %u to %u, considering poly %u as invalid.\n", - prev_sp->index, sp->index, sp->loopstart, prev_end, sp->index); + PRINT_ERR("\tPolys %u and %u share loops from %u to %u, considering poly %u as invalid.\n", + prev_sp->index, sp->index, sp->loopstart, prev_end, sp->index); if (do_fixes) { REMOVE_POLY_TAG((&mpolys[sp->index])); /* DO NOT REMOVE ITS LOOPS!!! @@ -701,7 +732,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh, /* We may have some remaining unused loops to get rid of! */ if (prev_end < totloop) { for (j = prev_end, ml = &mloops[prev_end]; j < totloop; j++, ml++) { - PRINT("\tLoop %u is unused.\n", j); + PRINT_ERR("\tLoop %u is unused.\n", j); if (do_fixes) REMOVE_LOOP_TAG(ml); } @@ -721,14 +752,14 @@ int BKE_mesh_validate_arrays(Mesh *mesh, 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 */ if (!finite(dw->weight)) { - PRINT("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight); + PRINT_ERR("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight); if (do_fixes) { dw->weight = 0.0f; vert_weights_fixed = TRUE; } } else if (dw->weight < 0.0f || dw->weight > 1.0f) { - PRINT("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight); + PRINT_ERR("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight); if (do_fixes) { CLAMP(dw->weight, 0.0f, 1.0f); vert_weights_fixed = TRUE; @@ -736,7 +767,7 @@ int BKE_mesh_validate_arrays(Mesh *mesh, } if (dw->def_nr < 0) { - PRINT("\tVertex deform %u, has invalid group %d\n", i, dw->def_nr); + PRINT_ERR("\tVertex deform %u, has invalid group %d\n", i, dw->def_nr); if (do_fixes) { defvert_remove_group(dv, dw); if (dv->dw) { @@ -787,8 +818,8 @@ int BKE_mesh_validate_arrays(Mesh *mesh, int tot_elem = 0; if (msel->index < 0) { - PRINT("\tMesh select element %d type %d index is negative, " - "resetting selection stack.\n", i, msel->type); + PRINT_ERR("\tMesh select element %d type %d index is negative, " + "resetting selection stack.\n", i, msel->type); free_msel = TRUE; break; } @@ -806,8 +837,8 @@ int BKE_mesh_validate_arrays(Mesh *mesh, } if (msel->index > tot_elem) { - PRINT("\tMesh select element %d type %d index %d is larger than data array size %d, " - "resetting selection stack.\n", i, msel->type, msel->index, tot_elem); + PRINT_ERR("\tMesh select element %d type %d index %d is larger than data array size %d, " + "resetting selection stack.\n", i, msel->type, msel->index, tot_elem); free_msel = TRUE; break; @@ -821,29 +852,49 @@ int BKE_mesh_validate_arrays(Mesh *mesh, } } - PRINT("%s: finished\n\n", __func__); + PRINT_MSG("%s: finished\n\n", __func__); + + *r_change = (verts_fixed || vert_weights_fixed || do_polyloop_free || do_edge_free || do_edge_recalc || msel_fixed); - return (verts_fixed || vert_weights_fixed || do_polyloop_free || do_edge_free || do_edge_recalc || msel_fixed); + return is_valid; } -static int mesh_validate_customdata(CustomData *data, const bool do_verbose, const bool do_fixes) +static bool mesh_validate_customdata(CustomData *data, CustomDataMask mask, + const bool do_verbose, const bool do_fixes, + bool *r_change) { - int i = 0, has_fixes = 0; + bool is_valid = true; + bool has_fixes = false; + int i = 0; - PRINT("%s: Checking %d CD layers...\n", __func__, data->totlayer); + PRINT_MSG("%s: Checking %d CD layers...\n", __func__, data->totlayer); while (i < data->totlayer) { CustomDataLayer *layer = &data->layers[i]; - CustomDataMask mask = CD_TYPE_AS_MASK(layer->type); - int ok = 1; + bool ok = true; + + if (CustomData_layertype_is_singleton(layer->type)) { + const int layer_tot = CustomData_number_of_layers(data, layer->type); + if (layer_tot > 1) { + PRINT_ERR("\tCustomDataLayer type %d is a singleton, found %d in Mesh structure\n", + layer->type, layer_tot); + ok = false; + } + } - if ((mask & CD_MASK_MESH) == 0) { - PRINT("\tCustomDataLayer type %d which isn't in CD_MASK_MESH is stored in Mesh structure\n", layer->type); + if (mask != 0) { + CustomDataMask layer_typemask = CD_TYPE_AS_MASK(layer->type); + if ((layer_typemask & mask) == 0) { + PRINT_ERR("\tCustomDataLayer type %d which isn't in the mask\n", + layer->type); + ok = false; + } + } + if (ok == false) { if (do_fixes) { CustomData_free_layer(data, layer->type, 0, i); - ok = 0; - has_fixes = 1; + has_fixes = true; } } @@ -851,65 +902,455 @@ static int mesh_validate_customdata(CustomData *data, const bool do_verbose, con i++; } - PRINT("%s: Finished\n\n", __func__); + PRINT_MSG("%s: Finished (is_valid=%d)\n\n", __func__, (int)!has_fixes); - return has_fixes; + *r_change = has_fixes; + + return is_valid; } #undef PRINT -static int BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata, - CustomData *ldata, CustomData *pdata, - const bool do_verbose, const short do_fixes) +/** + * \returns is_valid. + */ +bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata, + CustomData *ldata, CustomData *pdata, + const bool check_meshmask, + const bool do_verbose, const bool do_fixes, + bool *r_change) { - int vfixed = 0, efixed = 0, lfixed = 0, pfixed = 0; + bool is_valid = true; + bool is_change_v, is_change_e, is_change_l, is_change_p; + int tot_texpoly, tot_uvloop; + CustomDataMask mask = check_meshmask ? CD_MASK_MESH : 0; + + is_valid &= mesh_validate_customdata(vdata, mask, do_verbose, do_fixes, &is_change_v); + is_valid &= mesh_validate_customdata(edata, mask, do_verbose, do_fixes, &is_change_e); + is_valid &= mesh_validate_customdata(ldata, mask, do_verbose, do_fixes, &is_change_l); + is_valid &= mesh_validate_customdata(pdata, mask, do_verbose, do_fixes, &is_change_p); + + tot_texpoly = CustomData_number_of_layers(pdata, CD_MTEXPOLY); + tot_uvloop = CustomData_number_of_layers(ldata, CD_MLOOPUV); + if (tot_texpoly != tot_uvloop) { + PRINT_ERR("\tCustomDataLayer mismatch, tot_texpoly(%d), tot_uvloop(%d)\n", + tot_texpoly, tot_uvloop); + } - vfixed = mesh_validate_customdata(vdata, do_verbose, do_fixes); - efixed = mesh_validate_customdata(edata, do_verbose, do_fixes); - lfixed = mesh_validate_customdata(ldata, do_verbose, do_fixes); - pfixed = mesh_validate_customdata(pdata, do_verbose, do_fixes); + *r_change = (is_change_v || is_change_e || is_change_l || is_change_p); - return vfixed || efixed || lfixed || pfixed; + return is_valid; } +/** + * \see #DM_is_valid to call on derived meshes + * + * \returns true if a change is made. + */ int BKE_mesh_validate(Mesh *me, const int do_verbose) { - int layers_fixed = 0, arrays_fixed = 0; + bool is_valid = true; + bool is_change; if (do_verbose) { printf("MESH: %s\n", me->id.name + 2); } - layers_fixed = BKE_mesh_validate_all_customdata(&me->vdata, &me->edata, &me->ldata, &me->pdata, do_verbose, TRUE); - arrays_fixed = BKE_mesh_validate_arrays(me, - me->mvert, me->totvert, - me->medge, me->totedge, - me->mface, me->totface, - me->mloop, me->totloop, - me->mpoly, me->totpoly, - me->dvert, - do_verbose, true); - - if (layers_fixed || arrays_fixed) { + is_valid &= BKE_mesh_validate_all_customdata( + &me->vdata, &me->edata, &me->ldata, &me->pdata, + true, + do_verbose, true, + &is_change); + + is_valid &= BKE_mesh_validate_arrays( + me, + me->mvert, me->totvert, + me->medge, me->totedge, + me->mface, me->totface, + me->mloop, me->totloop, + me->mpoly, me->totpoly, + me->dvert, + do_verbose, true, + &is_change); + + if (is_change) { DAG_id_tag_update(&me->id, OB_RECALC_DATA); return true; } - return false; + else { + return false; + } +} + +/** + * Duplicate of BM_mesh_cd_validate() for Mesh data. + */ +void BKE_mesh_cd_validate(Mesh *me) +{ + int totlayer_mtex = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY); + int totlayer_uv = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV); + int mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY); + int uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV); + int i; + + if (LIKELY(totlayer_mtex == totlayer_uv)) { + /* pass */ + } + else if (totlayer_mtex < totlayer_uv) { + do { + const char *from_name = me->ldata.layers[uv_index + totlayer_mtex].name; + CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, from_name); + CustomData_set_layer_unique_name(&me->pdata, totlayer_mtex); + } while (totlayer_uv != ++totlayer_mtex); + mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY); + } + else if (totlayer_uv < totlayer_mtex) { + do { + const char *from_name = me->pdata.layers[mtex_index + totlayer_uv].name; + CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, from_name); + CustomData_set_layer_unique_name(&me->ldata, totlayer_uv); + } while (totlayer_mtex != ++totlayer_uv); + uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV); + } + + BLI_assert(totlayer_mtex == totlayer_uv); + + /* Check uv/tex names match as well!!! */ + for (i = 0; i < totlayer_mtex; i++, mtex_index++, uv_index++) { + const char *name_src = me->pdata.layers[mtex_index].name; + const char *name_dst = me->ldata.layers[uv_index].name; + if (!STREQ(name_src, name_dst)) { + BKE_mesh_uv_cdlayer_rename_index(me, mtex_index, uv_index, -1, name_src, false); + } + } +} +/** \} */ + + + +/* -------------------------------------------------------------------- */ + +/** \name Mesh Stripping (removing invalid data) + * \{ */ + +/* We need to keep this for edge creation (for now?), and some old readfile code... */ +void BKE_mesh_strip_loose_faces(Mesh *me) +{ + MFace *f; + int a, b; + + for (a = b = 0, f = me->mface; a < me->totface; a++, f++) { + if (f->v3) { + if (a != b) { + memcpy(&me->mface[b], f, sizeof(me->mface[b])); + CustomData_copy_data(&me->fdata, &me->fdata, a, b, 1); + } + b++; + } + } + if (a != b) { + CustomData_free_elem(&me->fdata, b, a - b); + me->totface = b; + } +} + +/* Works on both loops and polys! */ +/* Note: It won't try to guess which loops of an invalid poly to remove! + * this is the work of the caller, to mark those loops... + * See e.g. BKE_mesh_validate_arrays(). */ +void BKE_mesh_strip_loose_polysloops(Mesh *me) +{ + MPoly *p; + MLoop *l; + int a, b; + /* New loops idx! */ + int *new_idx = MEM_mallocN(sizeof(int) * me->totloop, __func__); + + for (a = b = 0, p = me->mpoly; a < me->totpoly; a++, p++) { + int invalid = FALSE; + int i = p->loopstart; + int stop = i + p->totloop; + + if (stop > me->totloop || stop < i) { + invalid = TRUE; + } + else { + l = &me->mloop[i]; + i = stop - i; + /* If one of the poly's loops is invalid, the whole poly is invalid! */ + for (; i--; l++) { + if (l->e == INVALID_LOOP_EDGE_MARKER) { + invalid = TRUE; + break; + } + } + } + + if (p->totloop >= 3 && !invalid) { + if (a != b) { + memcpy(&me->mpoly[b], p, sizeof(me->mpoly[b])); + CustomData_copy_data(&me->pdata, &me->pdata, a, b, 1); + } + b++; + } + } + if (a != b) { + CustomData_free_elem(&me->pdata, b, a - b); + me->totpoly = b; + } + + /* And now, get rid of invalid loops. */ + for (a = b = 0, l = me->mloop; a < me->totloop; a++, l++) { + if (l->e != INVALID_LOOP_EDGE_MARKER) { + if (a != b) { + memcpy(&me->mloop[b], l, sizeof(me->mloop[b])); + CustomData_copy_data(&me->ldata, &me->ldata, a, b, 1); + } + new_idx[a] = b; + b++; + } + else { + /* XXX Theoretically, we should be able to not do this, as no remaining poly + * should use any stripped loop. But for security's sake... */ + new_idx[a] = -a; + } + } + if (a != b) { + CustomData_free_elem(&me->ldata, b, a - b); + me->totloop = b; + } + + /* And now, update polys' start loop index. */ + /* Note: At this point, there should never be any poly using a striped loop! */ + for (a = 0, p = me->mpoly; a < me->totpoly; a++, p++) { + p->loopstart = new_idx[p->loopstart]; + } + + MEM_freeN(new_idx); +} + +void BKE_mesh_strip_loose_edges(Mesh *me) +{ + MEdge *e; + MLoop *l; + int a, b; + unsigned int *new_idx = MEM_mallocN(sizeof(int) * me->totedge, __func__); + + for (a = b = 0, e = me->medge; a < me->totedge; a++, e++) { + if (e->v1 != e->v2) { + if (a != b) { + memcpy(&me->medge[b], e, sizeof(me->medge[b])); + CustomData_copy_data(&me->edata, &me->edata, a, b, 1); + } + new_idx[a] = b; + b++; + } + else { + new_idx[a] = INVALID_LOOP_EDGE_MARKER; + } + } + if (a != b) { + CustomData_free_elem(&me->edata, b, a - b); + me->totedge = b; + } + + /* And now, update loops' edge indices. */ + /* XXX We hope no loop was pointing to a striped edge! + * Else, its e will be set to INVALID_LOOP_EDGE_MARKER :/ */ + for (a = 0, l = me->mloop; a < me->totloop; a++, l++) { + l->e = new_idx[l->e]; + } + + MEM_freeN(new_idx); +} +/** \} */ + + + +/* -------------------------------------------------------------------- */ + +/** \name Mesh Edge Calculation + * \{ */ + +/* make edges in a Mesh, for outside of editmode */ + +struct EdgeSort { + unsigned int v1, v2; + char is_loose, is_draw; +}; + +/* edges have to be added with lowest index first for sorting */ +static void to_edgesort(struct EdgeSort *ed, + unsigned int v1, unsigned int v2, + char is_loose, short is_draw) +{ + if (v1 < v2) { + ed->v1 = v1; ed->v2 = v2; + } + else { + ed->v1 = v2; ed->v2 = v1; + } + ed->is_loose = is_loose; + ed->is_draw = is_draw; } -int BKE_mesh_validate_dm(DerivedMesh *dm) +static int vergedgesort(const void *v1, const void *v2) { - return BKE_mesh_validate_arrays(NULL, - dm->getVertArray(dm), dm->getNumVerts(dm), - dm->getEdgeArray(dm), dm->getNumEdges(dm), - dm->getTessFaceArray(dm), dm->getNumTessFaces(dm), - dm->getLoopArray(dm), dm->getNumLoops(dm), - dm->getPolyArray(dm), dm->getNumPolys(dm), - dm->getVertDataArray(dm, CD_MDEFORMVERT), - TRUE, FALSE); + const struct EdgeSort *x1 = v1, *x2 = v2; + + if (x1->v1 > x2->v1) return 1; + else if (x1->v1 < x2->v1) return -1; + else if (x1->v2 > x2->v2) return 1; + else if (x1->v2 < x2->v2) return -1; + + return 0; +} + + +/* Create edges based on known verts and faces, + * this function is only used when loading very old blend files */ + +static void mesh_calc_edges_mdata( + MVert *UNUSED(allvert), MFace *allface, MLoop *allloop, + MPoly *allpoly, int UNUSED(totvert), int totface, int UNUSED(totloop), int totpoly, + const bool use_old, + MEdge **r_medge, int *r_totedge) +{ + MPoly *mpoly; + MFace *mface; + MEdge *medge, *med; + EdgeHash *hash; + struct EdgeSort *edsort, *ed; + int a, totedge = 0; + unsigned int totedge_final = 0; + unsigned int edge_index; + + /* we put all edges in array, sort them, and detect doubles that way */ + + for (a = totface, mface = allface; a > 0; a--, mface++) { + if (mface->v4) totedge += 4; + else if (mface->v3) totedge += 3; + else totedge += 1; + } + + if (totedge == 0) { + /* flag that mesh has edges */ + (*r_medge) = MEM_callocN(0, __func__); + (*r_totedge) = 0; + return; + } + + ed = edsort = MEM_mallocN(totedge * sizeof(struct EdgeSort), "EdgeSort"); + + for (a = totface, mface = allface; a > 0; a--, mface++) { + to_edgesort(ed++, mface->v1, mface->v2, !mface->v3, mface->edcode & ME_V1V2); + if (mface->v4) { + to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3); + to_edgesort(ed++, mface->v3, mface->v4, 0, mface->edcode & ME_V3V4); + to_edgesort(ed++, mface->v4, mface->v1, 0, mface->edcode & ME_V4V1); + } + else if (mface->v3) { + to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3); + to_edgesort(ed++, mface->v3, mface->v1, 0, mface->edcode & ME_V3V1); + } + } + + qsort(edsort, totedge, sizeof(struct EdgeSort), vergedgesort); + + /* count final amount */ + for (a = totedge, ed = edsort; a > 1; a--, ed++) { + /* edge is unique when it differs from next edge, or is last */ + if (ed->v1 != (ed + 1)->v1 || ed->v2 != (ed + 1)->v2) totedge_final++; + } + totedge_final++; + + medge = MEM_callocN(sizeof(MEdge) * totedge_final, __func__); + + for (a = totedge, med = medge, ed = edsort; a > 1; a--, ed++) { + /* edge is unique when it differs from next edge, or is last */ + if (ed->v1 != (ed + 1)->v1 || ed->v2 != (ed + 1)->v2) { + med->v1 = ed->v1; + med->v2 = ed->v2; + if (use_old == false || ed->is_draw) med->flag = ME_EDGEDRAW | ME_EDGERENDER; + if (ed->is_loose) med->flag |= ME_LOOSEEDGE; + + /* order is swapped so extruding this edge as a surface wont flip face normals + * with cyclic curves */ + if (ed->v1 + 1 != ed->v2) { + SWAP(unsigned int, med->v1, med->v2); + } + med++; + } + else { + /* equal edge, we merge the drawflag */ + (ed + 1)->is_draw |= ed->is_draw; + } + } + /* last edge */ + med->v1 = ed->v1; + med->v2 = ed->v2; + med->flag = ME_EDGEDRAW; + if (ed->is_loose) med->flag |= ME_LOOSEEDGE; + med->flag |= ME_EDGERENDER; + + MEM_freeN(edsort); + + /* set edge members of mloops */ + hash = BLI_edgehash_new_ex(__func__, totedge_final); + for (edge_index = 0, med = medge; edge_index < totedge_final; edge_index++, med++) { + BLI_edgehash_insert(hash, med->v1, med->v2, SET_UINT_IN_POINTER(edge_index)); + } + + mpoly = allpoly; + for (a = 0; a < totpoly; a++, mpoly++) { + MLoop *ml, *ml_next; + int i = mpoly->totloop; + + ml_next = allloop + mpoly->loopstart; /* first loop */ + ml = &ml_next[i - 1]; /* last loop */ + + while (i-- != 0) { + ml->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(hash, ml->v, ml_next->v)); + ml = ml_next; + ml_next++; + } + } + + BLI_edgehash_free(hash, NULL); + + *r_medge = medge; + *r_totedge = totedge_final; } /** + * If the mesh is from a very old blender version, + * convert mface->edcode to edge drawflags + */ +void BKE_mesh_calc_edges_legacy(Mesh *me, const bool use_old) +{ + MEdge *medge; + int totedge = 0; + + mesh_calc_edges_mdata(me->mvert, me->mface, me->mloop, me->mpoly, + me->totvert, me->totface, me->totloop, me->totpoly, + use_old, &medge, &totedge); + + if (totedge == 0) { + /* flag that mesh has edges */ + me->medge = medge; + me->totedge = 0; + return; + } + + medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, totedge); + me->medge = medge; + me->totedge = totedge; + + BKE_mesh_strip_loose_faces(me); +} + + +/** * Calculate edges from polygons * * \param mesh The mesh to add edges into @@ -921,7 +1362,8 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select) EdgeHashIterator *ehi; MPoly *mp; MEdge *med, *med_orig; - EdgeHash *eh = BLI_edgehash_new(); + EdgeHash *eh; + unsigned int eh_reserve; int i, totedge, totpoly = mesh->totpoly; int med_index; /* select for newly created meshes which are selected [#25595] */ @@ -930,6 +1372,9 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select) if (mesh->totedge == 0) update = false; + eh_reserve = max_ii(update ? mesh->totedge : 0, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totpoly)); + eh = BLI_edgehash_new_ex(__func__, eh_reserve); + if (update) { /* assume existing edges are valid * useful when adding more faces and generating edges from them */ @@ -999,3 +1444,4 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select) BLI_edgehash_free(eh, NULL); } +/** \} */ diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 41e0acf9f7a..4871b9bf3bf 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -69,19 +69,44 @@ #include "MOD_modifiertypes.h" -ModifierTypeInfo *modifierType_getInfo(ModifierType type) +static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {NULL}; +static VirtualModifierData virtualModifierCommonData; + +void BKE_modifier_init(void) { - static ModifierTypeInfo *types[NUM_MODIFIER_TYPES] = {NULL}; - static int types_init = 1; + ModifierData *md; - if (types_init) { - modifier_type_init(types); /* MOD_utils.c */ - types_init = 0; - } + /* Initialize modifier types */ + modifier_type_init(modifier_types); /* MOD_utils.c */ + + /* Initialize global cmmon storage used for virtual modifier list */ + md = modifier_new(eModifierType_Armature); + virtualModifierCommonData.amd = *((ArmatureModifierData *) md); + modifier_free(md); + + md = modifier_new(eModifierType_Curve); + virtualModifierCommonData.cmd = *((CurveModifierData *) md); + modifier_free(md); + + md = modifier_new(eModifierType_Lattice); + virtualModifierCommonData.lmd = *((LatticeModifierData *) md); + modifier_free(md); + md = modifier_new(eModifierType_ShapeKey); + virtualModifierCommonData.smd = *((ShapeKeyModifierData *) md); + modifier_free(md); + + virtualModifierCommonData.amd.modifier.mode |= eModifierMode_Virtual; + virtualModifierCommonData.cmd.modifier.mode |= eModifierMode_Virtual; + virtualModifierCommonData.lmd.modifier.mode |= eModifierMode_Virtual; + virtualModifierCommonData.smd.modifier.mode |= eModifierMode_Virtual; +} + +ModifierTypeInfo *modifierType_getInfo(ModifierType type) +{ /* type unsigned, no need to check < 0 */ - if (type < NUM_MODIFIER_TYPES && types[type]->name[0] != '\0') { - return types[type]; + if (type < NUM_MODIFIER_TYPES && modifier_types[type]->name[0] != '\0') { + return modifier_types[type]; } else { return NULL; @@ -289,7 +314,8 @@ void modifier_setError(ModifierData *md, const char *_format, ...) */ int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *lastPossibleCageIndex_r, int virtual_) { - ModifierData *md = (virtual_) ? modifiers_getVirtualModifierList(ob) : ob->modifiers.first; + VirtualModifierData virtualModifierData; + ModifierData *md = (virtual_) ? modifiers_getVirtualModifierList(ob, &virtualModifierData) : ob->modifiers.first; int i, cageIndex = -1; if (lastPossibleCageIndex_r) { @@ -435,74 +461,43 @@ ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, in /* NOTE: This is to support old files from before Blender supported modifiers, * in some cases versioning code updates these so for new files this will * return an empty list. */ -ModifierData *modifiers_getVirtualModifierList(Object *ob) +ModifierData *modifiers_getVirtualModifierList(Object *ob, VirtualModifierData *virtualModifierData) { - /* Kinda hacky, but should be fine since we are never - * re-entrant and avoid free hassles. - */ - static ArmatureModifierData amd; - static CurveModifierData cmd; - static LatticeModifierData lmd; - static ShapeKeyModifierData smd; - static int init = 1; ModifierData *md; - if (init) { - md = modifier_new(eModifierType_Armature); - amd = *((ArmatureModifierData *) md); - modifier_free(md); - - md = modifier_new(eModifierType_Curve); - cmd = *((CurveModifierData *) md); - modifier_free(md); - - md = modifier_new(eModifierType_Lattice); - lmd = *((LatticeModifierData *) md); - modifier_free(md); - - md = modifier_new(eModifierType_ShapeKey); - smd = *((ShapeKeyModifierData *) md); - modifier_free(md); - - amd.modifier.mode |= eModifierMode_Virtual; - cmd.modifier.mode |= eModifierMode_Virtual; - lmd.modifier.mode |= eModifierMode_Virtual; - smd.modifier.mode |= eModifierMode_Virtual; - - init = 0; - } - md = ob->modifiers.first; + *virtualModifierData = virtualModifierCommonData; + if (ob->parent) { if (ob->parent->type == OB_ARMATURE && ob->partype == PARSKEL) { - amd.object = ob->parent; - amd.modifier.next = md; - amd.deformflag = ((bArmature *)(ob->parent->data))->deformflag; - md = &amd.modifier; + virtualModifierData->amd.object = ob->parent; + virtualModifierData->amd.modifier.next = md; + virtualModifierData->amd.deformflag = ((bArmature *)(ob->parent->data))->deformflag; + md = &virtualModifierData->amd.modifier; } else if (ob->parent->type == OB_CURVE && ob->partype == PARSKEL) { - cmd.object = ob->parent; - cmd.defaxis = ob->trackflag + 1; - cmd.modifier.next = md; - md = &cmd.modifier; + virtualModifierData->cmd.object = ob->parent; + virtualModifierData->cmd.defaxis = ob->trackflag + 1; + virtualModifierData->cmd.modifier.next = md; + md = &virtualModifierData->cmd.modifier; } else if (ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) { - lmd.object = ob->parent; - lmd.modifier.next = md; - md = &lmd.modifier; + virtualModifierData->lmd.object = ob->parent; + virtualModifierData->lmd.modifier.next = md; + md = &virtualModifierData->lmd.modifier; } } /* shape key modifier, not yet for curves */ if (ELEM(ob->type, OB_MESH, OB_LATTICE) && BKE_key_from_object(ob)) { if (ob->type == OB_MESH && (ob->shapeflag & OB_SHAPE_EDIT_MODE)) - smd.modifier.mode |= eModifierMode_Editmode | eModifierMode_OnCage; + virtualModifierData->smd.modifier.mode |= eModifierMode_Editmode | eModifierMode_OnCage; else - smd.modifier.mode &= ~eModifierMode_Editmode | eModifierMode_OnCage; + virtualModifierData->smd.modifier.mode &= ~eModifierMode_Editmode | eModifierMode_OnCage; - smd.modifier.next = md; - md = &smd.modifier; + virtualModifierData->smd.modifier.next = md; + md = &virtualModifierData->smd.modifier; } return md; @@ -513,7 +508,8 @@ ModifierData *modifiers_getVirtualModifierList(Object *ob) */ Object *modifiers_isDeformedByArmature(Object *ob) { - ModifierData *md = modifiers_getVirtualModifierList(ob); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); ArmatureModifierData *amd = NULL; /* return the first selected armature, this lets us use multiple armatures */ @@ -536,7 +532,8 @@ Object *modifiers_isDeformedByArmature(Object *ob) */ Object *modifiers_isDeformedByLattice(Object *ob) { - ModifierData *md = modifiers_getVirtualModifierList(ob); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); LatticeModifierData *lmd = NULL; /* return the first selected lattice, this lets us use multiple lattices */ @@ -559,7 +556,8 @@ Object *modifiers_isDeformedByLattice(Object *ob) */ Object *modifiers_isDeformedByCurve(Object *ob) { - ModifierData *md = modifiers_getVirtualModifierList(ob); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); CurveModifierData *cmd = NULL; /* return the first selected curve, this lets us use multiple curves */ @@ -579,7 +577,8 @@ Object *modifiers_isDeformedByCurve(Object *ob) bool modifiers_usesArmature(Object *ob, bArmature *arm) { - ModifierData *md = modifiers_getVirtualModifierList(ob); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); for (; md; md = md->next) { if (md->type == eModifierType_Armature) { @@ -594,20 +593,21 @@ bool modifiers_usesArmature(Object *ob, bArmature *arm) bool modifier_isCorrectableDeformed(ModifierData *md) { - if (md->type == eModifierType_Armature) - return true; - if (md->type == eModifierType_ShapeKey) - return true; - - return false; + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + return (mti->deformMatricesEM != NULL); } -bool modifiers_isCorrectableDeformed(Object *ob) +bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob) { - ModifierData *md = modifiers_getVirtualModifierList(ob); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + int required_mode = eModifierMode_Realtime; + + if (ob->mode == OB_MODE_EDIT) + required_mode |= eModifierMode_Editmode; for (; md; md = md->next) { - if (ob->mode == OB_MODE_EDIT && (md->mode & eModifierMode_Editmode) == 0) { + if (!modifier_isEnabled(scene, md, required_mode)) { /* pass */ } else if (modifier_isCorrectableDeformed(md)) { diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c index 290b0684e40..a9ff569e70a 100644 --- a/source/blender/blenkernel/intern/modifiers_bmesh.c +++ b/source/blender/blenkernel/intern/modifiers_bmesh.c @@ -52,7 +52,7 @@ static BMFace *bm_face_create_from_mpoly(MPoly *mp, MLoop *ml, edges[j] = etable[ml->e]; } - return BM_face_create(bm, verts, edges, mp->totloop, BM_CREATE_SKIP_CD); + return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD); } /** @@ -232,8 +232,9 @@ BMEditMesh *DM_to_editbmesh(DerivedMesh *dm, BMEditMesh *existing, const bool do BMesh *DM_to_bmesh(DerivedMesh *dm, const bool calc_face_normal) { BMesh *bm; + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm); - bm = BM_mesh_create(&bm_mesh_allocsize_default); + bm = BM_mesh_create(&allocsize); DM_to_bmesh_ex(dm, bm, calc_face_normal); diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index bf4a63c52a8..d9630a7343d 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -62,7 +62,6 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" #include "BLI_math.h" -#include "BLI_mempool.h" #include "BLI_threads.h" #include "BKE_animsys.h" diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 32ca3ea6d5a..0cdcf4e7298 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -114,8 +114,8 @@ static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden, BLI_bitmap *prev_hidden) { BLI_bitmap *subd; - int hi_gridsize = ccg_gridsize(hi_level); - int lo_gridsize = ccg_gridsize(lo_level); + int hi_gridsize = BKE_ccg_gridsize(hi_level); + int lo_gridsize = BKE_ccg_gridsize(lo_level); int yh, xh, xl, yl, xo, yo, hi_ndx; int offset, factor; @@ -127,7 +127,7 @@ static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden, subd = BLI_BITMAP_NEW(hi_gridsize * hi_gridsize, "MDisps.hidden upsample"); - factor = ccg_factor(lo_level, hi_level); + factor = BKE_ccg_factor(lo_level, hi_level); offset = 1 << (hi_level - lo_level - 1); /* low-res blocks */ @@ -173,12 +173,12 @@ static BLI_bitmap *multires_mdisps_downsample_hidden(BLI_bitmap *old_hidden, int new_level) { BLI_bitmap *new_hidden; - int new_gridsize = ccg_gridsize(new_level); - int old_gridsize = ccg_gridsize(old_level); + int new_gridsize = BKE_ccg_gridsize(new_level); + int old_gridsize = BKE_ccg_gridsize(old_level); int x, y, factor, old_value; BLI_assert(new_level <= old_level); - factor = ccg_factor(new_level, old_level); + factor = BKE_ccg_factor(new_level, old_level); new_hidden = BLI_BITMAP_NEW(new_gridsize * new_gridsize, "downsample hidden"); @@ -246,7 +246,7 @@ static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level) { MDisps *mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop); - int gridsize = ccg_gridsize(level); + int gridsize = BKE_ccg_gridsize(level); int gridarea = gridsize * gridsize; int i, j, k; @@ -594,7 +594,7 @@ static void multires_copy_dm_grid(CCGElem *gridA, CCGElem *gridB, CCGKey *keyA, static void multires_grid_paint_mask_downsample(GridPaintMask *gpm, int level) { if (level < gpm->level) { - int gridsize = ccg_gridsize(level); + int gridsize = BKE_ccg_gridsize(level); float *data = MEM_callocN(sizeof(float) * gridsize * gridsize, "multires_grid_paint_mask_downsample"); int x, y; @@ -1645,6 +1645,11 @@ void multires_free(Multires *mr) } } +typedef struct IndexNode { + struct IndexNode *next, *prev; + int index; +} IndexNode; + static void create_old_vert_face_map(ListBase **map, IndexNode **mem, const MultiresFace *mface, const int totvert, const int totface) { diff --git a/source/blender/blenkernel/intern/navmesh_conversion.c b/source/blender/blenkernel/intern/navmesh_conversion.c index 1d662ae3116..3c499908bf7 100644 --- a/source/blender/blenkernel/intern/navmesh_conversion.c +++ b/source/blender/blenkernel/intern/navmesh_conversion.c @@ -38,6 +38,7 @@ #include "BLI_utildefines.h" #include "BLI_math.h" +#include "BLI_sort.h" #include "BKE_navmesh_conversion.h" #include "BKE_cdderivedmesh.h" @@ -340,7 +341,7 @@ int buildNavMeshData(const int nverts, const float *verts, trisMapping[i] = i; context.recastData = recastData; context.trisToFacesMap = trisToFacesMap; - recast_qsort(trisMapping, ntris, sizeof(int), &context, compareByData); + BLI_qsort_r(trisMapping, ntris, sizeof(int), &context, compareByData); /* search first valid triangle - triangle of convex polygon */ validTriStart = -1; @@ -366,7 +367,7 @@ int buildNavMeshData(const int nverts, const float *verts, /* create detailed mesh triangles - copy only valid triangles * and reserve memory for adjacency info */ dtris = MEM_callocN(sizeof(unsigned short) * 3 * 2 * ndtris, "buildNavMeshData dtris"); - memset(dtris, 0xffff, sizeof(unsigned short) * 3 * 2 * ndtris); + memset(dtris, 0xff, sizeof(unsigned short) * 3 * 2 * ndtris); for (i = 0; i < ndtris; i++) { memcpy(dtris + 3 * 2 * i, tris + 3 * dtrisToTrisMap[i], sizeof(unsigned short) * 3); } diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 5001aa01653..c0df306a3fa 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1107,7 +1107,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) * copying for internal use (threads for eg), where you wont want it to modify the * scene data. */ -static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_id_user, const short do_make_extern, const short copy_previews) +static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_id_user, bool do_make_extern, bool copy_previews) { bNodeTree *newtree; bNode *node /*, *nnode */ /* UNUSED */, *last; @@ -1116,13 +1116,17 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_id_use if (ntree == NULL) return NULL; - /* is ntree part of library? */ - for (newtree = G.main->nodetree.first; newtree; newtree = newtree->id.next) - if (newtree == ntree) break; - if (newtree) { - newtree = BKE_libblock_copy(&ntree->id); + if (bmain) { + /* is ntree part of library? */ + if (BLI_findindex(&bmain->nodetree, ntree) != -1) + newtree = BKE_libblock_copy(&ntree->id); + else + newtree = NULL; } - else { + else + newtree = NULL; + + if (newtree == NULL) { newtree = MEM_dupallocN(ntree); newtree->id.lib = NULL; /* same as owning datablock id.lib */ BKE_libblock_copy_data(&newtree->id, &ntree->id, true); /* copy animdata and ID props */ @@ -1208,7 +1212,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_id_use bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, const short do_id_user) { - return ntreeCopyTree_internal(ntree, do_id_user, TRUE, TRUE); + return ntreeCopyTree_internal(ntree, G.main, do_id_user, TRUE, TRUE); } bNodeTree *ntreeCopyTree(bNodeTree *ntree) { @@ -1590,6 +1594,8 @@ static void node_unlink_attached(bNodeTree *ntree, bNode *parent) void nodeFreeNode(bNodeTree *ntree, bNode *node) { bNodeSocket *sock, *nextsock; + char propname_esc[MAX_IDPROP_NAME * 2]; + char prefix[MAX_IDPROP_NAME * 2]; /* extra free callback */ if (node->typeinfo && node->typeinfo->freefunc_api) { @@ -1609,6 +1615,11 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node) BLI_remlink(&ntree->nodes, node); + BLI_strescape(propname_esc, node->name, sizeof(propname_esc)); + BLI_snprintf(prefix, sizeof(prefix), "nodes[\"%s\"]", propname_esc); + + BKE_animdata_fix_paths_remove((ID *)ntree, prefix); + if (ntree->typeinfo && ntree->typeinfo->free_node_cache) ntree->typeinfo->free_node_cache(ntree, node); @@ -1657,6 +1668,22 @@ static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *so MEM_freeN(sock->default_value); } +static void free_localized_node_groups(bNodeTree *ntree) +{ + bNode *node; + + for (node = ntree->nodes.first; node; node = node->next) { + if (node->type == NODE_GROUP && node->id) { + bNodeTree *ngroup = (bNodeTree *)node->id; + if (BLI_findindex(&G.main->nodetree, ngroup) == -1) { + /* ntree is not in library, i.e. localized node group: free it */ + ntreeFreeTree_ex(ngroup, false); + MEM_freeN(ngroup); + } + } + } +} + /* do not free ntree itself here, BKE_libblock_free calls this function too */ void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user) { @@ -1683,6 +1710,9 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user) } } + /* XXX not nice, but needed to free localized node groups properly */ + free_localized_node_groups(ntree); + /* unregister associated RNA types */ ntreeInterfaceTypeFree(ntree); @@ -1932,8 +1962,14 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree) /* Make full copy. * Note: previews are not copied here. */ - ltree = ntreeCopyTree_internal(ntree, FALSE, FALSE, FALSE); - + ltree = ntreeCopyTree_internal(ntree, NULL, FALSE, FALSE, FALSE); + + for (node = ltree->nodes.first; node; node = node->next) { + if (node->type == NODE_GROUP && node->id) { + node->id = (ID *)ntreeLocalize((bNodeTree *)node->id); + } + } + if (adt) { AnimData *ladt = BKE_animdata_from_id(<ree->id); @@ -1978,7 +2014,7 @@ void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree) /* we have to assume the editor already changed completely */ void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree) { - if (localtree && ntree) { + if (ntree && localtree) { if (ntree->typeinfo->local_merge) ntree->typeinfo->local_merge(localtree, ntree); @@ -2285,7 +2321,7 @@ bNode *nodeGetActive(bNodeTree *ntree) static bNode *node_get_active_id_recursive(bNodeInstanceKey active_key, bNodeInstanceKey parent_key, bNodeTree *ntree, short idtype) { - if (parent_key.value == active_key.value) { + if (parent_key.value == active_key.value || active_key.value == 0) { bNode *node; for (node = ntree->nodes.first; node; node = node->next) if (node->id && GS(node->id->name) == idtype) @@ -2666,7 +2702,7 @@ void BKE_node_instance_hash_clear(bNodeInstanceHash *hash, bNodeInstanceValueFP void *BKE_node_instance_hash_pop(bNodeInstanceHash *hash, bNodeInstanceKey key) { - return BLI_ghash_pop(hash->ghash, &key, NULL); + return BLI_ghash_popkey(hash->ghash, &key, NULL); } int BKE_node_instance_hash_haskey(bNodeInstanceHash *hash, bNodeInstanceKey key) @@ -3391,6 +3427,7 @@ static void registerCompositNodes(void) register_node_type_cmp_mask(); register_node_type_cmp_trackpos(); + register_node_type_cmp_planetrackdeform(); } static void registerShaderNodes(void) @@ -3448,6 +3485,7 @@ static void registerShaderNodes(void) register_node_type_sh_bsdf_transparent(); register_node_type_sh_bsdf_velvet(); register_node_type_sh_bsdf_toon(); + register_node_type_sh_bsdf_hair(); register_node_type_sh_emission(); register_node_type_sh_holdout(); //register_node_type_sh_volume_transparent(); @@ -3573,11 +3611,13 @@ void free_nodesystem(void) } if (nodetreetypes_hash) { - NODE_TREE_TYPES_BEGIN(nt) + NODE_TREE_TYPES_BEGIN (nt) + { if (nt->ext.free) { nt->ext.free(nt->ext.data); } - NODE_TREE_TYPES_END + } + NODE_TREE_TYPES_END; BLI_ghash_free(nodetreetypes_hash, NULL, ntree_free_type); nodetreetypes_hash = NULL; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 962209bef87..8c2475369de 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -64,6 +64,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_linklist.h" +#include "BLI_kdtree.h" #include "BLF_translation.h" @@ -142,11 +143,9 @@ void BKE_object_update_base_layer(struct Scene *scene, Object *ob) void BKE_object_free_particlesystems(Object *ob) { - while (ob->particlesystem.first) { - ParticleSystem *psys = ob->particlesystem.first; - - BLI_remlink(&ob->particlesystem, psys); - + ParticleSystem *psys; + + while ((psys = BLI_pophead(&ob->particlesystem))) { psys_free(ob, psys); } } @@ -167,13 +166,24 @@ void BKE_object_free_bulletsoftbody(Object *ob) } } +void BKE_object_free_curve_cache(Object *ob) +{ + if (ob->curve_cache) { + BKE_displist_free(&ob->curve_cache->disp); + BLI_freelistN(&ob->curve_cache->bev); + if (ob->curve_cache->path) { + free_path(ob->curve_cache->path); + } + MEM_freeN(ob->curve_cache); + ob->curve_cache = NULL; + } +} + void BKE_object_free_modifiers(Object *ob) { - while (ob->modifiers.first) { - ModifierData *md = ob->modifiers.first; - - BLI_remlink(&ob->modifiers, md); - + ModifierData *md; + + while ((md = BLI_pophead(&ob->modifiers))) { modifier_free(md); } @@ -246,8 +256,14 @@ void BKE_object_free_derived_caches(Object *ob) Mesh *me = ob->data; if (me->bb) { - MEM_freeN(me->bb); - me->bb = NULL; + me->bb->flag |= BOUNDBOX_DIRTY; + } + } + else if (ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { + Curve *cu = ob->data; + + if (cu->bb) { + cu->bb->flag |= BOUNDBOX_DIRTY; } } @@ -267,7 +283,9 @@ void BKE_object_free_derived_caches(Object *ob) ob->derivedDeform = NULL; } - BKE_displist_free(&ob->disp); + if (ob->curve_cache) { + BKE_displist_free(&ob->curve_cache->disp); + } } /* do not free object itself */ @@ -337,6 +355,14 @@ void BKE_object_free(Object *ob) free_sculptsession(ob); if (ob->pc_ids.first) BLI_freelistN(&ob->pc_ids); + + /* Free runtime curves data. */ + if (ob->curve_cache) { + BLI_freelistN(&ob->curve_cache->bev); + if (ob->curve_cache->path) + free_path(ob->curve_cache->path); + MEM_freeN(ob->curve_cache); + } } static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin) @@ -617,7 +643,9 @@ void BKE_object_unlink(Object *ob) for (lineset = (FreestyleLineSet *)srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { - BKE_unlink_linestyle_target_object(lineset->linestyle, ob); + if (lineset->linestyle) { + BKE_unlink_linestyle_target_object(lineset->linestyle, ob); + } } } } @@ -1256,8 +1284,6 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, int copy_caches) for (a = 0; a < obn->totcol; a++) id_us_plus((ID *)obn->mat[a]); - obn->disp.first = obn->disp.last = NULL; - if (ob->pd) { obn->pd = MEM_dupallocN(ob->pd); if (obn->pd->tex) @@ -1279,7 +1305,10 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, int copy_caches) obn->pc_ids.first = obn->pc_ids.last = NULL; obn->mpath = NULL; - + + /* Copy runtime surve data. */ + obn->curve_cache = NULL; + return obn; } @@ -1772,9 +1801,9 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) unit_m4(mat); cu = par->data; - if (cu->path == NULL || cu->path->data == NULL) /* only happens on reload file, but violates depsgraph still... fix! */ + if (ELEM3(NULL, par->curve_cache, par->curve_cache->path, par->curve_cache->path->data)) /* only happens on reload file, but violates depsgraph still... fix! */ BKE_displist_make_curveTypes(scene, par, 0); - if (cu->path == NULL) return; + if (par->curve_cache->path == NULL) return; /* catch exceptions: feature for nla stride editing */ if (ob->ipoflag & OB_DISABLE_PATH) { @@ -1805,7 +1834,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) /* time calculus is correct, now apply distance offset */ if (cu->flag & CU_OFFS_PATHDIST) { - ctime += timeoffs / cu->path->totdist; + ctime += timeoffs / par->curve_cache->path->totdist; /* restore */ SWAP(float, sf_orig, ob->sf); @@ -1962,7 +1991,7 @@ static void give_parvert(Object *par, int nr, float vec[3]) } else if (par->type == OB_LATTICE) { Lattice *latt = par->data; - DispList *dl = BKE_displist_find(&par->disp, DL_VERTS); + DispList *dl = par->curve_cache ? BKE_displist_find(&par->curve_cache->disp, DL_VERTS) : NULL; float (*co)[3] = dl ? (float (*)[3])dl->verts : NULL; int tot; @@ -1986,29 +2015,23 @@ static void give_parvert(Object *par, int nr, float vec[3]) static void ob_parvert3(Object *ob, Object *par, float mat[4][4]) { - float cmat[3][3], v1[3], v2[3], v3[3], q[4]; /* in local ob space */ - unit_m4(mat); - - if (ELEM4(par->type, OB_MESH, OB_SURF, OB_CURVE, OB_LATTICE)) { - + if (OB_TYPE_SUPPORT_PARVERT(par->type)) { + float cmat[3][3], v1[3], v2[3], v3[3], q[4]; + give_parvert(par, ob->par1, v1); give_parvert(par, ob->par2, v2); give_parvert(par, ob->par3, v3); - + tri_to_quat(q, v1, v2, v3); quat_to_mat3(cmat, q); copy_m4_m3(mat, cmat); - - if (ob->type == OB_CURVE) { - copy_v3_v3(mat[3], v1); - } - else { - add_v3_v3v3(mat[3], v1, v2); - add_v3_v3(mat[3], v3); - mul_v3_fl(mat[3], 1.0f / 3.0f); - } + + mid_v3_v3v3v3(mat[3], v1, v2, v3); + } + else { + unit_m4(mat); } } @@ -2291,7 +2314,7 @@ BoundBox *BKE_object_boundbox_get(Object *ob) bb = BKE_mesh_boundbox_get(ob); } else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - bb = ob->bb ? ob->bb : ((Curve *)ob->data)->bb; + bb = BKE_curve_boundbox_get(ob); } else if (ob->type == OB_MBALL) { bb = ob->bb; @@ -2360,18 +2383,7 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool us case OB_FONT: case OB_SURF: { - Curve *cu = ob->data; - - /* Use the object bounding box so that modifier output - * gets taken into account */ - if (ob->bb) { - bb = *(ob->bb); - } - else { - if (cu->bb == NULL) - BKE_curve_texspace_calc(cu); - bb = *(cu->bb); - } + bb = *BKE_curve_boundbox_get(ob); for (a = 0; a < 8; a++) { mul_m4_v3(ob->obmat, bb.vec[a]); @@ -2519,10 +2531,10 @@ void BKE_object_foreach_display_point( func_cb(co, user_data); } } - else if (ob->disp.first) { + else if (ob->curve_cache && ob->curve_cache->disp.first) { DispList *dl; - for (dl = ob->disp.first; dl; dl = dl->next) { + for (dl = ob->curve_cache->disp.first; dl; dl = dl->next) { float *v3 = dl->verts; int totvert = dl->nr; int i; @@ -2825,21 +2837,20 @@ void BKE_object_handle_update_ex(Scene *scene, Object *ob, /* quick cache removed */ } - /* the no-group proxy case, we call update */ - if (ob->proxy && ob->proxy_group == NULL) { - /* set pointer in library proxy target, for copying, but restore it */ - ob->proxy->proxy_from = ob; - // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name); - BKE_object_handle_update(scene, ob->proxy); - } - ob->recalc &= ~OB_RECALC_ALL; } /* the case when this is a group proxy, object_update is called in group.c */ if (ob->proxy) { + /* set pointer in library proxy target, for copying, but restore it */ ob->proxy->proxy_from = ob; // printf("set proxy pointer for later group stuff %s\n", ob->id.name); + + /* the no-group proxy case, we call update */ + if (ob->proxy_group == NULL) { + // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name); + BKE_object_handle_update(scene, ob->proxy); + } } } /* WARNING: "scene" here may not be the scene object actually resides in. @@ -3158,8 +3169,9 @@ int BKE_object_is_modified(Scene *scene, Object *ob) } else { ModifierData *md; + VirtualModifierData virtualModifierData; /* cloth */ - for (md = modifiers_getVirtualModifierList(ob); + for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md && (flag != (eModifierMode_Render | eModifierMode_Realtime)); md = md->next) { @@ -3180,10 +3192,11 @@ int BKE_object_is_modified(Scene *scene, Object *ob) int BKE_object_is_deform_modified(Scene *scene, Object *ob) { ModifierData *md; + VirtualModifierData virtualModifierData; int flag = 0; /* cloth */ - for (md = modifiers_getVirtualModifierList(ob); + for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md && (flag != (eModifierMode_Render | eModifierMode_Realtime)); md = md->next) { @@ -3205,8 +3218,9 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob) bool BKE_object_is_animated(Scene *scene, Object *ob) { ModifierData *md; + VirtualModifierData virtualModifierData; - for (md = modifiers_getVirtualModifierList(ob); md; md = md->next) + for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) if (modifier_dependsOnTime(md) && (modifier_isEnabled(scene, md, eModifierMode_Realtime) || modifier_isEnabled(scene, md, eModifierMode_Render))) @@ -3248,7 +3262,7 @@ void BKE_object_relink(Object *ob) ID_NEW(ob->proxy_group); } -MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, int use_default) +MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default) { MovieClip *clip = use_default ? scene->clip : NULL; bConstraint *con = ob->constraints.first, *scon = NULL; @@ -3422,3 +3436,131 @@ void BKE_object_groups_clear(Scene *scene, Base *base, Object *object) BKE_group_object_unlink(group, object, scene, base); } } + +/** + * Return a KDTree from the deformed object (in worldspace) + * + * \note Only mesh objects currently support deforming, others are TODO. + * + * \param ob + * \param r_tot + * \return The kdtree or NULL if it can't be created. + */ +KDTree *BKE_object_as_kdtree(Object *ob, int *r_tot) +{ + KDTree *tree = NULL; + unsigned int tot = 0; + + switch (ob->type) { + case OB_MESH: + { + Mesh *me = ob->data; + unsigned int i; + + DerivedMesh *dm = ob->derivedDeform ? ob->derivedDeform : ob->derivedFinal; + int *index; + + if (dm && (index = CustomData_get_layer(&dm->vertData, CD_ORIGINDEX))) { + MVert *mvert = dm->getVertArray(dm); + unsigned int totvert = dm->getNumVerts(dm); + + /* tree over-allocs in case where some verts have ORIGINDEX_NONE */ + tot = 0; + tree = BLI_kdtree_new(totvert); + + /* we don't how how many verts from the DM we can use */ + for (i = 0; i < totvert; i++) { + if (index[i] != ORIGINDEX_NONE) { + float co[3]; + mul_v3_m4v3(co, ob->obmat, mvert[i].co); + BLI_kdtree_insert(tree, index[i], co, NULL); + tot++; + } + } + } + else { + MVert *mvert = me->mvert; + + tot = me->totvert; + tree = BLI_kdtree_new(tot); + + for (i = 0; i < tot; i++) { + float co[3]; + mul_v3_m4v3(co, ob->obmat, mvert[i].co); + BLI_kdtree_insert(tree, i, co, NULL); + } + } + + BLI_kdtree_balance(tree); + break; + } + case OB_CURVE: + case OB_SURF: + { + /* TODO: take deformation into account */ + Curve *cu = ob->data; + unsigned int i, a; + + Nurb *nu; + + tot = BKE_nurbList_verts_count_without_handles(&cu->nurb); + tree = BLI_kdtree_new(tot); + i = 0; + + nu = cu->nurb.first; + while (nu) { + if (nu->bezt) { + BezTriple *bezt; + + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + float co[3]; + mul_v3_m4v3(co, ob->obmat, bezt->vec[1]); + BLI_kdtree_insert(tree, i++, co, NULL); + bezt++; + } + } + else { + BPoint *bp; + + bp = nu->bp; + a = nu->pntsu * nu->pntsv; + while (a--) { + float co[3]; + mul_v3_m4v3(co, ob->obmat, bp->vec); + BLI_kdtree_insert(tree, i++, co, NULL); + bp++; + } + } + nu = nu->next; + } + + BLI_kdtree_balance(tree); + break; + } + case OB_LATTICE: + { + /* TODO: take deformation into account */ + Lattice *lt = ob->data; + BPoint *bp; + unsigned int i; + + tot = lt->pntsu * lt->pntsv * lt->pntsw; + tree = BLI_kdtree_new(tot); + i = 0; + + for (bp = lt->def; i < tot; bp++) { + float co[3]; + mul_v3_m4v3(co, ob->obmat, bp->vec); + BLI_kdtree_insert(tree, i++, co, NULL); + } + + BLI_kdtree_balance(tree); + break; + } + } + + *r_tot = tot; + return tree; +} diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index bfec38419f1..77c5e57f382 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -73,12 +73,13 @@ bool *BKE_objdef_validmap_get(Object *ob, const int defbase_tot) GHash *gh; int i, step1 = 1; //int defbase_tot = BLI_countlist(&ob->defbase); + VirtualModifierData virtualModifierData; if (ob->defbase.first == NULL) { return NULL; } - gh = BLI_ghash_str_new("BKE_objdef_validmap_get gh"); + gh = BLI_ghash_str_new_ex("BKE_objdef_validmap_get gh", defbase_tot); /* add all names to a hash table */ for (dg = ob->defbase.first; dg; dg = dg->next) { @@ -88,7 +89,7 @@ bool *BKE_objdef_validmap_get(Object *ob, const int defbase_tot) BLI_assert(BLI_ghash_size(gh) == defbase_tot); /* now loop through the armature modifiers and identify deform bones */ - for (md = ob->modifiers.first; md; md = !md->next && step1 ? (step1 = 0), modifiers_getVirtualModifierList(ob) : md->next) { + for (md = ob->modifiers.first; md; md = !md->next && step1 ? (step1 = 0), modifiers_getVirtualModifierList(ob, &virtualModifierData) : md->next) { if (!(md->mode & (eModifierMode_Realtime | eModifierMode_Virtual))) continue; @@ -100,11 +101,13 @@ bool *BKE_objdef_validmap_get(Object *ob, const int defbase_tot) bPoseChannel *chan; for (chan = pose->chanbase.first; chan; chan = chan->next) { + void **val_p; if (chan->bone->flag & BONE_NO_DEFORM) continue; - if (BLI_ghash_remove(gh, chan->name, NULL, NULL)) { - BLI_ghash_insert(gh, chan->name, SET_INT_IN_POINTER(1)); + val_p = BLI_ghash_lookup_p(gh, chan->name); + if (val_p) { + *val_p = SET_INT_IN_POINTER(1); } } } diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index 21a69910b4d..c1e43365a84 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -25,6 +25,9 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/blenkernel/intern/ocean.c + * \ingroup bke + */ #include <math.h> #include <stdlib.h> diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 62ea16b9fb4..5c2789a2c1c 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -219,6 +219,9 @@ PackedFile *newPackedFile(ReportList *reports, const char *filename, const char if (read(file, data, filelen) == filelen) { pf = newPackedFileMemory(data, filelen); } + else { + MEM_freeN(data); + } close(file); } diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index b47a493581e..6bdfb22dc1a 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -359,8 +359,8 @@ int paint_is_bmesh_face_hidden(BMFace *f) float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level, unsigned x, unsigned y) { - int factor = ccg_factor(level, gpm->level); - int gridsize = ccg_gridsize(gpm->level); + int factor = BKE_ccg_factor(level, gpm->level); + int gridsize = BKE_ccg_gridsize(gpm->level); return gpm->data[(y * factor) * gridsize + (x * factor)]; } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 6b754743c11..24cf98d957d 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -221,12 +221,12 @@ Object *psys_find_object(Scene *scene, ParticleSystem *psys) } #endif -Object *psys_get_lattice(ParticleSimulationData *sim) +struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData *sim) { - Object *lattice = NULL; - - if (psys_in_edit_mode(sim->scene, sim->psys) == 0) { + struct LatticeDeformData *lattice_deform_data = NULL; + if (psys_in_edit_mode(sim->scene, sim->psys) == 0) { + Object *lattice = NULL; ModifierData *md = (ModifierData *)psys_get_modifier(sim->ob, sim->psys); for (; md; md = md->next) { @@ -237,10 +237,10 @@ Object *psys_get_lattice(ParticleSimulationData *sim) } } if (lattice) - init_latt_deform(lattice, NULL); + lattice_deform_data = init_latt_deform(lattice, NULL); } - return lattice; + return lattice_deform_data; } void psys_disable_all(Object *ob) { @@ -1729,7 +1729,7 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_ return 0; if (dm->deformedOnly || index_dmcache == DMCACHE_ISCHILD) { - /* for meshes that are either only defined or for child particles, the + /* for meshes that are either only deformed or for child particles, the * index and fw do not require any mapping, so we can directly use it */ if (from == PART_FROM_VERT) { if (index >= dm->getNumVerts(dm)) @@ -1817,8 +1817,8 @@ void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache copy_v3_v3(orco, orcodata[mapindex]); if (ornor) { - dm->getVertNo(dm, mapindex, nor); - normalize_v3(nor); + dm->getVertNo(dm, mapindex, ornor); + normalize_v3(ornor); } if (utan && vtan) { @@ -1843,7 +1843,7 @@ void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache if (nor) copy_v3_v3(nor, tmpnor); - normalize_v3(tmpnor); + normalize_v3(tmpnor); /* XXX Why not normalize tmpnor before copying it into nor??? -- mont29 */ mul_v3_fl(tmpnor, -foffset); add_v3_v3(vec, tmpnor); } @@ -2513,7 +2513,7 @@ static int psys_threads_init_path(ParticleThread *threads, Scene *scene, float c ctx->cfra = cfra; ctx->editupdate = editupdate; - psys->lattice = psys_get_lattice(&ctx->sim); + psys->lattice_deform_data = psys_create_lattice_deform_data(&ctx->sim); /* cache all relevant vertex groups if they exist */ ctx->vg_length = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_LENGTH); @@ -2974,7 +2974,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra) psys_free_path_cache(psys, psys->edit); cache = psys->pathcache = psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, steps + 1); - psys->lattice = psys_get_lattice(sim); + psys->lattice_deform_data = psys_create_lattice_deform_data(sim); ma = give_current_material(sim->ob, psys->part->omat); if (ma && (psys->part->draw_col == PART_DRAW_COL_MAT)) copy_v3_v3(col, &ma->r); @@ -3079,9 +3079,9 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra) } /* lattices have to be calculated separately to avoid mixups between effector calculations */ - if (psys->lattice) { + if (psys->lattice_deform_data) { for (k = 0, ca = cache[p]; k <= steps; k++, ca++) - calc_latt_deform(psys->lattice, ca->co, 1.0f); + calc_latt_deform(psys->lattice_deform_data, ca->co, 1.0f); } } @@ -3112,9 +3112,9 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra) psys->totcached = totpart; - if (psys->lattice) { - end_latt_deform(psys->lattice); - psys->lattice = NULL; + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; } if (vg_effector) @@ -4166,8 +4166,8 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey * /* TODO: proper velocity handling */ } - if (psys->lattice && edit == 0) - calc_latt_deform(psys->lattice, state->co, 1.0f); + if (psys->lattice_deform_data && edit == 0) + calc_latt_deform(psys->lattice_deform_data, state->co, 1.0f); } } } @@ -4402,8 +4402,8 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta unit_m4(mat); do_child_modifiers(sim, NULL, key1, key1->rot, cpa, cpa->fuv, mat, state, t); - if (psys->lattice) - calc_latt_deform(sim->psys->lattice, state->co, 1.0f); + if (psys->lattice_deform_data) + calc_latt_deform(psys->lattice_deform_data, state->co, 1.0f); } else { if (pa->state.time == cfra || ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) @@ -4461,8 +4461,8 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta } } - if (sim->psys->lattice) - calc_latt_deform(sim->psys->lattice, state->co, 1.0f); + if (sim->psys->lattice_deform_data) + calc_latt_deform(sim->psys->lattice_deform_data, state->co, 1.0f); } return 1; @@ -4678,9 +4678,9 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys) sim.psys = psys; sim.psmd = psys_get_modifier(ob, psys); - psys->lattice = psys_get_lattice(&sim); + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); - if (psys->lattice) { + if (psys->lattice_deform_data) { ParticleData *pa = psys->particles; HairKey *hkey; int p, h; @@ -4693,13 +4693,13 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys) hkey = pa->hair; for (h = 0; h < pa->totkey; h++, hkey++) { mul_m4_v3(hairmat, hkey->co); - calc_latt_deform(psys->lattice, hkey->co, 1.0f); + calc_latt_deform(psys->lattice_deform_data, hkey->co, 1.0f); mul_m4_v3(imat, hkey->co); } } - end_latt_deform(psys->lattice); - psys->lattice = NULL; + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; /* protect the applied shape */ psys->flag |= PSYS_EDITED; diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 16ea71204cc..526d54a97fa 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -70,6 +70,7 @@ #include "BLI_blenlib.h" #include "BLI_kdtree.h" #include "BLI_kdopbvh.h" +#include "BLI_sort.h" #include "BLI_threads.h" #include "BLI_linklist.h" @@ -814,7 +815,7 @@ static void distribute_threads_exec(ParticleThread *thread, ParticleData *pa, Ch psys_particle_on_dm(ctx->dm,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0); BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1); - maxw = BLI_kdtree_find_n_nearest(ctx->tree,3,orco1,NULL,ptn); + maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,NULL,ptn,3); for (w=0; w<maxw; w++) { pa->verts[w]=ptn->num; @@ -939,7 +940,7 @@ static void distribute_threads_exec(ParticleThread *thread, ParticleData *pa, Ch psys_particle_on_dm(dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1,NULL); BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1); - maxw = BLI_kdtree_find_n_nearest(ctx->tree,4,orco1,NULL,ptn); + maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,NULL,ptn,3); maxd=ptn[maxw-1].dist; /* mind=ptn[0].dist; */ /* UNUSED */ @@ -1010,12 +1011,11 @@ static void *distribute_threads_exec_cb(void *data) return 0; } -/* not thread safe, but qsort doesn't take userdata argument */ -static int *COMPARE_ORIG_INDEX = NULL; -static int distribute_compare_orig_index(const void *p1, const void *p2) +static int distribute_compare_orig_index(void *user_data, const void *p1, const void *p2) { - int index1 = COMPARE_ORIG_INDEX[*(const int *)p1]; - int index2 = COMPARE_ORIG_INDEX[*(const int *)p2]; + int *orig_index = (int *) user_data; + int index1 = orig_index[*(const int *)p1]; + int index2 = orig_index[*(const int *)p2]; if (index1 < index2) return -1; @@ -1332,20 +1332,19 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D /* For hair, sort by origindex (allows optimization's in rendering), */ /* however with virtual parents the children need to be in random order. */ if (part->type == PART_HAIR && !(part->childtype==PART_CHILD_FACES && part->parents!=0.0f)) { - COMPARE_ORIG_INDEX = NULL; + int *orig_index = NULL; if (from == PART_FROM_VERT) { if (dm->numVertData) - COMPARE_ORIG_INDEX= dm->getVertDataArray(dm, CD_ORIGINDEX); + orig_index = dm->getVertDataArray(dm, CD_ORIGINDEX); } else { if (dm->numTessFaceData) - COMPARE_ORIG_INDEX= dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + orig_index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); } - if (COMPARE_ORIG_INDEX) { - qsort(particle_element, totpart, sizeof(int), distribute_compare_orig_index); - COMPARE_ORIG_INDEX = NULL; + if (orig_index) { + BLI_qsort_r(particle_element, totpart, sizeof(int), orig_index, distribute_compare_orig_index); } } @@ -1514,9 +1513,9 @@ void psys_threads_free(ParticleThread *threads) if (ctx->vg_roughe) MEM_freeN(ctx->vg_roughe); - if (ctx->sim.psys->lattice) { - end_latt_deform(ctx->sim.psys->lattice); - ctx->sim.psys->lattice= NULL; + if (ctx->sim.psys->lattice_deform_data) { + end_latt_deform(ctx->sim.psys->lattice_deform_data); + ctx->sim.psys->lattice_deform_data = NULL; } /* distribution */ @@ -2485,7 +2484,7 @@ static EdgeHash *sph_springhash_build(ParticleSystem *psys) ParticleSpring *spring; int i = 0; - springhash = BLI_edgehash_new(); + springhash = BLI_edgehash_new_ex(__func__, psys->tot_fluidsprings); for (i=0, spring=psys->fluid_springs; i<psys->tot_fluidsprings; i++, spring++) BLI_edgehash_insert(springhash, spring->particle_index[0], spring->particle_index[1], SET_INT_IN_POINTER(i+1)); @@ -3314,9 +3313,14 @@ static float collision_newton_rhapson(ParticleCollision *col, float radius, Part pce->inv_nor = -1; - /* Initial step size should be small, but not too small or floating point - * precision errors will appear. - z0r */ - dt_init = COLLISION_INIT_STEP * col->inv_total_time; + if (col->inv_total_time > 0.0f) { + /* Initial step size should be small, but not too small or floating point + * precision errors will appear. - z0r */ + dt_init = COLLISION_INIT_STEP * col->inv_total_time; + } + else { + dt_init = 0.001f; + } /* start from the beginning */ t0 = 0.f; @@ -4108,7 +4112,7 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra)) invert_m4_m4(ob->imat, ob->obmat); - psys->lattice= psys_get_lattice(sim); + psys->lattice_deform_data= psys_create_lattice_deform_data(sim); if (psys->totpart==0) return; @@ -4479,7 +4483,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra) if (part->randsize > 0.0f) pa->size *= 1.0f - part->randsize * PSYS_FRAND(p + 1); - psys->lattice= psys_get_lattice(sim); + psys->lattice_deform_data = psys_create_lattice_deform_data(sim); dietime = pa->dietime; @@ -4494,9 +4498,9 @@ static void cached_step(ParticleSimulationData *sim, float cfra) else pa->alive = PARS_ALIVE; - if (psys->lattice) { - end_latt_deform(psys->lattice); - psys->lattice= NULL; + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; } if (PSYS_FRAND(p) > disp) @@ -4777,9 +4781,9 @@ static void system_step(ParticleSimulationData *sim, float cfra) update_children(sim); /* cleanup */ - if (psys->lattice) { - end_latt_deform(psys->lattice); - psys->lattice= NULL; + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; } } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 205159c94a1..45a29f6cc90 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -229,9 +229,10 @@ void pbvh_grow_nodes(PBVH *bvh, int totnode) bvh->node_mem_count *= 1.33; if (bvh->node_mem_count < totnode) bvh->node_mem_count = totnode; - bvh->nodes = MEM_callocN(sizeof(PBVHNode) * bvh->node_mem_count, + bvh->nodes = MEM_mallocN(sizeof(PBVHNode) * bvh->node_mem_count, "bvh nodes"); memcpy(bvh->nodes, prev, bvh->totnode * sizeof(PBVHNode)); + memset(bvh->nodes + bvh->totnode, 0, (bvh->node_mem_count - bvh->totnode) * sizeof(PBVHNode)); MEM_freeN(prev); } @@ -244,9 +245,13 @@ static int map_insert_vert(PBVH *bvh, GHash *map, unsigned int *face_verts, unsigned int *uniq_verts, int vertex) { - void *value, *key = SET_INT_IN_POINTER(vertex); + void *key, **value_p; - if (!BLI_ghash_haskey(map, key)) { + key = SET_INT_IN_POINTER(vertex); + value_p = BLI_ghash_lookup_p(map, key); + + if (value_p == NULL) { + void *value; if (BLI_BITMAP_GET(bvh->vert_bitmap, vertex)) { value = SET_INT_IN_POINTER(~(*face_verts)); ++(*face_verts); @@ -260,8 +265,9 @@ static int map_insert_vert(PBVH *bvh, GHash *map, BLI_ghash_insert(map, key, value); return GET_INT_FROM_POINTER(value); } - else - return GET_INT_FROM_POINTER(BLI_ghash_lookup(map, key)); + else { + return GET_INT_FROM_POINTER(*value_p); + } } /* Find vertices used by the faces in this node and update the draw buffers */ @@ -271,11 +277,12 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node) GHash *map; int i, j, totface; - map = BLI_ghash_int_new("build_mesh_leaf_node gh"); - node->uniq_verts = node->face_verts = 0; totface = node->totprim; + /* reserve size is rough guess */ + map = BLI_ghash_int_new_ex("build_mesh_leaf_node gh", 2 * totface); + node->face_vert_indices = MEM_callocN(sizeof(int) * 4 * totface, "bvh node face vert indices"); @@ -607,9 +614,9 @@ void BKE_pbvh_free(PBVH *bvh) if (node->bm_faces) BLI_ghash_free(node->bm_faces, NULL, NULL); if (node->bm_unique_verts) - BLI_ghash_free(node->bm_unique_verts, NULL, NULL); + BLI_gset_free(node->bm_unique_verts, NULL); if (node->bm_other_verts) - BLI_ghash_free(node->bm_other_verts, NULL, NULL); + BLI_gset_free(node->bm_other_verts, NULL); } } @@ -1307,8 +1314,8 @@ void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to if (uniquevert) *uniquevert = node->uniq_verts; break; case PBVH_BMESH: - tot = BLI_ghash_size(node->bm_unique_verts); - if (totvert) *totvert = tot + BLI_ghash_size(node->bm_other_verts); + tot = BLI_gset_size(node->bm_unique_verts); + if (totvert) *totvert = tot + BLI_gset_size(node->bm_other_verts); if (uniquevert) *uniquevert = tot; break; } @@ -1859,9 +1866,10 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, vi->mverts = verts; if (bvh->type == PBVH_BMESH) { - BLI_ghashIterator_init(&vi->bm_unique_verts, node->bm_unique_verts); - BLI_ghashIterator_init(&vi->bm_other_verts, node->bm_other_verts); + BLI_gsetIterator_init(&vi->bm_unique_verts, node->bm_unique_verts); + BLI_gsetIterator_init(&vi->bm_other_verts, node->bm_other_verts); vi->bm_vdata = &bvh->bm->vdata; + vi->cd_vert_mask_offset = CustomData_get_offset(vi->bm_vdata, CD_PAINT_MASK); } vi->gh = NULL; diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index cd21f8ad968..98f2f7bcf24 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -18,6 +18,10 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/blenkernel/intern/pbvh_bmesh.c + * \ingroup bli + */ + #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -48,8 +52,8 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index) PBVHNode *n = &bvh->nodes[node_index]; /* Create vert hash sets */ - n->bm_unique_verts = BLI_ghash_ptr_new("bm_unique_verts"); - n->bm_other_verts = BLI_ghash_ptr_new("bm_other_verts"); + n->bm_unique_verts = BLI_gset_ptr_new("bm_unique_verts"); + n->bm_other_verts = BLI_gset_ptr_new("bm_other_verts"); BB_reset(&n->vb); @@ -67,13 +71,12 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index) l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { v = l_iter->v; - if (!BLI_ghash_haskey(n->bm_unique_verts, v)) { + if (!BLI_gset_haskey(n->bm_unique_verts, v)) { if (BLI_ghash_haskey(bvh->bm_vert_to_node, v)) { - if (!BLI_ghash_haskey(n->bm_other_verts, v)) - BLI_ghash_insert(n->bm_other_verts, v, NULL); + BLI_gset_reinsert(n->bm_other_verts, v, NULL); } else { - BLI_ghash_insert(n->bm_unique_verts, v, NULL); + BLI_gset_insert(n->bm_unique_verts, v); BLI_ghash_insert(bvh->bm_vert_to_node, v, node_val); } } @@ -92,7 +95,7 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index) if (!G.background) { int smooth = bvh->flags & PBVH_DYNTOPO_SMOOTH_SHADING; n->draw_buffers = GPU_build_bmesh_buffers(smooth); - n->flag |= PBVH_UpdateDrawBuffers; + n->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals; } } @@ -101,6 +104,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index) { GHash *empty, *other; GHashIterator gh_iter; + GSetIterator gs_iter; PBVHNode *n, *c1, *c2; BB cb; float mid; @@ -140,8 +144,8 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index) c2 = &bvh->nodes[children + 1]; c1->flag |= PBVH_Leaf; c2->flag |= PBVH_Leaf; - c1->bm_faces = BLI_ghash_ptr_new("bm_faces"); - c2->bm_faces = BLI_ghash_ptr_new("bm_faces"); + c1->bm_faces = BLI_ghash_ptr_new_ex("bm_faces", BLI_ghash_size(n->bm_faces) / 2); + c2->bm_faces = BLI_ghash_ptr_new_ex("bm_faces", BLI_ghash_size(n->bm_faces) / 2); /* Partition the parent node's faces between the two children */ GHASH_ITER (gh_iter, n->bm_faces) { @@ -177,11 +181,11 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index) /* Mark this node's unique verts as unclaimed */ if (n->bm_unique_verts) { - GHASH_ITER (gh_iter, n->bm_unique_verts) { - BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + GSET_ITER (gs_iter, n->bm_unique_verts) { + BMVert *v = BLI_gsetIterator_getKey(&gs_iter); BLI_ghash_remove(bvh->bm_vert_to_node, v, NULL, NULL); } - BLI_ghash_free(n->bm_unique_verts, NULL, NULL); + BLI_gset_free(n->bm_unique_verts, NULL); } /* Unclaim faces */ @@ -192,7 +196,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index) BLI_ghash_free(n->bm_faces, NULL, NULL); if (n->bm_other_verts) - BLI_ghash_free(n->bm_other_verts, NULL, NULL); + BLI_gset_free(n->bm_other_verts, NULL); if (n->layer_disp) MEM_freeN(n->layer_disp); @@ -227,19 +231,26 @@ static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index) static int pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index) { GHash *prim_bbc; + GHash *bm_faces; + int bm_faces_size; GHashIterator gh_iter; + BBC *bbc_array; + unsigned int i; - if (BLI_ghash_size(bvh->nodes[node_index].bm_faces) <= bvh->leaf_limit) { + bm_faces = bvh->nodes[node_index].bm_faces; + bm_faces_size = BLI_ghash_size(bm_faces); + if (bm_faces_size <= bvh->leaf_limit) { /* Node limit not exceeded */ return FALSE; } /* For each BMFace, store the AABB and AABB centroid */ - prim_bbc = BLI_ghash_ptr_new("prim_bbc"); + prim_bbc = BLI_ghash_ptr_new_ex("prim_bbc", bm_faces_size); + bbc_array = MEM_callocN(sizeof(BBC) * bm_faces_size, "BBC"); - GHASH_ITER (gh_iter, bvh->nodes[node_index].bm_faces) { + GHASH_ITER_INDEX (gh_iter, bm_faces, i) { BMFace *f = BLI_ghashIterator_getKey(&gh_iter); - BBC *bbc = MEM_callocN(sizeof(BBC), "BBC"); + BBC *bbc = &bbc_array[i]; BMLoop *l_iter; BMLoop *l_first; @@ -255,7 +266,8 @@ static int pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index) pbvh_bmesh_node_split(bvh, prim_bbc, node_index); - BLI_ghash_free(prim_bbc, NULL, MEM_freeN); + BLI_ghash_free(prim_bbc, NULL, NULL); + MEM_freeN(bbc_array); return TRUE; } @@ -278,12 +290,12 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *bvh, int node_index, const float co[3], const BMVert *example) { - BMVert *v = BM_vert_create(bvh->bm, co, example, 0); + BMVert *v = BM_vert_create(bvh->bm, co, example, BM_CREATE_NOP); void *val = SET_INT_IN_POINTER(node_index); BLI_assert((bvh->totnode == 1 || node_index) && node_index <= bvh->totnode); - BLI_ghash_insert(bvh->nodes[node_index].bm_unique_verts, v, NULL); + BLI_gset_insert(bvh->nodes[node_index].bm_unique_verts, v); BLI_ghash_insert(bvh->bm_vert_to_node, v, val); /* Log the new vertex */ @@ -302,9 +314,7 @@ static BMFace *pbvh_bmesh_face_create(PBVH *bvh, int node_index, /* ensure we never add existing face */ BLI_assert(BM_face_exists(v_tri, 3, NULL) == false); - f = BM_face_create(bvh->bm, v_tri, e_tri, 3, 0); - // BM_elem_attrs_copy(bvh->bm, bvh->bm, f_example, f); - f->mat_nr = f_example->mat_nr; + f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP); if (!BLI_ghash_haskey(bvh->bm_face_to_node, f)) { @@ -367,15 +377,14 @@ static void pbvh_bmesh_vert_ownership_transfer(PBVH *bvh, PBVHNode *new_owner, BLI_assert(current_owner != new_owner); /* Remove current ownership */ - BLI_ghash_remove(bvh->bm_vert_to_node, v, NULL, NULL); - BLI_ghash_remove(current_owner->bm_unique_verts, v, NULL, NULL); + BLI_gset_remove(current_owner->bm_unique_verts, v, NULL); /* Set new ownership */ - BLI_ghash_insert(bvh->bm_vert_to_node, v, - SET_INT_IN_POINTER(new_owner - bvh->nodes)); - BLI_ghash_insert(new_owner->bm_unique_verts, v, NULL); - BLI_ghash_remove(new_owner->bm_other_verts, v, NULL, NULL); - BLI_assert(!BLI_ghash_haskey(new_owner->bm_other_verts, v)); + BLI_ghash_reinsert(bvh->bm_vert_to_node, v, + SET_INT_IN_POINTER(new_owner - bvh->nodes), NULL, NULL); + BLI_gset_insert(new_owner->bm_unique_verts, v); + BLI_gset_remove(new_owner->bm_other_verts, v, NULL); + BLI_assert(!BLI_gset_haskey(new_owner->bm_other_verts, v)); } static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v) @@ -386,18 +395,20 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v) BLI_assert(BLI_ghash_haskey(bvh->bm_vert_to_node, v)); v_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_vert_to_node, v); - BLI_ghash_remove(v_node->bm_unique_verts, v, NULL, NULL); + BLI_gset_remove(v_node->bm_unique_verts, v, NULL); BLI_ghash_remove(bvh->bm_vert_to_node, v, NULL, NULL); /* Have to check each neighboring face's node */ BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_face_to_node, f); - BLI_ghash_remove(f_node->bm_unique_verts, v, NULL, NULL); - BLI_ghash_remove(f_node->bm_other_verts, v, NULL, NULL); + /* Remove current ownership */ + /* Should be handled above by vert_to_node removal, leaving just in case - psy-fi */ + //BLI_ghash_remove(f_node->bm_unique_verts, v, NULL, NULL); + BLI_gset_remove(f_node->bm_other_verts, v, NULL); - BLI_assert(!BLI_ghash_haskey(f_node->bm_unique_verts, v)); - BLI_assert(!BLI_ghash_haskey(f_node->bm_other_verts, v)); + BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v)); + BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v)); } } @@ -417,7 +428,7 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f) do { v = l_iter->v; if (pbvh_bmesh_node_vert_use_count(bvh, f_node, v) == 1) { - if (BLI_ghash_haskey(f_node->bm_unique_verts, v)) { + if (BLI_gset_haskey(f_node->bm_unique_verts, v)) { /* Find a different node that uses 'v' */ PBVHNode *new_node; @@ -430,7 +441,7 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f) } else { /* Remove from other verts */ - BLI_ghash_remove(f_node->bm_other_verts, v, NULL, NULL); + BLI_gset_remove(f_node->bm_other_verts, v, NULL); } } } while ((l_iter = l_iter->next) != l_first); @@ -479,6 +490,13 @@ typedef struct { float limit_len_squared; } EdgeQueue; +typedef struct { + EdgeQueue *q; + BLI_mempool *pool; + BMesh *bm; + int cd_vert_mask_offset; +} EdgeQueueContext; + static int edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f) { BMVert *v_tri[3]; @@ -494,74 +512,73 @@ static int edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f) return ((len_squared_v3v3(q->center, c) <= q->radius_squared)); } -/* Return true if the vertex mask is less than 0.5, false otherwise */ -static int check_mask_half(BMesh *bm, BMVert *v) +/* Return true if the vertex mask is less than 1.0, false otherwise */ +static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v) { - const float *mask; - - mask = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_PAINT_MASK); - return ((*mask) < 0.5f); + return (BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f); } -static void edge_queue_insert(EdgeQueue *q, BLI_mempool *pool, BMEdge *e, - float priority, BMesh *bm) +static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e, + float priority) { BMVert **pair; - /* Don't let topology update affect masked vertices. Unlike with - * displacements, can't do 50% topology update, so instead set - * (arbitrary) cutoff: if both vertices' masks are less than 50%, - * topology update can happen. */ - if (check_mask_half(bm, e->v1) && check_mask_half(bm, e->v2)) { - pair = BLI_mempool_alloc(pool); + /* Don't let topology update affect fully masked vertices. This used to + * have a 50% mask cutoff, with the reasoning that you can't do a 50% + * topology update. But this gives an ugly border in the mesh. The mask + * should already make the brush move the vertices only 50%, which means + * that topology updates will also happen less frequent, that should be + * enough. */ + if (check_mask(eq_ctx, e->v1) || check_mask(eq_ctx, e->v2)) { + pair = BLI_mempool_alloc(eq_ctx->pool); pair[0] = e->v1; pair[1] = e->v2; - BLI_heap_insert(q->heap, priority, pair); + BLI_heap_insert(eq_ctx->q->heap, priority, pair); } } -static void long_edge_queue_edge_add(EdgeQueue *q, BLI_mempool *pool, - BMEdge *e, BMesh *bm) +static void long_edge_queue_edge_add(EdgeQueueContext *eq_ctx, + BMEdge *e) { const float len_sq = BM_edge_calc_length_squared(e); - if (len_sq > q->limit_len_squared) - edge_queue_insert(q, pool, e, 1.0f / len_sq, bm); + if (len_sq > eq_ctx->q->limit_len_squared) + edge_queue_insert(eq_ctx, e, 1.0f / len_sq); } -static void short_edge_queue_edge_add(EdgeQueue *q, BLI_mempool *pool, - BMEdge *e, BMesh *bm) +static void short_edge_queue_edge_add(EdgeQueueContext *eq_ctx, + BMEdge *e) { const float len_sq = BM_edge_calc_length_squared(e); - if (len_sq < q->limit_len_squared) - edge_queue_insert(q, pool, e, len_sq, bm); + if (len_sq < eq_ctx->q->limit_len_squared) + edge_queue_insert(eq_ctx, e, len_sq); } -static void long_edge_queue_face_add(EdgeQueue *q, BLI_mempool *pool, - BMFace *f, BMesh *bm) +static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx, + BMFace *f) { - if (edge_queue_tri_in_sphere(q, f)) { + if (edge_queue_tri_in_sphere(eq_ctx->q, f)) { BMLoop *l_iter; BMLoop *l_first; /* Check each edge of the face */ l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - long_edge_queue_edge_add(q, pool, l_iter->e, bm); + long_edge_queue_edge_add(eq_ctx, l_iter->e); } while ((l_iter = l_iter->next) != l_first); } } -static void short_edge_queue_face_add(EdgeQueue *q, BLI_mempool *pool, - BMFace *f, BMesh *bm) +static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx, + BMFace *f) { - if (edge_queue_tri_in_sphere(q, f)) { + if (edge_queue_tri_in_sphere(eq_ctx->q, f)) { BMLoop *l_iter; BMLoop *l_first; /* Check each edge of the face */ l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - short_edge_queue_edge_add(q, pool, l_iter->e, bm); + short_edge_queue_edge_add(eq_ctx, l_iter->e); } while ((l_iter = l_iter->next) != l_first); } } @@ -575,16 +592,16 @@ static void short_edge_queue_face_add(EdgeQueue *q, BLI_mempool *pool, * * The highest priority (lowest number) is given to the longest edge. */ -static void long_edge_queue_create(EdgeQueue *q, BLI_mempool *pool, +static void long_edge_queue_create(EdgeQueueContext *eq_ctx, PBVH *bvh, const float center[3], float radius) { int n; - q->heap = BLI_heap_new(); - q->center = center; - q->radius_squared = radius * radius; - q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len; + eq_ctx->q->heap = BLI_heap_new(); + eq_ctx->q->center = center; + eq_ctx->q->radius_squared = radius * radius; + eq_ctx->q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len; for (n = 0; n < bvh->totnode; n++) { PBVHNode *node = &bvh->nodes[n]; @@ -599,7 +616,7 @@ static void long_edge_queue_create(EdgeQueue *q, BLI_mempool *pool, GHASH_ITER (gh_iter, node->bm_faces) { BMFace *f = BLI_ghashIterator_getKey(&gh_iter); - long_edge_queue_face_add(q, pool, f, bvh->bm); + long_edge_queue_face_add(eq_ctx, f); } } } @@ -614,16 +631,16 @@ static void long_edge_queue_create(EdgeQueue *q, BLI_mempool *pool, * * The highest priority (lowest number) is given to the shortest edge. */ -static void short_edge_queue_create(EdgeQueue *q, BLI_mempool *pool, +static void short_edge_queue_create(EdgeQueueContext *eq_ctx, PBVH *bvh, const float center[3], float radius) { int n; - q->heap = BLI_heap_new(); - q->center = center; - q->radius_squared = radius * radius; - q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len; + eq_ctx->q->heap = BLI_heap_new(); + eq_ctx->q->center = center; + eq_ctx->q->radius_squared = radius * radius; + eq_ctx->q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len; for (n = 0; n < bvh->totnode; n++) { PBVHNode *node = &bvh->nodes[n]; @@ -638,7 +655,7 @@ static void short_edge_queue_create(EdgeQueue *q, BLI_mempool *pool, GHASH_ITER (gh_iter, node->bm_faces) { BMFace *f = BLI_ghashIterator_getKey(&gh_iter); - short_edge_queue_face_add(q, pool, f, bvh->bm); + short_edge_queue_face_add(eq_ctx, f); } } } @@ -653,12 +670,13 @@ static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3]) e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE); } -static void pbvh_bmesh_split_edge(PBVH *bvh, EdgeQueue *q, BLI_mempool *pool, +static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh, BMEdge *e, BLI_Buffer *edge_loops) { BMVert *v_new; float mid[3]; int i, node_index; + const int cd_vert_mask_offset = CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK); /* Get all faces adjacent to the edge */ pbvh_bmesh_edge_loops(edge_loops, e); @@ -670,6 +688,15 @@ static void pbvh_bmesh_split_edge(PBVH *bvh, EdgeQueue *q, BLI_mempool *pool, e->v1)); v_new = pbvh_bmesh_vert_create(bvh, node_index, mid, e->v1); + /* update paint mask */ + if (cd_vert_mask_offset != -1) { + float mask_v1 = BM_ELEM_CD_GET_FLOAT(e->v1, cd_vert_mask_offset); + float mask_v2 = BM_ELEM_CD_GET_FLOAT(e->v2, cd_vert_mask_offset); + float mask_v_new = 0.5f*(mask_v1 + mask_v2); + + BM_ELEM_CD_SET_FLOAT(v_new, cd_vert_mask_offset, mask_v_new); + } + /* For each face, add two new triangles and delete the original */ for (i = 0; i < edge_loops->count; i++) { BMLoop *l_adj = BLI_buffer_at(edge_loops, BMLoop *, i); @@ -686,7 +713,7 @@ static void pbvh_bmesh_split_edge(PBVH *bvh, EdgeQueue *q, BLI_mempool *pool, ni = GET_INT_FROM_POINTER(nip); /* Ensure node gets redrawn */ - bvh->nodes[ni].flag |= PBVH_UpdateDrawBuffers; + bvh->nodes[ni].flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals; /* Find the vertex not in the edge */ v_opp = l_adj->prev->v; @@ -706,7 +733,7 @@ static void pbvh_bmesh_split_edge(PBVH *bvh, EdgeQueue *q, BLI_mempool *pool, v_tri[2] = v_opp; bm_edges_from_tri(bvh->bm, v_tri, e_tri); f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj); - long_edge_queue_face_add(q, pool, f_new, bvh->bm); + long_edge_queue_face_add(eq_ctx, f_new); v_tri[0] = v_new; v_tri[1] = v2; @@ -715,17 +742,17 @@ static void pbvh_bmesh_split_edge(PBVH *bvh, EdgeQueue *q, BLI_mempool *pool, e_tri[2] = e_tri[1]; /* switched */ e_tri[1] = BM_edge_create(bvh->bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE); f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj); - long_edge_queue_face_add(q, pool, f_new, bvh->bm); + long_edge_queue_face_add(eq_ctx, f_new); /* Delete original */ pbvh_bmesh_face_remove(bvh, f_adj); BM_face_kill(bvh->bm, f_adj); /* Ensure new vertex is in the node */ - if (!BLI_ghash_haskey(bvh->nodes[ni].bm_unique_verts, v_new) && - !BLI_ghash_haskey(bvh->nodes[ni].bm_other_verts, v_new)) + if (!BLI_gset_haskey(bvh->nodes[ni].bm_unique_verts, v_new) && + !BLI_gset_haskey(bvh->nodes[ni].bm_other_verts, v_new)) { - BLI_ghash_insert(bvh->nodes[ni].bm_other_verts, v_new, NULL); + BLI_gset_insert(bvh->nodes[ni].bm_other_verts, v_new); } if (BM_vert_edge_count(v_opp) >= 9) { @@ -733,7 +760,7 @@ static void pbvh_bmesh_split_edge(PBVH *bvh, EdgeQueue *q, BLI_mempool *pool, BMEdge *e2; BM_ITER_ELEM (e2, &bm_iter, v_opp, BM_EDGES_OF_VERT) { - long_edge_queue_edge_add(q, pool, e2, bvh->bm); + long_edge_queue_edge_add(eq_ctx, e2); } } } @@ -741,23 +768,22 @@ static void pbvh_bmesh_split_edge(PBVH *bvh, EdgeQueue *q, BLI_mempool *pool, BM_edge_kill(bvh->bm, e); } -static int pbvh_bmesh_subdivide_long_edges(PBVH *bvh, EdgeQueue *q, - BLI_mempool *pool, +static int pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, PBVH *bvh, BLI_Buffer *edge_loops) { int any_subdivided = FALSE; - while (!BLI_heap_is_empty(q->heap)) { - BMVert **pair = BLI_heap_popmin(q->heap); + while (!BLI_heap_is_empty(eq_ctx->q->heap)) { + BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap); BMEdge *e; /* Check that the edge still exists */ if (!(e = BM_edge_exists(pair[0], pair[1]))) { - BLI_mempool_free(pool, pair); + BLI_mempool_free(eq_ctx->pool, pair); continue; } - BLI_mempool_free(pool, pair); + BLI_mempool_free(eq_ctx->pool, pair); pair = NULL; /* Check that the edge's vertices are still in the PBVH. It's @@ -770,12 +796,12 @@ static int pbvh_bmesh_subdivide_long_edges(PBVH *bvh, EdgeQueue *q, continue; } - if (BM_edge_calc_length_squared(e) <= q->limit_len_squared) + if (BM_edge_calc_length_squared(e) <= eq_ctx->q->limit_len_squared) continue; any_subdivided = TRUE; - pbvh_bmesh_split_edge(bvh, q, pool, e, edge_loops); + pbvh_bmesh_split_edge(eq_ctx, bvh, e, edge_loops); } return any_subdivided; @@ -846,10 +872,10 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e, BMVert *v1, pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f); /* Ensure that v1 is in the new face's node */ - if (!BLI_ghash_haskey(n->bm_unique_verts, v1) && - !BLI_ghash_haskey(n->bm_other_verts, v1)) + if (!BLI_gset_haskey(n->bm_unique_verts, v1) && + !BLI_gset_haskey(n->bm_other_verts, v1)) { - BLI_ghash_insert(n->bm_other_verts, v1, NULL); + BLI_gset_insert(n->bm_other_verts, v1); } } @@ -917,8 +943,8 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e, BMVert *v1, BM_vert_kill(bvh->bm, v2); } -static int pbvh_bmesh_collapse_short_edges(PBVH *bvh, EdgeQueue *q, - BLI_mempool *pool, +static int pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx, + PBVH *bvh, BLI_Buffer *edge_loops, BLI_Buffer *deleted_faces) { @@ -928,14 +954,14 @@ static int pbvh_bmesh_collapse_short_edges(PBVH *bvh, EdgeQueue *q, deleted_verts = BLI_ghash_ptr_new("deleted_verts"); - while (!BLI_heap_is_empty(q->heap)) { - BMVert **pair = BLI_heap_popmin(q->heap); + while (!BLI_heap_is_empty(eq_ctx->q->heap)) { + BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap); BMEdge *e; BMVert *v1, *v2; v1 = pair[0]; v2 = pair[1]; - BLI_mempool_free(pool, pair); + BLI_mempool_free(eq_ctx->pool, pair); pair = NULL; /* Check that the vertices/edge still exist */ @@ -1012,19 +1038,29 @@ int pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3], return hit; } + void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode) { int n; for (n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; - GHashIterator gh_iter; - GHASH_ITER (gh_iter, node->bm_faces) { - BM_face_normal_update(BLI_ghashIterator_getKey(&gh_iter)); - } - GHASH_ITER (gh_iter, node->bm_unique_verts) { - BM_vert_normal_update(BLI_ghashIterator_getKey(&gh_iter)); + if (node->flag & PBVH_UpdateNormals) { + GHashIterator gh_iter; + GSetIterator gs_iter; + + GHASH_ITER (gh_iter, node->bm_faces) { + BM_face_normal_update(BLI_ghashIterator_getKey(&gh_iter)); + } + GSET_ITER (gs_iter, node->bm_unique_verts) { + BM_vert_normal_update(BLI_gsetIterator_getKey(&gs_iter)); + } + /* This should be unneeded normally */ + GSET_ITER (gs_iter, node->bm_other_verts) { + BM_vert_normal_update(BLI_gsetIterator_getKey(&gs_iter)); + } + node->flag &= ~PBVH_UpdateNormals; } } } @@ -1059,7 +1095,7 @@ void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, int smooth_shading, n = bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode"); bvh->totnode = 1; n->flag = PBVH_Leaf; - n->bm_faces = BLI_ghash_ptr_new("bm_faces"); + n->bm_faces = BLI_ghash_ptr_new_ex("bm_faces", bvh->bm->totface); BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) { BLI_ghash_insert(n->bm_faces, f, NULL); } @@ -1077,6 +1113,7 @@ int BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, /* 2 is enough for edge faces - manifold edge */ BLI_buffer_declare_static(BMFace *, edge_loops, BLI_BUFFER_NOP, 2); BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32); + const int cd_vert_mask_offset = CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK); int modified = FALSE; int n; @@ -1085,8 +1122,10 @@ int BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, EdgeQueue q; BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert) * 2, 128, 128, 0); - short_edge_queue_create(&q, queue_pool, bvh, center, radius); - pbvh_bmesh_collapse_short_edges(bvh, &q, queue_pool, &edge_loops, + EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset}; + + short_edge_queue_create(&eq_ctx, bvh, center, radius); + pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh, &edge_loops, &deleted_faces); BLI_heap_free(q.heap, NULL); BLI_mempool_destroy(queue_pool); @@ -1096,8 +1135,10 @@ int BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, EdgeQueue q; BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert) * 2, 128, 128, 0); - long_edge_queue_create(&q, queue_pool, bvh, center, radius); - pbvh_bmesh_subdivide_long_edges(bvh, &q, queue_pool, &edge_loops); + EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset}; + + long_edge_queue_create(&eq_ctx, bvh, center, radius); + pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops); BLI_heap_free(q.heap, NULL); BLI_mempool_destroy(queue_pool); } @@ -1136,14 +1177,15 @@ BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3]) void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node) { GHashIterator gh_iter; + GSetIterator gs_iter; int i, totvert, tottri; /* Skip if original coords/triangles are already saved */ if (node->bm_orco) return; - totvert = (BLI_ghash_size(node->bm_unique_verts) + - BLI_ghash_size(node->bm_other_verts)); + totvert = (BLI_gset_size(node->bm_unique_verts) + + BLI_gset_size(node->bm_other_verts)); tottri = BLI_ghash_size(node->bm_faces); @@ -1152,14 +1194,14 @@ void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node) /* Copy out the vertices and assign a temporary index */ i = 0; - GHASH_ITER (gh_iter, node->bm_unique_verts) { - BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + GSET_ITER (gs_iter, node->bm_unique_verts) { + BMVert *v = BLI_gsetIterator_getKey(&gs_iter); copy_v3_v3(node->bm_orco[i], v->co); BM_elem_index_set(v, i); /* set_dirty! */ i++; } - GHASH_ITER (gh_iter, node->bm_other_verts) { - BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + GSET_ITER (gs_iter, node->bm_other_verts) { + BMVert *v = BLI_gsetIterator_getKey(&gs_iter); copy_v3_v3(node->bm_orco[i], v->co); BM_elem_index_set(v, i); /* set_dirty! */ i++; @@ -1216,12 +1258,12 @@ void BKE_pbvh_node_mark_topology_update(PBVHNode *node) node->flag |= PBVH_UpdateTopology; } -GHash *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node) +GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node) { return node->bm_unique_verts; } -GHash *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node) +GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node) { return node->bm_other_verts; } @@ -1250,6 +1292,27 @@ void bli_ghash_duplicate_key_check(GHash *gh) } } +void bli_gset_duplicate_key_check(GSet *gs) +{ + GSetIterator gs_iter1, gs_iter2; + + GSET_ITER (gs_iter1, gs) { + void *key1 = BLI_gsetIterator_getKey(&gs_iter1); + int dup = -1; + + GSET_ITER (gs_iter2, gs) { + void *key2 = BLI_gsetIterator_getKey(&gs_iter2); + + if (key1 == key2) { + dup++; + if (dup > 0) { + BLI_assert(!"duplicate in hash"); + } + } + } + } +} + void bmesh_print(BMesh *bm) { BMIter iter, siter; @@ -1264,14 +1327,14 @@ void bmesh_print(BMesh *bm) bm->totloop, bm->totface); fprintf(stderr, "vertices:\n"); - BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { fprintf(stderr, " %d co=(%.3f %.3f %.3f) oflag=%x\n", BM_elem_index_get(v), v->co[0], v->co[1], v->co[2], v->oflags[bm->stackdepth - 1].f); } fprintf(stderr, "edges:\n"); - BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { fprintf(stderr, " %d v1=%d, v2=%d, oflag=%x\n", BM_elem_index_get(e), BM_elem_index_get(e->v1), @@ -1280,7 +1343,7 @@ void bmesh_print(BMesh *bm) } fprintf(stderr, "faces:\n"); - BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { fprintf(stderr, " %d len=%d, oflag=%x\n", BM_elem_index_get(f), f->len, f->oflags[bm->stackdepth - 1].f); @@ -1311,6 +1374,7 @@ void bmesh_print(BMesh *bm) void pbvh_bmesh_print(PBVH *bvh) { GHashIterator gh_iter; + GSetIterator gs_iter; int n; fprintf(stderr, "\npbvh=%p\n", bvh); @@ -1338,13 +1402,13 @@ void pbvh_bmesh_print(PBVH *bvh) fprintf(stderr, " %d\n", BM_elem_index_get((BMFace *)BLI_ghashIterator_getKey(&gh_iter))); fprintf(stderr, " unique verts:\n"); - GHASH_ITER (gh_iter, node->bm_unique_verts) + GSET_ITER (gs_iter, node->bm_unique_verts) fprintf(stderr, " %d\n", - BM_elem_index_get((BMVert *)BLI_ghashIterator_getKey(&gh_iter))); + BM_elem_index_get((BMVert *)BLI_gsetIterator_getKey(&gs_iter))); fprintf(stderr, " other verts:\n"); - GHASH_ITER (gh_iter, node->bm_other_verts) + GSET_ITER (gs_iter, node->bm_other_verts) fprintf(stderr, " %d\n", - BM_elem_index_get((BMVert *)BLI_ghashIterator_getKey(&gh_iter))); + BM_elem_index_get((BMVert *)BLI_gsetIterator_getKey(&gs_iter))); } } @@ -1362,7 +1426,10 @@ void print_flag_factors(int flag) void pbvh_bmesh_verify(PBVH *bvh) { GHashIterator gh_iter; - int i; + GSetIterator gs_iter; + int i, vert_count = 0; + BMIter iter; + BMVert *vi; /* Check faces */ BLI_assert(bvh->bm->totface == BLI_ghash_size(bvh->bm_face_to_node)); @@ -1385,17 +1452,17 @@ void pbvh_bmesh_verify(PBVH *bvh) PBVHNode *nv; /* Check that the vertex is in the node */ - BLI_assert(BLI_ghash_haskey(n->bm_unique_verts, v) ^ - BLI_ghash_haskey(n->bm_other_verts, v)); + BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^ + BLI_gset_haskey(n->bm_other_verts, v)); /* Check that the vertex has a node owner */ nv = pbvh_bmesh_node_lookup(bvh, bvh->bm_vert_to_node, v); /* Check that the vertex's node knows it owns the vert */ - BLI_assert(BLI_ghash_haskey(nv->bm_unique_verts, v)); + BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v)); /* Check that the vertex isn't duplicated as an 'other' vert */ - BLI_assert(!BLI_ghash_haskey(nv->bm_other_verts, v)); + BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v)); } } @@ -1414,10 +1481,10 @@ void pbvh_bmesh_verify(PBVH *bvh) BLI_assert(n->flag & PBVH_Leaf); /* Check that the vert's node knows it owns the vert */ - BLI_assert(BLI_ghash_haskey(n->bm_unique_verts, v)); + BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v)); /* Check that the vertex isn't duplicated as an 'other' vert */ - BLI_assert(!BLI_ghash_haskey(n->bm_other_verts, v)); + BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v)); /* Check that the vert's node also contains one of the vert's * adjacent faces */ @@ -1428,8 +1495,37 @@ void pbvh_bmesh_verify(PBVH *bvh) } } BLI_assert(found); + + #if 1 + /* total freak stuff, check if node exists somewhere else */ + /* Slow */ + for (i = 0; i < bvh->totnode; i++) { + PBVHNode *n = &bvh->nodes[i]; + if (i != ni && n->bm_unique_verts) + BLI_assert(!BLI_gset_haskey(n->bm_unique_verts, v)); + } + + #endif } + #if 0 + /* check that every vert belongs somewhere */ + /* Slow */ + BM_ITER_MESH (vi, &iter, bvh->bm, BM_VERTS_OF_MESH) { + bool has_unique = false; + for (i = 0; i < bvh->totnode; i++) { + PBVHNode *n = &bvh->nodes[i]; + if ((n->bm_unique_verts != NULL) && BLI_gset_haskey(n->bm_unique_verts, vi)) + has_unique = true; + } + BLI_assert(has_unique); + vert_count++; + } + + /* if totvert differs from number of verts inside the hash. hash-totvert is checked above */ + BLI_assert(vert_count == bvh->bm->totvert); + #endif + /* Check that node elements are recorded in the top level */ for (i = 0; i < bvh->totnode; i++) { PBVHNode *n = &bvh->nodes[i]; @@ -1438,8 +1534,8 @@ void pbvh_bmesh_verify(PBVH *bvh) /* Slow */ #if 0 bli_ghash_duplicate_key_check(n->bm_faces); - bli_ghash_duplicate_key_check(n->bm_unique_verts); - bli_ghash_duplicate_key_check(n->bm_other_verts); + bli_gset_duplicate_key_check(n->bm_unique_verts); + bli_gset_duplicate_key_check(n->bm_other_verts); #endif GHASH_ITER (gh_iter, n->bm_faces) { @@ -1449,16 +1545,16 @@ void pbvh_bmesh_verify(PBVH *bvh) BLI_assert(GET_INT_FROM_POINTER(nip) == (n - bvh->nodes)); } - GHASH_ITER (gh_iter, n->bm_unique_verts) { - BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + GSET_ITER (gs_iter, n->bm_unique_verts) { + BMVert *v = BLI_gsetIterator_getKey(&gs_iter); void *nip = BLI_ghash_lookup(bvh->bm_vert_to_node, v); BLI_assert(BLI_ghash_haskey(bvh->bm_vert_to_node, v)); - BLI_assert(!BLI_ghash_haskey(n->bm_other_verts, v)); + BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v)); BLI_assert(GET_INT_FROM_POINTER(nip) == (n - bvh->nodes)); } - GHASH_ITER (gh_iter, n->bm_other_verts) { - BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + GSET_ITER (gs_iter, n->bm_other_verts) { + BMVert *v = BLI_gsetIterator_getKey(&gs_iter); BLI_assert(BLI_ghash_haskey(bvh->bm_vert_to_node, v)); BLI_assert(BM_vert_face_count(v) > 0); } diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index 4154b8e4799..89bfbc252a8 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -21,6 +21,10 @@ #ifndef __PBVH_INTERN_H__ #define __PBVH_INTERN_H__ +/** \file blender/blenkernel/intern/pbvh_intern.h + * \ingroup bli + */ + /* Axis-aligned bounding box */ typedef struct { float bmin[3], bmax[3]; @@ -101,8 +105,8 @@ struct PBVHNode { /* Dyntopo */ GHash *bm_faces; - GHash *bm_unique_verts; - GHash *bm_other_verts; + GSet *bm_unique_verts; + GSet *bm_other_verts; float (*bm_orco)[3]; int (*bm_ortri)[3]; int bm_tot_ortri; diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 93f6965e97b..9891a8cde28 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -66,6 +66,7 @@ #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_pointcache.h" @@ -227,6 +228,11 @@ static int ptcache_softbody_totpoint(void *soft_v, int UNUSED(cfra)) SoftBody *soft= soft_v; return soft->totpoint; } +static void ptcache_softbody_error(void *UNUSED(soft_v), const char *UNUSED(message)) +{ + /* ignored for now */ +} + /* Particle functions */ void BKE_ptcache_make_particle_key(ParticleKey *key, int index, void **data, float time) { @@ -405,6 +411,12 @@ static int ptcache_particle_totpoint(void *psys_v, int UNUSED(cfra)) ParticleSystem *psys = psys_v; return psys->totpart; } + +static void ptcache_particle_error(void *UNUSED(psys_v), const char *UNUSED(message)) +{ + /* ignored for now */ +} + static int ptcache_particle_totwrite(void *psys_v, int cfra) { ParticleSystem *psys = psys_v; @@ -534,6 +546,12 @@ static int ptcache_cloth_totpoint(void *cloth_v, int UNUSED(cfra)) return clmd->clothObject ? clmd->clothObject->numverts : 0; } +static void ptcache_cloth_error(void *cloth_v, const char *message) +{ + ClothModifierData *clmd= cloth_v; + modifier_setError(&clmd->modifier, "%s", message); +} + #ifdef WITH_SMOKE /* Smoke functions */ static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra)) @@ -548,6 +566,12 @@ static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra)) return 0; } +static void ptcache_smoke_error(void *smoke_v, const char *message) +{ + SmokeModifierData *smd= (SmokeModifierData *)smoke_v; + modifier_setError(&smd->modifier, "%s", message); +} + #define SMOKE_CACHE_VERSION "1.04" static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v) @@ -865,8 +889,10 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v) return 1; } + #else // WITH_SMOKE static int ptcache_smoke_totpoint(void *UNUSED(smoke_v), int UNUSED(cfra)) { return 0; } +static void ptcache_smoke_error(void *UNUSED(smoke_v), const char *UNUSED(message)) { } static int ptcache_smoke_read(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) { return 0; } static int ptcache_smoke_write(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) { return 0; } #endif // WITH_SMOKE @@ -879,6 +905,11 @@ static int ptcache_dynamicpaint_totpoint(void *sd, int UNUSED(cfra)) else return surface->data->total_points; } +static void ptcache_dynamicpaint_error(void *UNUSED(sd), const char *UNUSED(message)) +{ + /* ignored for now */ +} + #define DPAINT_CACHE_VERSION "1.01" static int ptcache_dynamicpaint_write(PTCacheFile *pf, void *dp_v) @@ -1055,6 +1086,11 @@ static int ptcache_rigidbody_totpoint(void *rb_v, int UNUSED(cfra)) return rbw->numbodies; } +static void ptcache_rigidbody_error(void *UNUSED(rb_v), const char *UNUSED(message)) +{ + /* ignored for now */ +} + /* Creating ID's */ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) { @@ -1067,6 +1103,7 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) pid->cache_ptr= &sb->pointcache; pid->ptcaches= &sb->ptcaches; pid->totpoint= pid->totwrite= ptcache_softbody_totpoint; + pid->error = ptcache_softbody_error; pid->write_point = ptcache_softbody_write; pid->read_point = ptcache_softbody_read; @@ -1107,6 +1144,7 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p pid->totpoint = ptcache_particle_totpoint; pid->totwrite = ptcache_particle_totwrite; + pid->error = ptcache_particle_error; pid->write_point = ptcache_particle_write; pid->read_point = ptcache_particle_read; @@ -1159,6 +1197,7 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl pid->cache_ptr= &clmd->point_cache; pid->ptcaches= &clmd->ptcaches; pid->totpoint= pid->totwrite= ptcache_cloth_totpoint; + pid->error = ptcache_cloth_error; pid->write_point = ptcache_cloth_write; pid->read_point = ptcache_cloth_read; @@ -1197,6 +1236,7 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo pid->ptcaches= &(sds->ptcaches[0]); pid->totpoint= pid->totwrite= ptcache_smoke_totpoint; + pid->error = ptcache_smoke_error; pid->write_point = NULL; pid->read_point = NULL; @@ -1236,6 +1276,7 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu pid->cache_ptr= &surface->pointcache; pid->ptcaches= &surface->ptcaches; pid->totpoint= pid->totwrite= ptcache_dynamicpaint_totpoint; + pid->error = ptcache_dynamicpaint_error; pid->write_point = NULL; pid->read_point = NULL; @@ -1272,6 +1313,7 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r pid->cache_ptr= &rbw->pointcache; pid->ptcaches= &rbw->ptcaches; pid->totpoint= pid->totwrite= ptcache_rigidbody_totpoint; + pid->error = ptcache_rigidbody_error; pid->write_point = ptcache_rigidbody_write; pid->read_point = ptcache_rigidbody_read; @@ -2083,21 +2125,31 @@ static int ptcache_read_stream(PTCacheID *pid, int cfra) return 0; } - if (!ptcache_file_header_begin_read(pf)) + if (!ptcache_file_header_begin_read(pf)) { + pid->error(pid->calldata, "Failed to read point cache file"); error = 1; - - if (!error && (pf->type != pid->type || !pid->read_header(pf))) + } + else if (pf->type != pid->type) { + pid->error(pid->calldata, "Point cache file has wrong type"); error = 1; - - if (!error && pf->totpoint != pid->totpoint(pid->calldata, cfra)) + } + else if (!pid->read_header(pf)) { + pid->error(pid->calldata, "Failed to read point cache file header"); + error = 1; + } + else if (pf->totpoint != pid->totpoint(pid->calldata, cfra)) { + pid->error(pid->calldata, "Number of points in cache does not match mesh"); error = 1; + } if (!error) { ptcache_file_pointers_init(pf); // we have stream reading here - if (!pid->read_stream(pf, pid->calldata)) + if (!pid->read_stream(pf, pid->calldata)) { + pid->error(pid->calldata, "Failed to read point cache file data"); error = 1; + } } ptcache_file_close(pf); @@ -2125,8 +2177,14 @@ static int ptcache_read(PTCacheID *pid, int cfra) if (pm) { int totpoint = pm->totpoint; - if ((pid->data_types & (1<<BPHYS_DATA_INDEX)) == 0) - totpoint = MIN2(totpoint, pid->totpoint(pid->calldata, cfra)); + if ((pid->data_types & (1<<BPHYS_DATA_INDEX)) == 0) { + int pid_totpoint = pid->totpoint(pid->calldata, cfra); + + if (totpoint != pid_totpoint) { + pid->error(pid->calldata, "Number of points in cache does not match mesh"); + totpoint = MIN2(totpoint, pid_totpoint); + } + } BKE_ptcache_mem_pointers_init(pm); @@ -2173,8 +2231,14 @@ static int ptcache_interpolate(PTCacheID *pid, float cfra, int cfra1, int cfra2) if (pm) { int totpoint = pm->totpoint; - if ((pid->data_types & (1<<BPHYS_DATA_INDEX)) == 0) - totpoint = MIN2(totpoint, pid->totpoint(pid->calldata, (int)cfra)); + if ((pid->data_types & (1<<BPHYS_DATA_INDEX)) == 0) { + int pid_totpoint = pid->totpoint(pid->calldata, (int)cfra); + + if (totpoint != pid_totpoint) { + pid->error(pid->calldata, "Number of points in cache does not match mesh"); + totpoint = MIN2(totpoint, pid_totpoint); + } + } BKE_ptcache_mem_pointers_init(pm); @@ -2969,12 +3033,10 @@ void BKE_ptcache_free(PointCache *cache) } void BKE_ptcache_free_list(ListBase *ptcaches) { - PointCache *cache = ptcaches->first; + PointCache *cache; - while (cache) { - BLI_remlink(ptcaches, cache); + while ((cache = BLI_pophead(ptcaches))) { BKE_ptcache_free(cache); - cache = ptcaches->first; } } diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c index 73f2a864e32..bb04d548a44 100644 --- a/source/blender/blenkernel/intern/property.c +++ b/source/blender/blenkernel/intern/property.c @@ -59,9 +59,8 @@ void BKE_bproperty_free(bProperty *prop) void BKE_bproperty_free_list(ListBase *lb) { bProperty *prop; - - while ( (prop = lb->first) ) { - BLI_remlink(lb, prop); + + while ((prop = BLI_pophead(lb))) { BKE_bproperty_free(prop); } } diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index f3276992381..42147be33e4 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -1166,7 +1166,7 @@ static void rigidbody_update_simulation_post_step(RigidBodyWorld *rbw) if (ob) { RigidBodyOb *rbo = ob->rigidbody_object; /* reset kinematic state for transformed objects */ - if (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ) { + if (rbo && (ob->flag & SELECT) && (G.moving & G_TRANSFORM_OBJ)) { RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED); RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); /* deactivate passive objects so they don't interfere with deactivation of active objects */ diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index 92f57a54a01..7c374fd5d78 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -63,8 +63,7 @@ void free_sensors(ListBase *lb) { bSensor *sens; - while ((sens= lb->first)) { - BLI_remlink(lb, sens); + while ((sens = BLI_pophead(lb))) { free_sensor(sens); } } @@ -113,9 +112,6 @@ void init_sensor(bSensor *sens) case SENS_ALWAYS: sens->pulse = 0; break; - case SENS_TOUCH: - sens->data= MEM_callocN(sizeof(bTouchSensor), "touchsens"); - break; case SENS_NEAR: ns=sens->data= MEM_callocN(sizeof(bNearSensor), "nearsens"); ns->dist= 1.0; @@ -227,9 +223,9 @@ void free_controllers(ListBase *lb) { bController *cont; - while ((cont= lb->first)) { - BLI_remlink(lb, cont); - if (cont->slinks) MEM_freeN(cont->slinks); + while ((cont = BLI_pophead(lb))) { + if (cont->slinks) + MEM_freeN(cont->slinks); free_controller(cont); } } @@ -346,8 +342,7 @@ void free_actuators(ListBase *lb) { bActuator *act; - while ((act= lb->first)) { - BLI_remlink(lb, act); + while ((act = BLI_pophead(lb))) { free_actuator(act); } } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 1874523dac9..41e43c00457 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -44,6 +44,7 @@ #include "DNA_anim_types.h" #include "DNA_group_types.h" +#include "DNA_linestyle_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_rigidbody_types.h" @@ -429,7 +430,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name) sce->r.filtertype = R_FILTER_MITCH; sce->r.size = 50; - sce->r.im_format.planes = R_IMF_PLANES_RGB; + sce->r.im_format.planes = R_IMF_PLANES_RGBA; sce->r.im_format.imtype = R_IMF_IMTYPE_PNG; sce->r.im_format.depth = R_IMF_CHAN_DEPTH_8; sce->r.im_format.quality = 90; @@ -492,23 +493,10 @@ Scene *BKE_scene_add(Main *bmain, const char *name) sce->r.border.ymax = 1.0f; sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct"); - sce->toolsettings->cornertype = 1; - sce->toolsettings->degr = 90; - sce->toolsettings->step = 9; - sce->toolsettings->turn = 1; - sce->toolsettings->extr_offs = 1; sce->toolsettings->doublimit = 0.001; - sce->toolsettings->segments = 32; - sce->toolsettings->rings = 32; - sce->toolsettings->vertices = 32; - sce->toolsettings->uvcalc_radius = 1.0f; - sce->toolsettings->uvcalc_cubesize = 1.0f; - sce->toolsettings->uvcalc_mapdir = 1; - sce->toolsettings->uvcalc_mapalign = 1; sce->toolsettings->uvcalc_margin = 0.001f; sce->toolsettings->unwrapper = 1; sce->toolsettings->select_thresh = 0.01f; - sce->toolsettings->jointrilimit = 0.8f; sce->toolsettings->selectmode = SCE_SELECT_VERTEX; sce->toolsettings->uv_selectmode = UV_SELECT_VERTEX; @@ -1064,6 +1052,7 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra) */ static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene) { + SceneRenderLayer *srl; float ctime = BKE_scene_frame_get(scene); /* scene itself */ @@ -1098,6 +1087,22 @@ static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene) if (adt && adt->drivers.first) BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS); } + + /* freestyle */ + for (srl = scene->r.layers.first; srl; srl = srl->next) { + FreestyleConfig *config = &srl->freestyleConfig; + FreestyleLineSet *lineset; + + for (lineset = config->linesets.first; lineset; lineset = lineset->next) { + if (lineset->linestyle) { + ID *lid = &lineset->linestyle->id; + AnimData *adt = BKE_animdata_from_id(lid); + + if (adt && adt->drivers.first) + BKE_animsys_evaluate_animdata(scene, lid, adt, ctime, ADT_RECALC_DRIVERS); + } + } + } } /* deps hack - do extra recalcs at end */ diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index fe2f52d79fd..c41c66ef561 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -47,6 +47,7 @@ #include "BLI_listbase.h" #include "BLI_utildefines.h" +#include "BKE_idprop.h" #include "BKE_screen.h" /* ************ Spacetype/regiontype handling ************** */ @@ -111,7 +112,7 @@ ARegionType *BKE_regiontype_from_id(SpaceType *st, int regionid) if (art->regionid == regionid) return art; - printf("Error, region type missing in - name:\"%s\", id:%d\n", st->name, st->spaceid); + printf("Error, region type %d missing in - name:\"%s\", id:%d\n", regionid, st->name, st->spaceid); return st->regiontypes.first; } @@ -267,6 +268,8 @@ void BKE_spacedata_draw_locks(int set) /* not region itself */ void BKE_area_region_free(SpaceType *st, ARegion *ar) { + uiList *uilst; + if (st) { ARegionType *art = BKE_regiontype_from_id(st, ar->regiontype); @@ -285,6 +288,23 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar) } BLI_freelistN(&ar->panels); + + for (uilst = ar->ui_lists.first; uilst; uilst = uilst->next) { + if (uilst->dyn_data) { + uiListDyn *dyn_data = uilst->dyn_data; + if (dyn_data->items_filter_flags) { + MEM_freeN(dyn_data->items_filter_flags); + } + if (dyn_data->items_filter_neworder) { + MEM_freeN(dyn_data->items_filter_neworder); + } + MEM_freeN(dyn_data); + } + if (uilst->properties) { + IDP_FreeProperty(uilst->properties); + MEM_freeN(uilst->properties); + } + } BLI_freelistN(&ar->ui_lists); } diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 34b19e3f357..dd7e847feaf 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -417,33 +417,41 @@ void BKE_sequencer_editing_free(Scene *scene) static void sequencer_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf) { - IMB_colormanagement_assign_float_colorspace(ibuf, scene->sequencer_colorspace_settings.name); + if (ibuf->rect_float) { + IMB_colormanagement_assign_float_colorspace(ibuf, scene->sequencer_colorspace_settings.name); + } } void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, int make_float) { const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); const char *to_colorspace = scene->sequencer_colorspace_settings.name; + const char *float_colorspace = IMB_colormanagement_get_float_colorspace(ibuf); if (!ibuf->rect_float) { - if (make_float && ibuf->rect) { - /* when converting byte buffer to float in sequencer we need to make float - * buffer be in sequencer's working space, which is currently only doable - * from linear space. - * - */ - - /* - * OCIO_TODO: would be nice to support direct single transform from byte to sequencer's - */ - - IMB_float_from_rect(ibuf); + if (ibuf->rect) { + const char *byte_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf); + if (make_float || !STREQ(to_colorspace, byte_colorspace)) { + /* If byte space is not in sequencer's working space, we deliver float color space, + * this is to to prevent data loss. + */ + + /* when converting byte buffer to float in sequencer we need to make float + * buffer be in sequencer's working space, which is currently only doable + * from linear space. + */ + + /* + * OCIO_TODO: would be nice to support direct single transform from byte to sequencer's + */ + + IMB_float_from_rect(ibuf); + } + else { + return; + } } else { - /* if there's only byte buffer in image it's already in compositor's working space, - * nothing to do here - */ - return; } } @@ -452,8 +460,10 @@ void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, int make_ if (ibuf->rect) imb_freerectImBuf(ibuf); - IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - from_colorspace, to_colorspace, TRUE); + if (!STREQ(float_colorspace, to_colorspace)) { + IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, + from_colorspace, to_colorspace, true); + } } } @@ -467,7 +477,7 @@ void BKE_sequencer_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf) if (to_colorspace && to_colorspace[0] != '\0') { IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - from_colorspace, to_colorspace, TRUE); + from_colorspace, to_colorspace, true); } } @@ -622,7 +632,7 @@ static void seq_update_sound_bounds_recursive_rec(Scene *scene, Sequence *metase endofs = seq->start + seq->len - end; sound_move_scene_sound(scene, seq->scene_sound, seq->start + startofs, - seq->start + seq->len - endofs, startofs); + seq->start + seq->len - endofs, startofs + seq->anim_startofs); } } } @@ -654,8 +664,9 @@ void BKE_sequence_calc_disp(Scene *scene, Sequence *seq) if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) { BKE_sequencer_update_sound_bounds(scene, seq); } - else if (seq->type == SEQ_TYPE_META) + else if (seq->type == SEQ_TYPE_META) { seq_update_sound_bounds_recursive(scene, seq); + } } void BKE_sequence_calc(Scene *scene, Sequence *seq) @@ -865,8 +876,7 @@ void BKE_sequencer_sort(Scene *scene) seqbase.first = seqbase.last = NULL; effbase.first = effbase.last = NULL; - while ( (seq = ed->seqbasep->first) ) { - BLI_remlink(ed->seqbasep, seq); + while ((seq = BLI_pophead(ed->seqbasep))) { if (seq->type & SEQ_TYPE_EFFECT) { seqt = effbase.first; @@ -2669,10 +2679,14 @@ static ImBuf *do_render_strip_uncached(SeqRenderData context, Sequence *seq, flo seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN, seq_rendersize_to_proxysize(context.preview_render_size)); - /* we don't need both (speed reasons)! */ - if (ibuf && ibuf->rect_float && ibuf->rect) - imb_freerectImBuf(ibuf); if (ibuf) { + BKE_sequencer_imbuf_to_sequencer_space(context.scene, ibuf, FALSE); + + /* we don't need both (speed reasons)! */ + if (ibuf->rect_float && ibuf->rect) { + imb_freerectImBuf(ibuf); + } + seq->strip->stripdata->orig_width = ibuf->x; seq->strip->stripdata->orig_height = ibuf->y; } @@ -3677,6 +3691,51 @@ bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, Scene *evil_scene) return offset ? false : true; } +/* Unlike _update_sound_ funcs, these ones take info from audaspace to update sequence length! */ +#ifdef WITH_AUDASPACE +static bool sequencer_refresh_sound_length_recursive(Scene *scene, ListBase *seqbase) +{ + Sequence *seq; + bool changed = false; + + for (seq = seqbase->first; seq; seq = seq->next) { + if (seq->type == SEQ_TYPE_META) { + if (sequencer_refresh_sound_length_recursive(scene, &seq->seqbase)) { + BKE_sequence_calc(scene, seq); + changed = true; + } + } + else if (seq->type == SEQ_TYPE_SOUND_RAM) { + AUD_SoundInfo info = AUD_getInfo(seq->sound->playback_handle); + int old = seq->len; + float fac; + + seq->len = (int)ceil((double)info.length * FPS); + fac = (float)seq->len / (float)old; + old = seq->startofs; + seq->startofs *= fac; + seq->endofs *= fac; + seq->start += (old - seq->startofs); /* So that visual/"real" start frame does not change! */ + + BKE_sequence_calc(scene, seq); + changed = true; + } + } + return changed; +} +#endif + +void BKE_sequencer_refresh_sound_length(Scene *scene) +{ +#ifdef WITH_AUDASPACE + if (scene->ed) { + sequencer_refresh_sound_length_recursive(scene, &scene->ed->seqbase); + } +#else + (void)scene; +#endif +} + void BKE_sequencer_update_sound_bounds_all(Scene *scene) { Editing *ed = scene->ed; @@ -3954,6 +4013,29 @@ Sequence *BKE_sequence_get_by_name(ListBase *seqbase, const char *name, int recu return NULL; } +/** + * Only use as last resort when the StripElem is available but no the Sequence. + * (needed for RNA) + */ +Sequence *BKE_sequencer_from_elem(ListBase *seqbase, StripElem *se) +{ + Sequence *iseq; + + for (iseq = seqbase->first; iseq; iseq = iseq->next) { + Sequence *seq_found; + if ((iseq->strip && iseq->strip->stripdata) && + (ARRAY_HAS_ITEM(se, iseq->strip->stripdata, iseq->len))) + { + break; + } + else if ((seq_found = BKE_sequencer_from_elem(&iseq->seqbase, se))) { + iseq = seq_found; + break; + } + } + + return iseq; +} Sequence *BKE_sequencer_active_get(Scene *scene) { diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index b9843ad0619..5c9c564998e 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -198,10 +198,10 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) * MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored) * MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored) */ -int normal_projection_project_vertex(char options, const float vert[3], const float dir[3], - const SpaceTransform *transf, - BVHTree *tree, BVHTreeRayHit *hit, - BVHTree_RayCastCallback callback, void *userdata) +int BKE_shrinkwrap_project_normal(char options, const float vert[3], + const float dir[3], const SpaceTransform *transf, + BVHTree *tree, BVHTreeRayHit *hit, + BVHTree_RayCastCallback callback, void *userdata) { /* don't use this because this dist value could be incompatible * this value used by the callback for comparing prev/new dist values. @@ -368,14 +368,14 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) if (use_normal & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) { if (auxData.tree) { - normal_projection_project_vertex(0, tmp_co, tmp_no, - &local2aux, auxData.tree, &hit, - auxData.raycast_callback, &auxData); + BKE_shrinkwrap_project_normal(0, tmp_co, tmp_no, + &local2aux, auxData.tree, &hit, + auxData.raycast_callback, &auxData); } - normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, tmp_no, - &calc->local2target, treeData.tree, &hit, - treeData.raycast_callback, &treeData); + BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, tmp_no, + &calc->local2target, treeData.tree, &hit, + treeData.raycast_callback, &treeData); } /* Project over negative direction of axis */ @@ -384,14 +384,14 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) negate_v3_v3(inv_no, tmp_no); if (auxData.tree) { - normal_projection_project_vertex(0, tmp_co, inv_no, - &local2aux, auxData.tree, &hit, - auxData.raycast_callback, &auxData); + BKE_shrinkwrap_project_normal(0, tmp_co, inv_no, + &local2aux, auxData.tree, &hit, + auxData.raycast_callback, &auxData); } - normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, inv_no, - &calc->local2target, treeData.tree, &hit, - treeData.raycast_callback, &treeData); + BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, inv_no, + &calc->local2target, treeData.tree, &hit, + treeData.raycast_callback, &treeData); } /* don't set the initial dist (which is more efficient), @@ -506,7 +506,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM DerivedMesh *ss_mesh = NULL; ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData; - /* remove loop dependencies on derived meshs (TODO should this be done elsewhere?) */ + /* remove loop dependencies on derived meshes (TODO should this be done elsewhere?) */ if (smd->target == ob) smd->target = NULL; if (smd->auxTarget == ob) smd->auxTarget = NULL; diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index bb65955e3b5..fb0e22abf2a 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -1142,8 +1142,8 @@ static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_mult /* values */ output->influence[index_out] = em1.influence[index_in]; - if (output->velocity) { - output->velocity[index_out] = em1.velocity[index_in]; + if (output->velocity && em1.velocity) { + copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]); } } @@ -1160,9 +1160,11 @@ static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_mult else { output->influence[index_out] = MAX2(em2->influence[index_in], output->influence[index_out]); } - if (output->velocity) { + if (output->velocity && em2->velocity) { /* last sample replaces the velocity */ - output->velocity[index_out] = ADD_IF_LOWER(output->velocity[index_out], em2->velocity[index_in]); + output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3], em2->velocity[index_in * 3]); + output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1], em2->velocity[index_in * 3 + 1]); + output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2], em2->velocity[index_in * 3 + 2]); } } } // low res loop @@ -2384,6 +2386,7 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, if (effectors) { float *density = smoke_get_density(sds->fluid); + float *fuel = smoke_get_fuel(sds->fluid); float *force_x = smoke_get_force_x(sds->fluid); float *force_y = smoke_get_force_y(sds->fluid); float *force_z = smoke_get_force_z(sds->fluid); @@ -2406,7 +2409,7 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0}; unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); - if ((density[index] < FLT_EPSILON) || obstacle[index]) + if (((fuel ? MAX2(density[index], fuel[index]) : density[index]) < FLT_EPSILON) || obstacle[index]) continue; vel[0] = velocity_x[index]; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 2f8eb7d9931..3910ef5cb69 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -427,6 +427,8 @@ void sound_update_fps(struct Scene *scene) { if (scene->sound_scene) AUD_setSequencerFPS(scene->sound_scene, FPS); + + BKE_sequencer_refresh_sound_length(scene); } void sound_update_scene_listener(struct Scene *scene) diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 35482d9553d..0de4541f9a3 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -298,7 +298,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, CCGVertHDL *fverts = NULL; BLI_array_declare(fverts); #endif - EdgeHash *ehash; + EdgeSet *eset; float creaseFactor = (float)ccgSubSurf_getSubdivisionLevels(ss); float uv[3] = {0.0f, 0.0f, 0.0f}; /* only first 2 values are written into */ @@ -334,7 +334,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, } /* create edges */ - ehash = BLI_edgehash_new(); + eset = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totface)); for (i = 0; i < totface; i++) { MPoly *mp = &((MPoly *) mpoly)[i]; @@ -359,7 +359,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, MVert *mv0 = mvert + (ml[j_next].v); MVert *mv1 = mvert + (ml[j].v); - if (!BLI_edgehash_haskey(ehash, v0, v1)) { + if (BLI_edgeset_reinsert(eset, v0, v1)) { CCGEdge *e, *orige = ccgSubSurf_getFaceEdge(origf, j_next); CCGEdgeHDL ehdl = SET_INT_IN_POINTER(mp->loopstart + j_next); float crease; @@ -370,12 +370,11 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, crease = ccgSubSurf_getEdgeCrease(orige); ccgSubSurf_syncEdge(ss, ehdl, fverts[j_next], fverts[j], crease, &e); - BLI_edgehash_insert(ehash, v0, v1, NULL); } } } - BLI_edgehash_free(ehash, NULL); + BLI_edgeset_free(eset); /* create faces */ for (i = 0; i < totface; i++) { @@ -1065,8 +1064,8 @@ void subsurf_copy_grid_hidden(DerivedMesh *dm, const MPoly *mpoly, for (j = 0; j < mpoly[i].totloop; j++) { const MDisps *md = &mdisps[mpoly[i].loopstart + j]; - int hidden_gridsize = ccg_gridsize(md->level); - int factor = ccg_factor(level, md->level); + int hidden_gridsize = BKE_ccg_gridsize(md->level); + int factor = BKE_ccg_factor(level, md->level); if (!md->hidden) continue; @@ -1108,8 +1107,8 @@ void subsurf_copy_grid_paint_mask(DerivedMesh *dm, const MPoly *mpoly, if (!gpm->data) continue; - factor = ccg_factor(level, gpm->level); - gpm_gridsize = ccg_gridsize(gpm->level); + factor = BKE_ccg_factor(level, gpm->level); + gpm_gridsize = BKE_ccg_gridsize(gpm->level); for (y = 0; y < gridSize; y++) { for (x = 0; x < gridSize; x++) { @@ -1332,7 +1331,7 @@ static void ccgDM_copyFinalLoopArray(DerivedMesh *dm, MLoop *mloop) if (!ccgdm->ehash) { MEdge *medge; - ccgdm->ehash = BLI_edgehash_new(); + ccgdm->ehash = BLI_edgehash_new_ex(__func__, ccgdm->dm.numEdgeData); medge = ccgdm->dm.getEdgeArray((DerivedMesh *)ccgdm); for (i = 0; i < ccgdm->dm.numEdgeData; i++) { @@ -3190,8 +3189,10 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, ccgdm->dm.getVert = ccgDM_getFinalVert; ccgdm->dm.getEdge = ccgDM_getFinalEdge; ccgdm->dm.getTessFace = ccgDM_getFinalFace; + ccgdm->dm.getVertCo = ccgDM_getFinalVertCo; ccgdm->dm.getVertNo = ccgDM_getFinalVertNo; + ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray; ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray; ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray; @@ -3217,11 +3218,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, ccgdm->dm.getPolyMap = ccgDM_getPolyMap; ccgdm->dm.getPBVH = ccgDM_getPBVH; - ccgdm->dm.getTessFace = ccgDM_getFinalFace; - ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray; - ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray; - ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray; - ccgdm->dm.calcNormals = ccgDM_calcNormals; ccgdm->dm.recalcTessellation = ccgDM_recalcTessellation; @@ -3577,6 +3573,8 @@ struct DerivedMesh *subsurf_make_derived_from_derived( int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges); CCGDerivedMesh *result; + /* note: editmode calculation can only run once per + * modifier stack evaluation (uses freed cache) [#36299] */ if (flags & SUBSURF_FOR_EDIT_MODE) { int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels) : smd->levels; diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index f0c01e25598..be43aae1ed3 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -1151,17 +1151,26 @@ void txt_pop_sel(Text *text) text->selc = text->curc; } -void txt_order_cursors(Text *text) +void txt_order_cursors(Text *text, const bool reverse) { if (!text) return; if (!text->curl) return; if (!text->sell) return; - /* Flip so text->curl is before text->sell */ - if ((txt_get_span(text->curl, text->sell) < 0) || - (text->curl == text->sell && text->curc > text->selc)) - { - txt_curs_swap(text); + /* Flip so text->curl is before/after text->sell */ + if (reverse == false) { + if ((txt_get_span(text->curl, text->sell) < 0) || + (text->curl == text->sell && text->curc > text->selc)) + { + txt_curs_swap(text); + } + } + else { + if ((txt_get_span(text->curl, text->sell) > 0) || + (text->curl == text->sell && text->curc < text->selc)) + { + txt_curs_swap(text); + } } } @@ -1181,7 +1190,7 @@ static void txt_delete_sel(Text *text) if (!txt_has_sel(text)) return; - txt_order_cursors(text); + txt_order_cursors(text, false); if (!undoing) { buf = txt_sel_to_buf(text); @@ -1305,7 +1314,7 @@ int txt_find_string(Text *text, const char *findstr, int wrap, int match_case) if (!text || !text->curl || !text->sell) return 0; - txt_order_cursors(text); + txt_order_cursors(text, false); tl = startl = text->sell; @@ -1938,6 +1947,7 @@ static unsigned int txt_redo_read_unicode(const char *undo_buf, int *undo_pos, s void txt_do_undo(Text *text) { int op = text->undo_buf[text->undo_pos]; + int prev_flags; unsigned int linep, i; unsigned int uchar; unsigned int curln, selln; @@ -2061,8 +2071,14 @@ void txt_do_undo(Text *text) txt_move_to(text, selln, selc, 1); if ((curln == selln) && (curc == selc)) { + /* disable tabs to spaces since moving right may involve skipping multiple spaces */ + prev_flags = text->flags; + text->flags &= ~TXT_TABSTOSPACES; + for (i = 0; i < linep; i++) txt_move_right(text, 1); + + text->flags = prev_flags; } txt_delete_selected(text); @@ -2833,7 +2849,7 @@ void txt_move_lines(struct Text *text, const int direction) if (!text || !text->curl || !text->sell) return; - txt_order_cursors(text); + txt_order_cursors(text, false); line_other = (direction == TXT_MOVE_LINE_DOWN) ? text->sell->next : text->curl->prev; diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index e2b7358525a..22b0fe7bc24 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -71,16 +71,16 @@ /* ****************** Mapping ******************* */ -TexMapping *add_tex_mapping(void) +TexMapping *add_tex_mapping(int type) { TexMapping *texmap = MEM_callocN(sizeof(TexMapping), "TexMapping"); - default_tex_mapping(texmap); + default_tex_mapping(texmap, type); return texmap; } -void default_tex_mapping(TexMapping *texmap) +void default_tex_mapping(TexMapping *texmap, int type) { memset(texmap, 0, sizeof(TexMapping)); @@ -92,11 +92,12 @@ void default_tex_mapping(TexMapping *texmap) texmap->projy = PROJ_Y; texmap->projz = PROJ_Z; texmap->mapping = MTEX_FLAT; + texmap->type = type; } void init_tex_mapping(TexMapping *texmap) { - float smat[3][3], rmat[3][3], mat[3][3], proj[3][3]; + float smat[4][4], rmat[4][4], tmat[4][4], proj[4][4], size[3]; if (texmap->projx == PROJ_X && texmap->projy == PROJ_Y && texmap->projz == PROJ_Z && is_zero_v3(texmap->loc) && is_zero_v3(texmap->rot) && is_one_v3(texmap->size)) @@ -107,7 +108,8 @@ void init_tex_mapping(TexMapping *texmap) } else { /* axis projection */ - zero_m3(proj); + zero_m4(proj); + proj[3][3] = 1.0f; if (texmap->projx != PROJ_N) proj[texmap->projx - 1][0] = 1.0f; @@ -117,19 +119,50 @@ void init_tex_mapping(TexMapping *texmap) proj[texmap->projz - 1][2] = 1.0f; /* scale */ - size_to_mat3(smat, texmap->size); + copy_v3_v3(size, texmap->size); + + if (ELEM(texmap->type, TEXMAP_TYPE_TEXTURE, TEXMAP_TYPE_NORMAL)) { + /* keep matrix invertible */ + if (fabsf(size[0]) < 1e-5f) + size[0] = signf(size[0]) * 1e-5f; + if (fabsf(size[1]) < 1e-5f) + size[1] = signf(size[1]) * 1e-5f; + if (fabsf(size[2]) < 1e-5f) + size[2] = signf(size[2]) * 1e-5f; + } + size_to_mat4(smat, texmap->size); + /* rotation */ - /* TexMapping rotation are now in radians. */ - eul_to_mat3(rmat, texmap->rot); - - /* compose it all */ - mul_m3_m3m3(mat, rmat, smat); - mul_m3_m3m3(mat, proj, mat); - + eul_to_mat4(rmat, texmap->rot); + /* translation */ - copy_m4_m3(texmap->mat, mat); - copy_v3_v3(texmap->mat[3], texmap->loc); + unit_m4(tmat); + copy_v3_v3(tmat[3], texmap->loc); + + if (texmap->type == TEXMAP_TYPE_TEXTURE) { + /* to transform a texture, the inverse transform needs + * to be applied to the texture coordinate */ + mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0); + invert_m4(texmap->mat); + } + else if (texmap->type == TEXMAP_TYPE_POINT) { + /* forward transform */ + mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0); + } + else if (texmap->type == TEXMAP_TYPE_VECTOR) { + /* no translation for vectors */ + mul_m4_m4m4(texmap->mat, rmat, smat); + } + else if (texmap->type == TEXMAP_TYPE_NORMAL) { + /* no translation for normals, and inverse transpose */ + mul_m4_m4m4(texmap->mat, rmat, smat); + invert_m4(texmap->mat); + transpose_m4(texmap->mat); + } + + /* projection last */ + mul_m4_m4m4(texmap->mat, texmap->mat, proj); texmap->flag &= ~TEXMAP_UNIT_MATRIX; } diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 4c363292898..b8711f6e5f6 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -103,6 +103,18 @@ static void tracking_tracks_free(ListBase *tracks) BLI_freelistN(tracks); } +/* Free the whole list of plane tracks, list's head and tail are set to NULL. */ +static void tracking_plane_tracks_free(ListBase *plane_tracks) +{ + MovieTrackingPlaneTrack *plane_track; + + for (plane_track = plane_tracks->first; plane_track; plane_track = plane_track->next) { + BKE_tracking_plane_track_free(plane_track); + } + + BLI_freelistN(plane_tracks); +} + /* Free reconstruction structures, only frees contents of a structure, * (if structure is allocated in heap, it shall be handled outside). * @@ -122,6 +134,7 @@ static void tracking_reconstruction_free(MovieTrackingReconstruction *reconstruc static void tracking_object_free(MovieTrackingObject *object) { tracking_tracks_free(&object->tracks); + tracking_plane_tracks_free(&object->plane_tracks); tracking_reconstruction_free(&object->reconstruction); } @@ -173,6 +186,7 @@ static void tracking_dopesheet_free(MovieTrackingDopesheet *dopesheet) void BKE_tracking_free(MovieTracking *tracking) { tracking_tracks_free(&tracking->tracks); + tracking_plane_tracks_free(&tracking->plane_tracks); tracking_reconstruction_free(&tracking->reconstruction); tracking_objects_free(&tracking->objects); @@ -198,7 +212,7 @@ void BKE_tracking_settings_init(MovieTracking *tracking) tracking->settings.default_algorithm_flag |= TRACK_ALGORITHM_FLAG_USE_BRUTE; tracking->settings.dist = 1; tracking->settings.object_distance = 1; - tracking->settings.reconstruction_success_threshold = 1e-3; + tracking->settings.reconstruction_success_threshold = 1e-3f; tracking->stabilization.scaleinf = 1.0f; tracking->stabilization.locinf = 1.0f; @@ -221,6 +235,18 @@ ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking) return &tracking->tracks; } +/* Get list base of active object's plane tracks. */ +ListBase *BKE_tracking_get_active_plane_tracks(MovieTracking *tracking) +{ + MovieTrackingObject *object = BKE_tracking_object_get_active(tracking); + + if (object && (object->flag & TRACKING_OBJECT_CAMERA) == 0) { + return &object->plane_tracks; + } + + return &tracking->plane_tracks; +} + /* Get reconstruction data of active object. */ MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTracking *tracking) { @@ -475,7 +501,7 @@ void BKE_tracking_clipboard_copy_tracks(MovieTracking *tracking, MovieTrackingOb } /* Check whether there're any tracks in the clipboard. */ -int BKE_tracking_clipboard_has_tracks(void) +bool BKE_tracking_clipboard_has_tracks(void) { return tracking_clipboard.tracks.first != NULL; } @@ -652,7 +678,7 @@ void BKE_tracking_track_flag_clear(MovieTrackingTrack *track, int area, int flag * * NOTE: frame number should be in clip space, not scene space. */ -int BKE_tracking_track_has_marker_at_frame(MovieTrackingTrack *track, int framenr) +bool BKE_tracking_track_has_marker_at_frame(MovieTrackingTrack *track, int framenr) { return BKE_tracking_marker_get_exact(track, framenr) != NULL; } @@ -661,7 +687,7 @@ int BKE_tracking_track_has_marker_at_frame(MovieTrackingTrack *track, int framen * * NOTE: frame number should be in clip space, not scene space. */ -int BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, int framenr) +bool BKE_tracking_track_has_enabled_marker_at_frame(MovieTrackingTrack *track, int framenr) { MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr); @@ -996,7 +1022,7 @@ float *BKE_tracking_track_get_mask(int frame_width, int frame_height, } /* area - which part of marker should be selected. see TRACK_AREA_* constants */ -void BKE_tracking_track_select(ListBase *tracksbase, MovieTrackingTrack *track, int area, int extend) +void BKE_tracking_track_select(ListBase *tracksbase, MovieTrackingTrack *track, int area, bool extend) { if (extend) { BKE_tracking_track_flag_set(track, area, SELECT); @@ -1025,6 +1051,17 @@ void BKE_tracking_track_deselect(MovieTrackingTrack *track, int area) BKE_tracking_track_flag_clear(track, area, SELECT); } +void BKE_tracking_tracks_deselect_all(ListBase *tracksbase) +{ + MovieTrackingTrack *track; + + for (track = tracksbase->first; track; track = track->next) { + if ((track->flag & TRACK_HIDDEN) == 0) { + BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT); + } + } +} + /*********************** Marker *************************/ MovieTrackingMarker *BKE_tracking_marker_insert(MovieTrackingTrack *track, MovieTrackingMarker *marker) @@ -1264,6 +1301,296 @@ void BKE_tracking_marker_get_subframe_position(MovieTrackingTrack *track, float add_v2_v2(pos, track->offset); } +/*********************** Plane Track *************************/ + +/* Creates new plane track out of selected point tracks */ +MovieTrackingPlaneTrack *BKE_tracking_plane_track_add(MovieTracking *tracking, ListBase *plane_tracks_base, + ListBase *tracks, int framenr) +{ + MovieTrackingPlaneTrack *plane_track; + MovieTrackingPlaneMarker plane_marker; + MovieTrackingTrack *track; + float tracks_min[2], tracks_max[2]; + int track_index, num_selected_tracks = 0; + + (void) tracking; /* Ignored. */ + + /* Use bounding box of selected markers as an initial size of plane. */ + INIT_MINMAX2(tracks_min, tracks_max); + for (track = tracks->first; track; track = track->next) { + if (TRACK_SELECTED(track)) { + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); + float pattern_min[2], pattern_max[2]; + BKE_tracking_marker_pattern_minmax(marker, pattern_min, pattern_max); + add_v2_v2(pattern_min, marker->pos); + add_v2_v2(pattern_max, marker->pos); + minmax_v2v2_v2(tracks_min, tracks_max, pattern_min); + minmax_v2v2_v2(tracks_min, tracks_max, pattern_max); + num_selected_tracks++; + } + } + + if (num_selected_tracks < 4) { + return NULL; + } + + /* Allocate new plane track. */ + plane_track = MEM_callocN(sizeof(MovieTrackingPlaneTrack), "new plane track"); + + /* Use some default name. */ + strcpy(plane_track->name, "Plane Track"); + + /* Use selected tracks from given list as a plane. */ + plane_track->point_tracks = MEM_mallocN(sizeof(MovieTrackingTrack *) * num_selected_tracks, "new plane tracks array"); + for (track = tracks->first, track_index = 0; track; track = track->next) { + if (TRACK_SELECTED(track)) { + plane_track->point_tracks[track_index] = track; + track_index++; + } + } + plane_track->point_tracksnr = num_selected_tracks; + + /* Setup new plane marker and add it to the track. */ + plane_marker.framenr = framenr; + plane_marker.flag = 0; + + copy_v2_v2(plane_marker.corners[0], tracks_min); + copy_v2_v2(plane_marker.corners[2], tracks_max); + + plane_marker.corners[1][0] = tracks_max[0]; + plane_marker.corners[1][1] = tracks_min[1]; + plane_marker.corners[3][0] = tracks_min[0]; + plane_marker.corners[3][1] = tracks_max[1]; + + BKE_tracking_plane_marker_insert(plane_track, &plane_marker); + + /* Put new plane track to the list, ensure it's name is unique. */ + BLI_addtail(plane_tracks_base, plane_track); + BKE_tracking_plane_track_unique_name(plane_tracks_base, plane_track); + + return plane_track; +} + +void BKE_tracking_plane_track_unique_name(ListBase *plane_tracks_base, MovieTrackingPlaneTrack *plane_track) +{ + BLI_uniquename(plane_tracks_base, plane_track, CTX_DATA_(BLF_I18NCONTEXT_ID_MOVIECLIP, "Plane Track"), '.', + offsetof(MovieTrackingPlaneTrack, name), sizeof(plane_track->name)); +} + +/* Free specified plane track, only frees contents of a structure + * (if track is allocated in heap, it shall be handled outside). + * + * All the pointers inside track becomes invalid after this call. + */ +void BKE_tracking_plane_track_free(MovieTrackingPlaneTrack *plane_track) +{ + if (plane_track->markers) { + MEM_freeN(plane_track->markers); + } + + MEM_freeN(plane_track->point_tracks); +} + +MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_named(MovieTracking *tracking, + MovieTrackingObject *object, + const char *name) +{ + ListBase *plane_tracks_base = BKE_tracking_object_get_plane_tracks(tracking, object); + MovieTrackingPlaneTrack *plane_track; + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (!strcmp(plane_track->name, name)) { + return plane_track; + } + } + + return NULL; +} + +MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_active(struct MovieTracking *tracking) +{ + ListBase *plane_tracks_base; + + if (tracking->act_plane_track == NULL) { + return NULL; + } + + plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + + /* Check that active track is in current plane tracks list */ + if (BLI_findindex(plane_tracks_base, tracking->act_plane_track) >= 0) { + return tracking->act_plane_track; + } + + return NULL; +} + +void BKE_tracking_plane_tracks_deselect_all(ListBase *plane_tracks_base) +{ + MovieTrackingPlaneTrack *plane_track; + + for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) { + plane_track->flag &= ~SELECT; + } +} + +/*********************** Plane Marker *************************/ + +MovieTrackingPlaneMarker *BKE_tracking_plane_marker_insert(MovieTrackingPlaneTrack *plane_track, + MovieTrackingPlaneMarker *plane_marker) +{ + MovieTrackingPlaneMarker *old_plane_marker = NULL; + + if (plane_track->markersnr) + old_plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, plane_marker->framenr); + + if (old_plane_marker) { + /* Simply replace settings in existing marker. */ + *old_plane_marker = *plane_marker; + + return old_plane_marker; + } + else { + int a = plane_track->markersnr; + + /* Find position in array where to add new marker. */ + /* TODO(sergey): we coud use bisect to speed things up. */ + while (a--) { + if (plane_track->markers[a].framenr < plane_marker->framenr) { + break; + } + } + + plane_track->markersnr++; + plane_track->markers = MEM_reallocN(plane_track->markers, + sizeof(MovieTrackingPlaneMarker) * plane_track->markersnr); + + /* Shift array to "free" space for new marker. */ + memmove(plane_track->markers + a + 2, plane_track->markers + a + 1, + (plane_track->markersnr - a - 2) * sizeof(MovieTrackingPlaneMarker)); + + /* Put new marker to an array. */ + plane_track->markers[a + 1] = *plane_marker; + plane_track->last_marker = a + 1; + + return &plane_track->markers[a + 1]; + } +} + +void BKE_tracking_plane_marker_delete(MovieTrackingPlaneTrack *plane_track, int framenr) +{ + int a = 0; + + while (a < plane_track->markersnr) { + if (plane_track->markers[a].framenr == framenr) { + if (plane_track->markersnr > 1) { + memmove(plane_track->markers + a, plane_track->markers + a + 1, + (plane_track->markersnr - a - 1) * sizeof(MovieTrackingPlaneMarker)); + plane_track->markersnr--; + plane_track->markers = MEM_reallocN(plane_track->markers, + sizeof(MovieTrackingMarker) * plane_track->markersnr); + } + else { + MEM_freeN(plane_track->markers); + plane_track->markers = NULL; + plane_track->markersnr = 0; + } + + break; + } + + a++; + } +} + +/* TODO(sergey): The next couple of functions are really quite the same as point marker version, + * would be nice to de-duplicate them somehow.. + */ + +/* Get a plane marker at given frame, + * If there's no such marker, closest one from the left side will be returned. + */ +MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get(MovieTrackingPlaneTrack *plane_track, int framenr) +{ + int a = plane_track->markersnr - 1; + + if (!plane_track->markersnr) + return NULL; + + /* Approximate pre-first framenr marker with first marker. */ + if (framenr < plane_track->markers[0].framenr) { + return &plane_track->markers[0]; + } + + if (plane_track->last_marker < plane_track->markersnr) { + a = plane_track->last_marker; + } + + if (plane_track->markers[a].framenr <= framenr) { + while (a < plane_track->markersnr && plane_track->markers[a].framenr <= framenr) { + if (plane_track->markers[a].framenr == framenr) { + plane_track->last_marker = a; + + return &plane_track->markers[a]; + } + a++; + } + + /* If there's no marker for exact position, use nearest marker from left side. */ + return &plane_track->markers[a - 1]; + } + else { + while (a >= 0 && plane_track->markers[a].framenr >= framenr) { + if (plane_track->markers[a].framenr == framenr) { + plane_track->last_marker = a; + + return &plane_track->markers[a]; + } + + a--; + } + + /* If there's no marker for exact position, use nearest marker from left side. */ + return &plane_track->markers[a]; + } + + return NULL; +} + +/* Get a plane marker at exact given frame, if there's no marker at the frame, + * NULL will be returned. + */ +MovieTrackingPlaneMarker *BKE_tracking_plane_marker_get_exact(MovieTrackingPlaneTrack *plane_track, int framenr) +{ + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); + + if (plane_marker->framenr != framenr) { + return NULL; + } + + return plane_marker; +} + +/* Ensure there's a marker for the given frame. */ +MovieTrackingPlaneMarker *BKE_tracking_plane_marker_ensure(MovieTrackingPlaneTrack *plane_track, int framenr) +{ + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); + + if (plane_marker->framenr != framenr) { + MovieTrackingPlaneMarker plane_marker_new; + + plane_marker_new = *plane_marker; + plane_marker_new.framenr = framenr; + + plane_marker = BKE_tracking_plane_marker_insert(plane_track, &plane_marker_new); + } + + return plane_marker; +} + /*********************** Object *************************/ MovieTrackingObject *BKE_tracking_object_add(MovieTracking *tracking, const char *name) @@ -1295,17 +1622,17 @@ MovieTrackingObject *BKE_tracking_object_add(MovieTracking *tracking, const char return object; } -int BKE_tracking_object_delete(MovieTracking *tracking, MovieTrackingObject *object) +bool BKE_tracking_object_delete(MovieTracking *tracking, MovieTrackingObject *object) { MovieTrackingTrack *track; int index = BLI_findindex(&tracking->objects, object); if (index == -1) - return FALSE; + return false; if (object->flag & TRACKING_OBJECT_CAMERA) { /* object used for camera solving can't be deleted */ - return FALSE; + return false; } track = object->tracks.first; @@ -1328,7 +1655,7 @@ int BKE_tracking_object_delete(MovieTracking *tracking, MovieTrackingObject *obj BKE_tracking_dopesheet_tag_update(tracking); - return TRUE; + return true; } void BKE_tracking_object_unique_name(MovieTracking *tracking, MovieTrackingObject *object) @@ -1379,6 +1706,15 @@ ListBase *BKE_tracking_object_get_tracks(MovieTracking *tracking, MovieTrackingO return &object->tracks; } +ListBase *BKE_tracking_object_get_plane_tracks(MovieTracking *tracking, MovieTrackingObject *object) +{ + if (object->flag & TRACKING_OBJECT_CAMERA) { + return &tracking->plane_tracks; + } + + return &object->plane_tracks; +} + MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(MovieTracking *tracking, MovieTrackingObject *object) { @@ -1550,7 +1886,7 @@ static void cameraIntrinscisOptionsFromTracking(libmv_CameraIntrinsicsOptions *c camera_intrinsics_options->k3 = camera->k3; camera_intrinsics_options->image_width = calibration_width; - camera_intrinsics_options->image_height = (double) (calibration_height * aspy); + camera_intrinsics_options->image_height = (int) (calibration_height * aspy); } MovieDistortion *BKE_tracking_distortion_new(void) @@ -1592,7 +1928,7 @@ MovieDistortion *BKE_tracking_distortion_copy(MovieDistortion *distortion) } ImBuf *BKE_tracking_distortion_exec(MovieDistortion *distortion, MovieTracking *tracking, ImBuf *ibuf, - int calibration_width, int calibration_height, float overscan, int undistort) + int calibration_width, int calibration_height, float overscan, bool undistort) { ImBuf *resibuf; @@ -1684,7 +2020,7 @@ ImBuf *BKE_tracking_undistort_frame(MovieTracking *tracking, ImBuf *ibuf, int ca camera->intrinsics = BKE_tracking_distortion_new(); return BKE_tracking_distortion_exec(camera->intrinsics, tracking, ibuf, calibration_width, - calibration_height, overscan, TRUE); + calibration_height, overscan, true); } ImBuf *BKE_tracking_distort_frame(MovieTracking *tracking, ImBuf *ibuf, int calibration_width, @@ -1696,7 +2032,7 @@ ImBuf *BKE_tracking_distort_frame(MovieTracking *tracking, ImBuf *ibuf, int cali camera->intrinsics = BKE_tracking_distortion_new(); return BKE_tracking_distortion_exec(camera->intrinsics, tracking, ibuf, calibration_width, - calibration_height, overscan, FALSE); + calibration_height, overscan, false); } void BKE_tracking_max_undistortion_delta_across_bound(MovieTracking *tracking, rcti *rect, float delta[2]) @@ -1717,8 +2053,8 @@ void BKE_tracking_max_undistortion_delta_across_bound(MovieTracking *tracking, r BKE_tracking_undistort_v2(tracking, pos, warped_pos); - delta[0] = max_ff(delta[0], fabs(pos[0] - warped_pos[0])); - delta[1] = max_ff(delta[1], fabs(pos[1] - warped_pos[1])); + delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0])); + delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1])); /* top edge */ pos[0] = a; @@ -1726,8 +2062,8 @@ void BKE_tracking_max_undistortion_delta_across_bound(MovieTracking *tracking, r BKE_tracking_undistort_v2(tracking, pos, warped_pos); - delta[0] = max_ff(delta[0], fabs(pos[0] - warped_pos[0])); - delta[1] = max_ff(delta[1], fabs(pos[1] - warped_pos[1])); + delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0])); + delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1])); if (a >= rect->xmax) break; @@ -1743,8 +2079,8 @@ void BKE_tracking_max_undistortion_delta_across_bound(MovieTracking *tracking, r BKE_tracking_undistort_v2(tracking, pos, warped_pos); - delta[0] = max_ff(delta[0], fabs(pos[0] - warped_pos[0])); - delta[1] = max_ff(delta[1], fabs(pos[1] - warped_pos[1])); + delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0])); + delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1])); /* right edge */ pos[0] = rect->xmax; @@ -1752,8 +2088,8 @@ void BKE_tracking_max_undistortion_delta_across_bound(MovieTracking *tracking, r BKE_tracking_undistort_v2(tracking, pos, warped_pos); - delta[0] = max_ff(delta[0], fabs(pos[0] - warped_pos[0])); - delta[1] = max_ff(delta[1], fabs(pos[1] - warped_pos[1])); + delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0])); + delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1])); if (a >= rect->ymax) break; @@ -1762,7 +2098,7 @@ void BKE_tracking_max_undistortion_delta_across_bound(MovieTracking *tracking, r /*********************** Image sampling *************************/ -static void disable_imbuf_channels(ImBuf *ibuf, MovieTrackingTrack *track, int grayscale) +static void disable_imbuf_channels(ImBuf *ibuf, MovieTrackingTrack *track, bool grayscale) { BKE_tracking_disable_channels(ibuf, track->flag & TRACK_DISABLE_RED, track->flag & TRACK_DISABLE_GREEN, @@ -1771,7 +2107,7 @@ static void disable_imbuf_channels(ImBuf *ibuf, MovieTrackingTrack *track, int g ImBuf *BKE_tracking_sample_pattern(int frame_width, int frame_height, ImBuf *search_ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker, - int from_anchor, int use_mask, int num_samples_x, int num_samples_y, + bool from_anchor, bool use_mask, int num_samples_x, int num_samples_y, float pos[2]) { ImBuf *pattern_ibuf; @@ -1834,7 +2170,7 @@ ImBuf *BKE_tracking_sample_pattern(int frame_width, int frame_height, ImBuf *sea } ImBuf *BKE_tracking_get_pattern_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker, - int anchored, int disable_channels) + bool anchored, bool disable_channels) { ImBuf *pattern_ibuf, *search_ibuf; float pat_min[2], pat_max[2]; @@ -1849,7 +2185,7 @@ ImBuf *BKE_tracking_get_pattern_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, Mo if (search_ibuf) { pattern_ibuf = BKE_tracking_sample_pattern(ibuf->x, ibuf->y, search_ibuf, track, marker, - anchored, FALSE, num_samples_x, num_samples_y, NULL); + anchored, false, num_samples_x, num_samples_y, NULL); IMB_freeImBuf(search_ibuf); } @@ -1861,7 +2197,7 @@ ImBuf *BKE_tracking_get_pattern_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, Mo } ImBuf *BKE_tracking_get_search_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, MovieTrackingMarker *marker, - int anchored, int disable_channels) + bool anchored, bool disable_channels) { ImBuf *searchibuf; int x, y, w, h; @@ -1893,7 +2229,7 @@ ImBuf *BKE_tracking_get_search_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, Mov (track->flag & TRACK_DISABLE_GREEN) || (track->flag & TRACK_DISABLE_BLUE)) { - disable_imbuf_channels(searchibuf, track, TRUE); + disable_imbuf_channels(searchibuf, track, true); } } @@ -1904,8 +2240,8 @@ ImBuf *BKE_tracking_get_search_imbuf(ImBuf *ibuf, MovieTrackingTrack *track, Mov * better tracks sometimes. however, instead of simply zeroing the channels * out, do a partial grayscale conversion so the display is better. */ -void BKE_tracking_disable_channels(ImBuf *ibuf, int disable_red, int disable_green, int disable_blue, - int grayscale) +void BKE_tracking_disable_channels(ImBuf *ibuf, bool disable_red, bool disable_green, bool disable_blue, + bool grayscale) { int x, y; float scale; @@ -1969,7 +2305,7 @@ void BKE_tracking_disable_channels(ImBuf *ibuf, int disable_red, int disable_gre typedef struct TracksMap { char object_name[MAX_NAME]; - int is_camera; + bool is_camera; int num_tracks; int customdata_size; @@ -1982,7 +2318,7 @@ typedef struct TracksMap { int ptr; } TracksMap; -static TracksMap *tracks_map_new(const char *object_name, int is_camera, int num_tracks, int customdata_size) +static TracksMap *tracks_map_new(const char *object_name, bool is_camera, int num_tracks, int customdata_size) { TracksMap *map = MEM_callocN(sizeof(TracksMap), "TrackingsMap"); @@ -2034,8 +2370,6 @@ static void tracks_map_insert(TracksMap *map, MovieTrackingTrack *track, void *c static void tracks_map_merge(TracksMap *map, MovieTracking *tracking) { MovieTrackingTrack *track; - MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); - MovieTrackingTrack *rot_track = tracking->stabilization.rot_track; ListBase tracks = {NULL, NULL}, new_tracks = {NULL, NULL}; ListBase *old_tracks; int a; @@ -2059,61 +2393,49 @@ static void tracks_map_merge(TracksMap *map, MovieTracking *tracking) * of currently operating tracks (if needed) */ for (a = 0; a < map->num_tracks; a++) { - int replace_sel = 0, replace_rot = 0; - MovieTrackingTrack *new_track, *old; + MovieTrackingTrack *old_track; + bool mapped_to_old = false; track = &map->tracks[a]; /* find original of operating track in list of previously displayed tracks */ - old = BLI_ghash_lookup(map->hash, track); - if (old) { - MovieTrackingTrack *cur = old_tracks->first; - - while (cur) { - if (cur == old) - break; + old_track = BLI_ghash_lookup(map->hash, track); + if (old_track) { + if (BLI_findindex(old_tracks, old_track) != -1) { + BLI_remlink(old_tracks, old_track); - cur = cur->next; - } + /* Copy flags like selection back to the track map. */ + track->flag = old_track->flag; + track->pat_flag = old_track->pat_flag; + track->search_flag = old_track->search_flag; - /* original track was found, re-use flags and remove this track */ - if (cur) { - if (cur == act_track) - replace_sel = 1; - if (cur == rot_track) - replace_rot = 1; + /* Copy all the rest settings back from the map to the actual tracks. */ + MEM_freeN(old_track->markers); + *old_track = *track; + old_track->markers = MEM_dupallocN(old_track->markers); - track->flag = cur->flag; - track->pat_flag = cur->pat_flag; - track->search_flag = cur->search_flag; + BLI_addtail(&tracks, old_track); - BKE_tracking_track_free(cur); - BLI_freelinkN(old_tracks, cur); + mapped_to_old = true; } } - new_track = tracking_track_duplicate(track); - - BLI_ghash_remove(map->hash, track, NULL, NULL); /* XXX: are we actually need this */ - BLI_ghash_insert(map->hash, track, new_track); - - if (replace_sel) /* update current selection in clip */ - tracking->act_track = new_track; + if (mapped_to_old == false) { + MovieTrackingTrack *new_track = tracking_track_duplicate(track); - if (replace_rot) /* update track used for rotation stabilization */ - tracking->stabilization.rot_track = new_track; + /* Update old-new track mapping */ + BLI_ghash_remove(map->hash, track, NULL, NULL); + BLI_ghash_insert(map->hash, track, new_track); - BLI_addtail(&tracks, new_track); + BLI_addtail(&tracks, new_track); + } } /* move all tracks, which aren't operating */ track = old_tracks->first; while (track) { MovieTrackingTrack *next = track->next; - - track->next = track->prev = NULL; BLI_addtail(&new_tracks, track); - track = next; } @@ -2176,13 +2498,13 @@ typedef struct MovieTrackingContext { MovieClip *clip; int clip_flag; - int frames; + int frames, first_frame; bool first_time; MovieTrackingSettings settings; TracksMap *tracks_map; - short backwards, sequence; + bool backwards, sequence; int sync_frame; } MovieTrackingContext; @@ -2216,6 +2538,7 @@ MovieTrackingContext *BKE_tracking_context_new(MovieClip *clip, MovieClipUser *u context->backwards = backwards; context->sync_frame = user->framenr; context->first_time = true; + context->first_frame = user->framenr; context->sequence = sequence; /* count */ @@ -2355,7 +2678,7 @@ static float *track_get_search_floatbuf(ImBuf *ibuf, MovieTrackingTrack *track, float *gray_pixels; int width, height; - searchibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, FALSE, TRUE); + searchibuf = BKE_tracking_get_search_imbuf(ibuf, track, marker, false, true); if (!searchibuf) { *width_r = 0; @@ -2528,7 +2851,7 @@ static bool track_context_update_reference(MovieTrackingContext *context, TrackC } /* Fill in libmv tracker options structure with settings need to be used to perform track. */ -static void tracking_configure_tracker(MovieTrackingTrack *track, float *mask, +static void tracking_configure_tracker(const MovieTrackingTrack *track, float *mask, libmv_TrackRegionOptions *options) { options->motion_model = track->motion_model; @@ -2551,19 +2874,24 @@ static void tracking_configure_tracker(MovieTrackingTrack *track, float *mask, static bool tracking_check_marker_margin(MovieTrackingTrack *track, MovieTrackingMarker *marker, int frame_width, int frame_height) { - float pat_min[2], pat_max[2], dim[2], margin[2]; + float pat_min[2], pat_max[2]; + float margin_left, margin_top, margin_right, margin_bottom; + float normalized_track_margin[2]; /* margin from frame boundaries */ BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max); - sub_v2_v2v2(dim, pat_max, pat_min); - margin[0] = margin[1] = max_ff(dim[0], dim[1]) / 2.0f; - margin[0] = max_ff(margin[0], (float)track->margin / frame_width); - margin[1] = max_ff(margin[1], (float)track->margin / frame_height); + normalized_track_margin[0] = (float)track->margin / frame_width; + normalized_track_margin[1] = (float)track->margin / frame_height; + + margin_left = max_ff(-pat_min[0], normalized_track_margin[0]); + margin_top = max_ff( pat_max[1], normalized_track_margin[1]); + margin_right = max_ff( pat_max[0], normalized_track_margin[0]); + margin_bottom = max_ff(-pat_min[1], normalized_track_margin[1]); /* do not track markers which are too close to boundary */ - if (marker->pos[0] < margin[0] || marker->pos[0] > 1.0f - margin[0] || - marker->pos[1] < margin[1] || marker->pos[1] > 1.0f - margin[1]) + if (marker->pos[0] < margin_left || marker->pos[0] > 1.0f - margin_right || + marker->pos[1] < margin_bottom || marker->pos[1] > 1.0f - margin_top) { return false; } @@ -2703,7 +3031,7 @@ static bool configure_and_run_tracker(ImBuf *destination_ibuf, MovieTrackingTrac /* Track all the tracks from context one more frame, * returns FALSe if nothing was tracked. */ -int BKE_tracking_context_step(MovieTrackingContext *context) +bool BKE_tracking_context_step(MovieTrackingContext *context) { ImBuf *destination_ibuf; int frame_delta = context->backwards ? -1 : 1; @@ -2717,7 +3045,7 @@ int BKE_tracking_context_step(MovieTrackingContext *context) /* Nothing to track, avoid unneeded frames reading to save time and memory. */ if (!map_size) - return FALSE; + return false; /* Get an image buffer for frame we're tracking to. */ context->user.framenr += frame_delta; @@ -2725,7 +3053,7 @@ int BKE_tracking_context_step(MovieTrackingContext *context) destination_ibuf = BKE_movieclip_get_ibuf_flag(context->clip, &context->user, context->clip_flag, MOVIECLIP_CACHE_SKIP); if (!destination_ibuf) - return FALSE; + return false; frame_width = destination_ibuf->x; frame_height = destination_ibuf->y; @@ -2787,12 +3115,50 @@ int BKE_tracking_context_step(MovieTrackingContext *context) return ok; } +void BKE_tracking_context_finish(MovieTrackingContext *context) +{ + MovieClip *clip = context->clip; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); + MovieTrackingPlaneTrack *plane_track; + int map_size = tracks_map_get_size(context->tracks_map); + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) { + int i; + for (i = 0; i < map_size; i++) { + TrackContext *track_context = NULL; + MovieTrackingTrack *track, *old_track; + bool do_update = false; + int j; + + tracks_map_get_indexed_element(context->tracks_map, i, &track, (void **)&track_context); + + old_track = BLI_ghash_lookup(context->tracks_map->hash, track); + for (j = 0; j < plane_track->point_tracksnr; j++) { + if (plane_track->point_tracks[j] == old_track) { + do_update = true; + break; + } + } + + if (do_update) { + BKE_tracking_track_plane_from_existing_motion(plane_track, context->first_frame); + break; + } + } + } + } +} + /* Refine marker's position using previously known keyframe. * Direction of searching for a keyframe depends on backwards flag, * which means if backwards is false, previous keyframe will be as * reference. */ -void BKE_tracking_refine_marker(MovieClip *clip, MovieTrackingTrack *track, MovieTrackingMarker *marker, int backwards) +void BKE_tracking_refine_marker(MovieClip *clip, MovieTrackingTrack *track, MovieTrackingMarker *marker, bool backwards) { MovieTrackingMarker *reference_marker = NULL; ImBuf *reference_ibuf, *destination_ibuf; @@ -2810,7 +3176,7 @@ void BKE_tracking_refine_marker(MovieClip *clip, MovieTrackingTrack *track, Movi BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height); - /* Get an image buffer for reference frame, also gets referecnce marker. + /* Get an image buffer for reference frame, also gets reference marker. * * Usually tracking_context_get_reference_ibuf will return current frame * if marker is keyframed, which is correct for normal tracking. But here @@ -2863,18 +3229,238 @@ void BKE_tracking_refine_marker(MovieClip *clip, MovieTrackingTrack *track, Movi IMB_freeImBuf(destination_ibuf); } +/*********************** Plane tracking *************************/ + +typedef double Vec2[2]; + +static int point_markers_correspondences_on_both_image(MovieTrackingPlaneTrack *plane_track, int frame1, int frame2, + Vec2 **x1_r, Vec2 **x2_r) +{ + int i, correspondence_index; + Vec2 *x1, *x2; + + *x1_r = x1 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x1"); + *x2_r = x2 = MEM_mallocN(sizeof(*x1) * plane_track->point_tracksnr, "point correspondences x2"); + + for (i = 0, correspondence_index = 0; i < plane_track->point_tracksnr; i++) { + MovieTrackingTrack *point_track = plane_track->point_tracks[i]; + MovieTrackingMarker *point_marker1, *point_marker2; + + point_marker1 = BKE_tracking_marker_get_exact(point_track, frame1); + point_marker2 = BKE_tracking_marker_get_exact(point_track, frame2); + + if (point_marker1 != NULL && point_marker2 != NULL) { + /* Here conversion from float to double happens. */ + x1[correspondence_index][0] = point_marker1->pos[0]; + x1[correspondence_index][1] = point_marker1->pos[1]; + + x2[correspondence_index][0] = point_marker2->pos[0]; + x2[correspondence_index][1] = point_marker2->pos[1]; + + correspondence_index++; + } + } + + return correspondence_index; +} + +/* TODO(sergey): Make it generic function available for everyone. */ +BLI_INLINE void mat3f_from_mat3d(float mat_float[3][3], double mat_double[3][3]) +{ + /* Keep it stupid simple for better data flow in CPU. */ + mat_float[0][0] = mat_double[0][0]; + mat_float[0][1] = mat_double[0][1]; + mat_float[0][2] = mat_double[0][2]; + + mat_float[1][0] = mat_double[1][0]; + mat_float[1][1] = mat_double[1][1]; + mat_float[1][2] = mat_double[1][2]; + + mat_float[2][0] = mat_double[2][0]; + mat_float[2][1] = mat_double[2][1]; + mat_float[2][2] = mat_double[2][2]; +} + +/* NOTE: frame number should be in clip space, not scene space */ +static void track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track, int start_frame, + int direction, bool retrack) +{ + MovieTrackingPlaneMarker *start_plane_marker = BKE_tracking_plane_marker_get(plane_track, start_frame); + MovieTrackingPlaneMarker *keyframe_plane_marker = NULL; + MovieTrackingPlaneMarker new_plane_marker; + int current_frame, frame_delta = direction > 0 ? 1 : -1; + + if (plane_track->flag & PLANE_TRACK_AUTOKEY) { + /* Find a keyframe in given direction. */ + for (current_frame = start_frame; ; current_frame += frame_delta) { + MovieTrackingPlaneMarker *next_plane_marker = + BKE_tracking_plane_marker_get_exact(plane_track, current_frame + frame_delta); + + if (next_plane_marker == NULL) { + break; + } + + if ((next_plane_marker->flag & PLANE_MARKER_TRACKED) == 0) { + keyframe_plane_marker = next_plane_marker; + break; + } + } + } + else { + start_plane_marker->flag |= PLANE_MARKER_TRACKED; + } + + new_plane_marker = *start_plane_marker; + new_plane_marker.flag |= PLANE_MARKER_TRACKED; + + for (current_frame = start_frame; ; current_frame += frame_delta) { + MovieTrackingPlaneMarker *next_plane_marker = + BKE_tracking_plane_marker_get_exact(plane_track, current_frame + frame_delta); + Vec2 *x1, *x2; + int i, num_correspondences; + double H_double[3][3]; + float H[3][3]; + + /* As soon as we meet keyframed plane, we stop updating the sequence. */ + if (next_plane_marker && (next_plane_marker->flag & PLANE_MARKER_TRACKED) == 0) { + /* Don't override keyframes if track is in auto-keyframe mode */ + if (plane_track->flag & PLANE_TRACK_AUTOKEY) { + break; + } + } + + num_correspondences = + point_markers_correspondences_on_both_image(plane_track, current_frame, current_frame + frame_delta, + &x1, &x2); + + if (num_correspondences < 4) { + MEM_freeN(x1); + MEM_freeN(x2); + + break; + } + + libmv_homography2DFromCorrespondencesEuc(x1, x2, num_correspondences, H_double); + + mat3f_from_mat3d(H, H_double); + + for (i = 0; i < 4; i++) { + float vec[3] = {0.0f, 0.0f, 1.0f}, vec2[3]; + copy_v2_v2(vec, new_plane_marker.corners[i]); + + /* Apply homography */ + mul_v3_m3v3(vec2, H, vec); + + /* Normalize. */ + vec2[0] /= vec2[2]; + vec2[1] /= vec2[2]; + + copy_v2_v2(new_plane_marker.corners[i], vec2); + } + + new_plane_marker.framenr = current_frame + frame_delta; + + if (!retrack && keyframe_plane_marker && + next_plane_marker && + (plane_track->flag & PLANE_TRACK_AUTOKEY)) + { + float fac = ((float) next_plane_marker->framenr - start_plane_marker->framenr) / + ((float) keyframe_plane_marker->framenr - start_plane_marker->framenr); + + fac = 3 * fac * fac - 2 * fac * fac * fac; + + for (i = 0; i < 4; i++) { + interp_v2_v2v2(new_plane_marker.corners[i], new_plane_marker.corners[i], + next_plane_marker->corners[i], fac); + } + } + + BKE_tracking_plane_marker_insert(plane_track, &new_plane_marker); + + MEM_freeN(x1); + MEM_freeN(x2); + } +} + +/* NOTE: frame number should be in clip space, not scene space */ +void BKE_tracking_track_plane_from_existing_motion(MovieTrackingPlaneTrack *plane_track, int start_frame) +{ + track_plane_from_existing_motion(plane_track, start_frame, 1, false); + track_plane_from_existing_motion(plane_track, start_frame, -1, false); +} + +static MovieTrackingPlaneMarker *find_plane_keyframe(MovieTrackingPlaneTrack *plane_track, + int start_frame, int direction) +{ + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, start_frame); + int index = plane_marker - plane_track->markers; + int frame_delta = direction > 0 ? 1 : -1; + + while (index >= 0 && index < plane_track->markersnr) { + if ((plane_marker->flag & PLANE_MARKER_TRACKED) == 0) { + return plane_marker; + } + plane_marker += frame_delta; + } + + return NULL; +} + +void BKE_tracking_retrack_plane_from_existing_motion_at_segment(MovieTrackingPlaneTrack *plane_track, int start_frame) +{ + MovieTrackingPlaneMarker *prev_plane_keyframe, *next_plane_keyframe; + + prev_plane_keyframe = find_plane_keyframe(plane_track, start_frame, -1); + next_plane_keyframe = find_plane_keyframe(plane_track, start_frame, 1); + + if (prev_plane_keyframe != NULL && next_plane_keyframe != NULL) { + /* First we track from left keyframe to the right one without any blending. */ + track_plane_from_existing_motion(plane_track, prev_plane_keyframe->framenr, 1, true); + + /* And then we track from the right keyframe to the left one, so shape blends in nicely */ + track_plane_from_existing_motion(plane_track, next_plane_keyframe->framenr, -1, false); + } + else if (prev_plane_keyframe != NULL) { + track_plane_from_existing_motion(plane_track, prev_plane_keyframe->framenr, 1, true); + } + else if (next_plane_keyframe != NULL) { + track_plane_from_existing_motion(plane_track, next_plane_keyframe->framenr, -1, true); + } +} + +BLI_INLINE void float_corners_to_double(/*const*/ float corners[4][2], double double_corners[4][2]) +{ + copy_v2db_v2fl(double_corners[0], corners[0]); + copy_v2db_v2fl(double_corners[1], corners[1]); + copy_v2db_v2fl(double_corners[2], corners[2]); + copy_v2db_v2fl(double_corners[3], corners[3]); +} + +void BKE_tracking_homography_between_two_quads(/*const*/ float reference_corners[4][2], /*const*/ float corners[4][2], float H[3][3]) +{ + Vec2 x1[4], x2[4]; + double H_double[3][3]; + + float_corners_to_double(reference_corners, x1); + float_corners_to_double(corners, x2); + + libmv_homography2DFromCorrespondencesEuc(x1, x2, 4, H_double); + + mat3f_from_mat3d(H, H_double); +} + /*********************** Camera solving *************************/ typedef struct MovieReconstructContext { struct libmv_Tracks *tracks; bool select_keyframes; int keyframe1, keyframe2; - short refine_flags; + int refine_flags; struct libmv_Reconstruction *reconstruction; char object_name[MAX_NAME]; - int is_camera; + bool is_camera; short motion_flag; float focal_length; @@ -2888,7 +3474,7 @@ typedef struct MovieReconstructContext { TracksMap *tracks_map; float success_threshold; - int use_fallback_reconstruction; + bool use_fallback_reconstruction; int sfra, efra; } MovieReconstructContext; @@ -2957,7 +3543,7 @@ static void reconstruct_retrieve_libmv_intrinsics(MovieReconstructContext *conte * Actually, this also copies reconstructed cameras * from libmv to movie clip datablock. */ -static int reconstruct_retrieve_libmv_tracks(MovieReconstructContext *context, MovieTracking *tracking) +static bool reconstruct_retrieve_libmv_tracks(MovieReconstructContext *context, MovieTracking *tracking) { struct libmv_Reconstruction *libmv_reconstruction = context->reconstruction; MovieTrackingReconstruction *reconstruction = NULL; @@ -2999,7 +3585,7 @@ static int reconstruct_retrieve_libmv_tracks(MovieReconstructContext *context, M track->flag &= ~TRACK_HAS_BUNDLE; ok = false; - printf("No bundle for track #%d '%s'\n", tracknr, track->name); + printf("Unable to reconstruct position for track #%d '%s'\n", tracknr, track->name); } track = track->next; @@ -3134,12 +3720,12 @@ static int reconstruct_count_tracks_on_both_keyframes(MovieTracking *tracking, M } /* Perform early check on whether everything is fine to start reconstruction. */ -int BKE_tracking_reconstruction_check(MovieTracking *tracking, MovieTrackingObject *object, - char *error_msg, int error_size) +bool BKE_tracking_reconstruction_check(MovieTracking *tracking, MovieTrackingObject *object, + char *error_msg, int error_size) { if (tracking->settings.motion_flag & TRACKING_MOTION_MODAL) { /* TODO: check for number of tracks? */ - return TRUE; + return true; } else if ((tracking->settings.reconstruction_flag & TRACKING_USE_KEYFRAME_SELECTION) == 0) { /* automatic keyframe selection does not require any pre-process checks */ @@ -3148,16 +3734,16 @@ int BKE_tracking_reconstruction_check(MovieTracking *tracking, MovieTrackingObje N_("At least 8 common tracks on both of keyframes are needed for reconstruction"), error_size); - return FALSE; + return false; } } #ifndef WITH_LIBMV BLI_strncpy(error_msg, N_("Blender is compiled without motion tracking library"), error_size); - return FALSE; + return false; #endif - return TRUE; + return true; } /* Create context for camera/object motion reconstruction. @@ -3264,7 +3850,6 @@ static void reconstruct_update_solve_cb(void *customdata, double progress, const BLI_snprintf(progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message); } - /* FIll in camera intrinsics structure from reconstruction context. */ static void camraIntrincicsOptionsFromContext(libmv_CameraIntrinsicsOptions *camera_intrinsics_options, MovieReconstructContext *context) @@ -3352,7 +3937,7 @@ void BKE_tracking_reconstruction_solve(MovieReconstructContext *context, short * /* Finish reconstruction process by copying reconstructed data * to an actual movie clip datablock. */ -int BKE_tracking_reconstruction_finish(MovieReconstructContext *context, MovieTracking *tracking) +bool BKE_tracking_reconstruction_finish(MovieReconstructContext *context, MovieTracking *tracking) { MovieTrackingReconstruction *reconstruction; MovieTrackingObject *object; @@ -3377,9 +3962,9 @@ int BKE_tracking_reconstruction_finish(MovieReconstructContext *context, MovieTr reconstruction->flag |= TRACKING_RECONSTRUCTED; if (!reconstruct_retrieve_libmv(context, tracking)) - return FALSE; + return false; - return TRUE; + return true; } static void tracking_scale_reconstruction(ListBase *tracksbase, MovieTrackingReconstruction *reconstruction, @@ -3544,7 +4129,7 @@ static unsigned char *detect_get_frame_ucharbuf(ImBuf *ibuf) /* Detect features using FAST detector */ void BKE_tracking_detect_fast(MovieTracking *tracking, ListBase *tracksbase, ImBuf *ibuf, int framenr, int margin, int min_trackness, int min_distance, bGPDlayer *layer, - int place_outside_layer) + bool place_outside_layer) { struct libmv_Features *features; unsigned char *pixels = detect_get_frame_ucharbuf(ibuf); @@ -3556,14 +4141,14 @@ void BKE_tracking_detect_fast(MovieTracking *tracking, ListBase *tracksbase, ImB detect_retrieve_libmv_features(tracking, tracksbase, features, framenr, ibuf->x, ibuf->y, layer, - place_outside_layer ? true : false); + place_outside_layer); libmv_featuresDestroy(features); } /*********************** 2D stabilization *************************/ -/* Claculate median point of markers of tracks marked as used for +/* Calculate median point of markers of tracks marked as used for * 2D stabilization. * * NOTE: frame number should be in clip space, not scene space @@ -3601,7 +4186,7 @@ static bool stabilization_median_point_get(MovieTracking *tracking, int framenr, * * NOTE: frame number should be in clip space, not scene space */ -static void stabilization_calculate_data(MovieTracking *tracking, int framenr, float width, float height, +static void stabilization_calculate_data(MovieTracking *tracking, int framenr, int width, int height, float firstmedian[2], float median[2], float translation[2], float *scale, float *angle) { @@ -3631,7 +4216,7 @@ static void stabilization_calculate_data(MovieTracking *tracking, int framenr, f b[0] *= width; b[1] *= height; - *angle = -atan2(a[0] * b[1] - a[1] * b[0], a[0] * b[0] + a[1] * b[1]); + *angle = -atan2f(a[0] * b[1] - a[1] * b[0], a[0] * b[0] + a[1] * b[1]); *angle *= stab->rotinf; /* convert to rotation around image center */ @@ -3691,8 +4276,8 @@ static float stabilization_calculate_autoscale_factor(MovieTracking *tracking, i BKE_tracking_stabilization_data_to_mat4(width, height, aspect, translation, 1.0f, angle, mat); - si = sin(angle); - co = cos(angle); + si = sinf(angle); + co = cosf(angle); for (i = 0; i < 4; i++) { int j; @@ -3831,7 +4416,7 @@ ImBuf *BKE_tracking_stabilize_frame(MovieTracking *tracking, int framenr, ImBuf float tloc[2], tscale, tangle; MovieTrackingStabilization *stab = &tracking->stabilization; ImBuf *tmpibuf; - float width = ibuf->x, height = ibuf->y; + int width = ibuf->x, height = ibuf->y; float aspect = tracking->camera.pixel_aspect; float mat[4][4]; int j, filter = tracking->stabilization.filter; @@ -3893,7 +4478,7 @@ ImBuf *BKE_tracking_stabilize_frame(MovieTracking *tracking, int framenr, ImBuf for (j = 0; j < tmpibuf->y; j++) { int i; for (i = 0; i < tmpibuf->x; i++) { - float vec[3] = {i, j, 0}; + float vec[3] = {i, j, 0.0f}; mul_v3_m4v3(vec, mat, vec); @@ -3920,7 +4505,7 @@ ImBuf *BKE_tracking_stabilize_frame(MovieTracking *tracking, int framenr, ImBuf * stabilization data and used for easy coordinate * transformation. * - * NOTE: The reaosn it is 4x4 matrix is because it's + * NOTE: The reason it is 4x4 matrix is because it's * used for OpenGL drawing directly. */ void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect, @@ -4170,7 +4755,7 @@ static void tracking_dopesheet_channels_calc(MovieTracking *tracking) /* Sot dopesheet channels using given method (name, average error, total coverage, * longest tracked segment) and could also inverse the list if it's enabled. */ -static void tracking_dopesheet_channels_sort(MovieTracking *tracking, int sort_method, int inverse) +static void tracking_dopesheet_channels_sort(MovieTracking *tracking, int sort_method, bool inverse) { MovieTrackingDopesheet *dopesheet = &tracking->dopesheet; @@ -4307,7 +4892,7 @@ void BKE_tracking_dopesheet_update(MovieTracking *tracking) MovieTrackingDopesheet *dopesheet = &tracking->dopesheet; short sort_method = dopesheet->sort_method; - short inverse = dopesheet->flag & TRACKING_DOPE_SORT_INVERSE; + bool inverse = (dopesheet->flag & TRACKING_DOPE_SORT_INVERSE) != 0; if (dopesheet->ok) return; diff --git a/source/blender/blenkernel/intern/treehash.c b/source/blender/blenkernel/intern/treehash.c new file mode 100644 index 00000000000..d1e9da72208 --- /dev/null +++ b/source/blender/blenkernel/intern/treehash.c @@ -0,0 +1,164 @@ +/* + * ***** 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. + * + * Contributor(s): Blender Foundation 2013 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file treehash.c + * \ingroup bke + * + * Tree hash for the outliner space. + */ + +#include <stdlib.h> + +#include "BKE_treehash.h" + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_mempool.h" + +#include "DNA_outliner_types.h" + +#include "MEM_guardedalloc.h" + +typedef struct TseGroup +{ + TreeStoreElem **elems; + int size; + int allocated; +} TseGroup; + +/* Allocate structure for TreeStoreElements; + * Most of elements in treestore have no duplicates, + * so there is no need to preallocate memory for more than one pointer */ +static TseGroup *tse_group_create(void) +{ + TseGroup *tse_group = MEM_mallocN(sizeof(TseGroup), "TseGroup"); + tse_group->elems = MEM_mallocN(sizeof(TreeStoreElem *), "TseGroupElems"); + tse_group->size = 0; + tse_group->allocated = 1; + return tse_group; +} + +static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem) +{ + if (tse_group->size == tse_group->allocated) { + tse_group->allocated *= 2; + tse_group->elems = MEM_reallocN(tse_group->elems, sizeof(TreeStoreElem *) * tse_group->allocated); + } + tse_group->elems[tse_group->size] = elem; + tse_group->size++; +} + +static void tse_group_free(TseGroup *tse_group) +{ + MEM_freeN(tse_group->elems); + MEM_freeN(tse_group); +} + +static unsigned int tse_hash(const void *ptr) +{ + const TreeStoreElem *tse = ptr; + unsigned int hash; + BLI_assert(tse->type || !tse->nr); + hash = BLI_ghashutil_inthash(SET_INT_IN_POINTER((tse->nr << 16) + tse->type)); + hash ^= BLI_ghashutil_inthash(tse->id); + return hash; +} + +static int tse_cmp(const void *a, const void *b) +{ + const TreeStoreElem *tse_a = a; + const TreeStoreElem *tse_b = b; + return tse_a->type != tse_b->type || tse_a->nr != tse_b->nr || tse_a->id != tse_b->id; +} + +static void fill_treehash(void *treehash, BLI_mempool *treestore) +{ + TreeStoreElem *tselem; + BLI_mempool_iter iter; + BLI_mempool_iternew(treestore, &iter); + while ((tselem = BLI_mempool_iterstep(&iter))) { + BKE_treehash_add_element(treehash, tselem); + } +} + +void *BKE_treehash_create_from_treestore(BLI_mempool *treestore) +{ + GHash *treehash = BLI_ghash_new_ex(tse_hash, tse_cmp, "treehash", BLI_mempool_count(treestore)); + fill_treehash(treehash, treestore); + return treehash; +} + +static void free_treehash_group(void *key) +{ + tse_group_free(key); +} + +void *BKE_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore) +{ + BLI_ghash_clear_ex(treehash, NULL, free_treehash_group, BLI_mempool_count(treestore)); + fill_treehash(treehash, treestore); + return treehash; +} + +void BKE_treehash_add_element(void *treehash, TreeStoreElem *elem) +{ + TseGroup *group = BLI_ghash_lookup(treehash, elem); + if (!group) { + group = tse_group_create(); + BLI_ghash_insert(treehash, elem, group); + } + tse_group_add(group, elem); +} + +static TseGroup *BKE_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id) +{ + TreeStoreElem tse_template; + tse_template.type = type; + tse_template.nr = type ? nr : 0; // we're picky! :) + tse_template.id = id; + return BLI_ghash_lookup(th, &tse_template); +} + +TreeStoreElem *BKE_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id) +{ + TseGroup *group = BKE_treehash_lookup_group(treehash, type, nr, id); + if (group) { + int i; + for (i = 0; i < group->size; i++) { + if (!group->elems[i]->used) { + return group->elems[i]; + } + } + } + return NULL; +} + +TreeStoreElem *BKE_treehash_lookup_any(void *treehash, short type, short nr, struct ID *id) +{ + TseGroup *group = BKE_treehash_lookup_group(treehash, type, nr, id); + return group ? group->elems[0] : NULL; +} + +void BKE_treehash_free(void *treehash) +{ + BLI_ghash_free(treehash, NULL, free_treehash_group); +} diff --git a/source/blender/blenlib/BLI_alloca.h b/source/blender/blenlib/BLI_alloca.h index b93f5b7123e..06c3e8d8996 100644 --- a/source/blender/blenlib/BLI_alloca.h +++ b/source/blender/blenlib/BLI_alloca.h @@ -19,6 +19,7 @@ */ #ifndef __BLI_ALLOCA_H__ +#define __BLI_ALLOCA_H__ /** \file BLI_alloca.h * \ingroup bli diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h index 566fc95eb4f..4110c85c2a5 100644 --- a/source/blender/blenlib/BLI_array.h +++ b/source/blender/blenlib/BLI_array.h @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2008 Blender Foundation. * All rights reserved. diff --git a/source/blender/blenlib/BLI_bitmap.h b/source/blender/blenlib/BLI_bitmap.h index ca98d28cc40..bcdc97cdaa7 100644 --- a/source/blender/blenlib/BLI_bitmap.h +++ b/source/blender/blenlib/BLI_bitmap.h @@ -26,6 +26,10 @@ #ifndef __BLI_BITMAP_H__ #define __BLI_BITMAP_H__ +/** \file BLI_bitmap.h + * \ingroup bli + */ + typedef unsigned int BLI_bitmap; /* warning: the bitmap does not keep track of its own size or check @@ -54,17 +58,17 @@ typedef unsigned int BLI_bitmap; /* get the value of a single bit at '_index' */ #define BLI_BITMAP_GET(_bitmap, _index) \ ((_bitmap)[(_index) >> BLI_BITMAP_POWER] & \ - (1 << ((_index) & BLI_BITMAP_MASK))) + (1u << ((_index) & BLI_BITMAP_MASK))) /* set the value of a single bit at '_index' */ #define BLI_BITMAP_SET(_bitmap, _index) \ ((_bitmap)[(_index) >> BLI_BITMAP_POWER] |= \ - (1 << ((_index) & BLI_BITMAP_MASK))) + (1u << ((_index) & BLI_BITMAP_MASK))) /* clear the value of a single bit at '_index' */ #define BLI_BITMAP_CLEAR(_bitmap, _index) \ ((_bitmap)[(_index) >> BLI_BITMAP_POWER] &= \ - ~(1 << ((_index) & BLI_BITMAP_MASK))) + ~(1u << ((_index) & BLI_BITMAP_MASK))) /* set or clear the value of a single bit at '_index' */ #define BLI_BITMAP_MODIFY(_bitmap, _index, _set) \ diff --git a/source/blender/blenlib/BLI_boxpack2d.h b/source/blender/blenlib/BLI_boxpack2d.h index 3bc486054f5..8316987dfcd 100644 --- a/source/blender/blenlib/BLI_boxpack2d.h +++ b/source/blender/blenlib/BLI_boxpack2d.h @@ -46,7 +46,7 @@ typedef struct BoxPack { struct BoxVert *v[4]; } BoxPack; -void BLI_box_pack_2D(BoxPack *boxarray, const int len, float *tot_width, float *tot_height); +void BLI_box_pack_2d(BoxPack *boxarray, const int len, float *tot_width, float *tot_height); #endif diff --git a/source/blender/blenlib/BLI_buffer.h b/source/blender/blenlib/BLI_buffer.h index 461b56e157f..9c4b4b00b24 100644 --- a/source/blender/blenlib/BLI_buffer.h +++ b/source/blender/blenlib/BLI_buffer.h @@ -21,21 +21,23 @@ #ifndef __BLI_BUFFER_H__ #define __BLI_BUFFER_H__ -/* Note: this more or less fills same purpose as BLI_array, but makes +/** \file BLI_buffer.h + * \ingroup bli + * + * \note this more or less fills same purpose as BLI_array, but makes * it much easier to resize the array outside of the function it was - * declared in since */ - -/* Usage examples: + * declared in since. * - * { - * BLI_buffer_declare_static(int, my_int_array, BLI_BUFFER_NOP, 32); + * Usage examples: + * \code + * BLI_buffer_declare_static(int, my_int_array, BLI_BUFFER_NOP, 32); * - * BLI_buffer_append(my_int_array, int, 42); - * assert(my_int_array.count == 1); - * assert(BLI_buffer_at(my_int_array, int, 0) == 42); + * BLI_buffer_append(my_int_array, int, 42); + * assert(my_int_array.count == 1); + * assert(BLI_buffer_at(my_int_array, int, 0) == 42); * - * BLI_buffer_free(&my_int_array); - * } + * BLI_buffer_free(&my_int_array); + * \endcode */ typedef struct { diff --git a/source/blender/blenlib/BLI_callbacks.h b/source/blender/blenlib/BLI_callbacks.h index 8a0442c8bc8..8d5ea91c422 100644 --- a/source/blender/blenlib/BLI_callbacks.h +++ b/source/blender/blenlib/BLI_callbacks.h @@ -18,7 +18,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/blenlib/BLI_callbacks.h +/** \file BLI_callbacks.h * \ingroup bli */ @@ -43,6 +43,8 @@ typedef enum { BLI_CB_EVT_SAVE_POST, BLI_CB_EVT_SCENE_UPDATE_PRE, BLI_CB_EVT_SCENE_UPDATE_POST, + BLI_CB_EVT_GAME_PRE, + BLI_CB_EVT_GAME_POST, BLI_CB_EVT_TOT } eCbEvent; @@ -61,8 +63,4 @@ void BLI_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt); void BLI_callback_global_init(void); void BLI_callback_global_finalize(void); - -/* This is blenlib internal only, unrelated to above */ -void callLocalErrorCallBack(const char *msg); - #endif /* __BLI_CALLBACKS_H__ */ diff --git a/source/blender/blenlib/BLI_compiler_attrs.h b/source/blender/blenlib/BLI_compiler_attrs.h new file mode 100644 index 00000000000..fc16e7dbba6 --- /dev/null +++ b/source/blender/blenlib/BLI_compiler_attrs.h @@ -0,0 +1,88 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Campbell Barton + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_COMPILER_ATTRS_H__ +#define __BLI_COMPILER_ATTRS_H__ + +/** \file BLI_compiler_attrs.h + * \ingroup bli + */ + +/* hint to make sure function result is actually used */ +#ifdef __GNUC__ +# define ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define ATTR_WARN_UNUSED_RESULT +#endif + +/* hint to mark function arguments expected to be non-null + * if no arguments are given to the macro, all of pointer + * arguments owuld be expected to be non-null + */ +#ifdef __GNUC__ +# define ATTR_NONNULL(args ...) __attribute__((nonnull(args))) +#else +# define ATTR_NONNULL(...) +#endif + +/* hint to mark function as it wouldn't return */ +#if defined(__GNUC__) || defined(__clang__) +# define ATTR_NORETURN __attribute__((noreturn)) +#else +# define ATTR_NORETURN +#endif + +/* hint to treat any non-null function return value cannot alias any other pointer */ +#if (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 403)) +# define ATTR_MALLOC __attribute__((malloc)) +#else +# define ATTR_MALLOC +#endif + +/* the function return value points to memory (2 args for 'size * tot') */ +#if (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 403)) +# define ATTR_ALLOC_SIZE(args ...) __attribute__((alloc_size(args))) +#else +# define ATTR_ALLOC_SIZE(...) +#endif + +/* ensures a NULL terminating argument as the n'th last argument of a variadic function */ +#ifdef __GNUC__ +# define ATTR_SENTINEL(arg_pos) __attribute__((sentinel(arg_pos))) +#else +# define ATTR_SENTINEL(arg_pos) +#endif + +/* hint to compiler that function uses printf-style format string */ +#ifdef __GNUC__ +# define ATTR_PRINTF_FORMAT(format_param, dots_param) __attribute__((format(printf, format_param, dots_param))) +#else +# define ATTR_PRINTF_FORMAT(format_param, dots_param) +#endif + +#endif /* __BLI_COMPILER_ATTRS_H__ */ diff --git a/source/blender/compositor/operations/COM_MixBlendOperation.h b/source/blender/blenlib/BLI_convexhull2d.h index ce3f187a5e2..4b82071ede8 100644 --- a/source/blender/compositor/operations/COM_MixBlendOperation.h +++ b/source/blender/blenlib/BLI_convexhull2d.h @@ -1,5 +1,5 @@ /* - * Copyright 2011, Blender Foundation. + * ***** 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 @@ -15,31 +15,20 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand + * ***** END GPL LICENSE BLOCK ***** */ -#ifndef _COM_MixBlendOperation_h -#define _COM_MixBlendOperation_h -#include "COM_MixBaseOperation.h" +#ifndef __BLI_CONVEXHULL2D_H__ +#define __BLI_CONVEXHULL2D_H__ - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. +/** \file BLI_convexhull2d.h + * \ingroup bli */ -class MixBlendOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixBlendOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); -}; -#endif +int BLI_convexhull_2d_sorted(const float (*points)[2], const int n, int r_points[]); +int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[]); + +float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned int n); +float BLI_convexhull_aabb_fit_points_2d(const float (*points)[2], unsigned int n); + +#endif /* __BLI_CONVEXHULL2D_H__ */ diff --git a/source/blender/blenlib/BLI_dynstr.h b/source/blender/blenlib/BLI_dynstr.h index 833c416c1c1..61bdf23cec1 100644 --- a/source/blender/blenlib/BLI_dynstr.h +++ b/source/blender/blenlib/BLI_dynstr.h @@ -40,6 +40,8 @@ #include <stdarg.h> +#include "BLI_compiler_attrs.h" + struct DynStr; /** The abstract DynStr type */ @@ -75,16 +77,8 @@ void BLI_dynstr_nappend(DynStr *ds, const char *cstr, int len); * \param ds The DynStr to append to. * \param format The printf format string to use. */ -void BLI_dynstr_appendf(DynStr *ds, const char *format, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 2, 3))) -#endif -; -void BLI_dynstr_vappendf(DynStr *ds, const char *format, va_list args) -#ifdef __GNUC__ -__attribute__ ((format(printf, 2, 0))) -#endif -; +void BLI_dynstr_appendf(DynStr *ds, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3); +void BLI_dynstr_vappendf(DynStr *ds, const char *format, va_list args) ATTR_PRINTF_FORMAT(2, 0); /** * Find the length of a DynStr. diff --git a/source/blender/blenlib/BLI_edgehash.h b/source/blender/blenlib/BLI_edgehash.h index 9ece3afde37..2ca011871d8 100644 --- a/source/blender/blenlib/BLI_edgehash.h +++ b/source/blender/blenlib/BLI_edgehash.h @@ -29,6 +29,8 @@ * \brief A general unordered 2-int pair hash table ADT. */ +#include "BLI_compiler_attrs.h" + struct EdgeHash; struct EdgeHashIterator; typedef struct EdgeHash EdgeHash; @@ -36,60 +38,60 @@ typedef struct EdgeHashIterator EdgeHashIterator; typedef void (*EdgeHashFreeFP)(void *key); -EdgeHash *BLI_edgehash_new(void); -void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP valfreefp); +enum { + EDGEHASH_FLAG_ALLOW_DUPES = (1 << 0), /* only checked for in debug mode */ +}; -/* Insert edge (v0,v1) into hash with given value, does - * not check for duplicates. - */ +EdgeHash *BLI_edgehash_new_ex(const char *info, + const unsigned int nentries_reserve); +EdgeHash *BLI_edgehash_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP valfreefp); void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val); - -/* Return value for given edge (v0,v1), or NULL if - * if key does not exist in hash. (If need exists - * to differentiate between key-value being NULL and - * lack of key then see BLI_edgehash_lookup_p(). - */ -void *BLI_edgehash_lookup(EdgeHash *eh, unsigned int v0, unsigned int v1); - -/* Return pointer to value for given edge (v0,v1), - * or NULL if key does not exist in hash. - */ -void **BLI_edgehash_lookup_p(EdgeHash *eh, unsigned int v0, unsigned int v1); - -/* Return boolean true/false if edge (v0,v1) in hash. */ -bool BLI_edgehash_haskey(EdgeHash *eh, unsigned int v0, unsigned int v1); - -/* Return number of keys in hash. */ -int BLI_edgehash_size(EdgeHash *eh); - -/* Remove all edges from hash. */ +bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val); +void *BLI_edgehash_lookup(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT; +void **BLI_edgehash_lookup_p(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, + const unsigned int nentries_reserve); void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP valfreefp); +void BLI_edgehash_flag_set(EdgeHash *eh, unsigned int flag); +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. - */ -EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh); - -/* Free an EdgeHashIterator. */ +EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; void BLI_edgehashIterator_free(EdgeHashIterator *ehi); - -/* Retrieve the key from an iterator. */ void BLI_edgehashIterator_getKey(EdgeHashIterator *ehi, unsigned int *v0_r, unsigned int *v1_r); +void *BLI_edgehashIterator_getValue(EdgeHashIterator *ehi) ATTR_WARN_UNUSED_RESULT; +void **BLI_edgehashIterator_getValue_p(EdgeHashIterator *ehi) ATTR_WARN_UNUSED_RESULT; +void BLI_edgehashIterator_setValue(EdgeHashIterator *ehi, void *val); +void BLI_edgehashIterator_step(EdgeHashIterator *ehi); +bool BLI_edgehashIterator_isDone(EdgeHashIterator *ehi) ATTR_WARN_UNUSED_RESULT; -/* Retrieve the value from an iterator. */ -void *BLI_edgehashIterator_getValue(EdgeHashIterator *ehi); +#define BLI_EDGEHASH_SIZE_GUESS_FROM_LOOPS(totloop) ((totloop) / 2) +#define BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totpoly) ((totpoly) * 2) -/* Set the value for an iterator. */ -void BLI_edgehashIterator_setValue(EdgeHashIterator *ehi, void *val); +/* *** EdgeSet *** */ -/* Steps the iterator to the next index. */ -void BLI_edgehashIterator_step(EdgeHashIterator *ehi); +struct EdgeSet; +struct EdgeSetIterator; +typedef struct EdgeSet EdgeSet; +typedef struct EdgeSetIterator EdgeSetIterator; + +EdgeSet *BLI_edgeset_new_ex(const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +EdgeSet *BLI_edgeset_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +int BLI_edgeset_size(EdgeSet *es) ATTR_WARN_UNUSED_RESULT; +bool BLI_edgeset_reinsert(EdgeSet *es, unsigned int v0, unsigned int v1); +void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1); +bool BLI_edgeset_haskey(EdgeSet *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT; +void BLI_edgeset_free(EdgeSet *es); + +/* rely on inline api for now */ +BLI_INLINE EdgeSetIterator *BLI_edgesetIterator_new(EdgeSet *gs) { return (EdgeSetIterator *)BLI_edgehashIterator_new((EdgeHash *)gs); } +BLI_INLINE void BLI_edgesetIterator_free(EdgeSetIterator *esi) { BLI_edgehashIterator_free((EdgeHashIterator *)esi); } +BLI_INLINE void BLI_edgesetIterator_getKey(EdgeSetIterator *esi, unsigned int *v0_r, unsigned int *v1_r) { BLI_edgehashIterator_getKey((EdgeHashIterator *)esi, v0_r, v1_r); } +BLI_INLINE void BLI_edgesetIterator_step(EdgeSetIterator *esi) { BLI_edgehashIterator_step((EdgeHashIterator *)esi); } +BLI_INLINE bool BLI_edgesetIterator_isDone(EdgeSetIterator *esi) { return BLI_edgehashIterator_isDone((EdgeHashIterator *)esi); } -/* Determine if an iterator is done. */ -bool BLI_edgehashIterator_isDone(EdgeHashIterator *ehi); -#endif +#endif /* __BLI_EDGEHASH_H__ */ diff --git a/source/blender/blenlib/BLI_endian_switch.h b/source/blender/blenlib/BLI_endian_switch.h index f48b1b072c3..35242fecf4a 100644 --- a/source/blender/blenlib/BLI_endian_switch.h +++ b/source/blender/blenlib/BLI_endian_switch.h @@ -27,35 +27,28 @@ * \ingroup bli */ -#ifdef __GNUC__ -# define ATTR_ENDIAN_SWITCH \ - __attribute__((nonnull(1))) -#else -# define ATTR_ENDIAN_SWITCH -#endif +#include "BLI_compiler_attrs.h" /* BLI_endian_switch_inline.h */ -BLI_INLINE void BLI_endian_switch_int16(short *val) ATTR_ENDIAN_SWITCH; -BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val) ATTR_ENDIAN_SWITCH; -BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_ENDIAN_SWITCH; -BLI_INLINE void BLI_endian_switch_uint32(unsigned int *val) ATTR_ENDIAN_SWITCH; -BLI_INLINE void BLI_endian_switch_float(float *val) ATTR_ENDIAN_SWITCH; -BLI_INLINE void BLI_endian_switch_int64(int64_t *val) ATTR_ENDIAN_SWITCH; -BLI_INLINE void BLI_endian_switch_uint64(uint64_t *val) ATTR_ENDIAN_SWITCH; -BLI_INLINE void BLI_endian_switch_double(double *val) ATTR_ENDIAN_SWITCH; +BLI_INLINE void BLI_endian_switch_int16(short *val) ATTR_NONNULL(1); +BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val) ATTR_NONNULL(1); +BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_NONNULL(1); +BLI_INLINE void BLI_endian_switch_uint32(unsigned int *val) ATTR_NONNULL(1); +BLI_INLINE void BLI_endian_switch_float(float *val) ATTR_NONNULL(1); +BLI_INLINE void BLI_endian_switch_int64(int64_t *val) ATTR_NONNULL(1); +BLI_INLINE void BLI_endian_switch_uint64(uint64_t *val) ATTR_NONNULL(1); +BLI_INLINE void BLI_endian_switch_double(double *val) ATTR_NONNULL(1); /* endian_switch.c */ -void BLI_endian_switch_int16_array(short *val, const int size) ATTR_ENDIAN_SWITCH; -void BLI_endian_switch_uint16_array(unsigned short *val, const int size) ATTR_ENDIAN_SWITCH; -void BLI_endian_switch_int32_array(int *val, const int size) ATTR_ENDIAN_SWITCH; -void BLI_endian_switch_uint32_array(unsigned int *val, const int size) ATTR_ENDIAN_SWITCH; -void BLI_endian_switch_float_array(float *val, const int size) ATTR_ENDIAN_SWITCH; -void BLI_endian_switch_int64_array(int64_t *val, const int size) ATTR_ENDIAN_SWITCH; -void BLI_endian_switch_uint64_array(uint64_t *val, const int size) ATTR_ENDIAN_SWITCH; -void BLI_endian_switch_double_array(double *val, const int size) ATTR_ENDIAN_SWITCH; +void BLI_endian_switch_int16_array(short *val, const int size) ATTR_NONNULL(1); +void BLI_endian_switch_uint16_array(unsigned short *val, const int size) ATTR_NONNULL(1); +void BLI_endian_switch_int32_array(int *val, const int size) ATTR_NONNULL(1); +void BLI_endian_switch_uint32_array(unsigned int *val, const int size) ATTR_NONNULL(1); +void BLI_endian_switch_float_array(float *val, const int size) ATTR_NONNULL(1); +void BLI_endian_switch_int64_array(int64_t *val, const int size) ATTR_NONNULL(1); +void BLI_endian_switch_uint64_array(uint64_t *val, const int size) ATTR_NONNULL(1); +void BLI_endian_switch_double_array(double *val, const int size) ATTR_NONNULL(1); #include "BLI_endian_switch_inline.h" -#undef ATTR_ENDIAN_SWITCH - #endif /* __BLI_ENDIAN_SWITCH_H__ */ diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index 0a6d95df40a..ca82086b529 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -43,6 +43,12 @@ extern "C" { /* for size_t (needed on windows) */ #include <stddef.h> +#include <limits.h> /* for PATH_MAX */ + +#ifndef PATH_MAX +# define PATH_MAX 4096 +#endif + struct gzFile; /* Common */ diff --git a/source/blender/blenlib/BLI_fnmatch.h b/source/blender/blenlib/BLI_fnmatch.h index 6c466759010..f69f5b39869 100644 --- a/source/blender/blenlib/BLI_fnmatch.h +++ b/source/blender/blenlib/BLI_fnmatch.h @@ -28,6 +28,8 @@ extern "C" { #endif +#if defined WIN32 && !defined _LIBC || defined __sun + #if defined(__cplusplus) || (defined(__STDC__) && __STDC__) #undef __P #define __P(protos) protos @@ -65,6 +67,13 @@ extern "C" { extern int fnmatch __P((const char *__pattern, const char *__string, int __flags)); +#else +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +# include <fnmatch.h> +#endif /* defined WIN32 && !defined _LIBC || defined __sun */ + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index 3ad0e18c8d7..e5a93691ad0 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -33,6 +33,9 @@ * \brief A general (pointer -> pointer) hash table ADT */ +#include "BLI_sys_types.h" /* for bool */ +#include "BLI_compiler_attrs.h" + #ifdef __cplusplus extern "C" { #endif @@ -42,97 +45,51 @@ typedef int (*GHashCmpFP) (const void *a, const void *b); typedef void (*GHashKeyFreeFP) (void *key); typedef void (*GHashValFreeFP) (void *val); -typedef struct Entry { - struct Entry *next; - - void *key, *val; -} Entry; - -typedef struct GHash { - GHashHashFP hashfp; - GHashCmpFP cmpfp; - - Entry **buckets; - struct BLI_mempool *entrypool; - unsigned int nbuckets; - unsigned int nentries, cursize; -} GHash; +typedef struct GHash GHash; typedef struct GHashIterator { GHash *gh; - unsigned int curBucket; struct Entry *curEntry; + unsigned int curBucket; } GHashIterator; +enum { + GHASH_FLAG_ALLOW_DUPES = (1 << 0), /* only checked for in debug mode */ +}; + /* *** */ -GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info); +GHash *BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); void BLI_ghash_insert(GHash *gh, void *key, void *val); -void *BLI_ghash_lookup(GHash *gh, const void *key); +bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); +void *BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; +void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; bool BLI_ghash_remove(GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); -void *BLI_ghash_pop(GHash *gh, void *key, GHashKeyFreeFP keyfreefp); -bool BLI_ghash_haskey(GHash *gh, const void *key); -int BLI_ghash_size(GHash *gh); +void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, + const unsigned int nentries_reserve); +void *BLI_ghash_popkey(GHash *gh, void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT; +bool BLI_ghash_haskey(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; +int BLI_ghash_size(GHash *gh) ATTR_WARN_UNUSED_RESULT; +void BLI_ghash_flag_set(GHash *gh, unsigned int flag); +void BLI_ghash_flag_clear(GHash *gh, unsigned int flag); /* *** */ -/** - * Create a new GHashIterator. The hash table must not be mutated - * while the iterator is in use, and the iterator will step exactly - * BLI_ghash_size(gh) times before becoming done. - * - * \param gh The GHash to iterate over. - * \return Pointer to a new DynStr. - */ -GHashIterator *BLI_ghashIterator_new(GHash *gh); -/** - * Init an already allocated GHashIterator. The hash table must not - * be mutated while the iterator is in use, and the iterator will - * step exactly BLI_ghash_size(gh) times before becoming done. - * - * \param ghi The GHashIterator to initialize. - * \param gh The GHash to iterate over. - */ -void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh); -/** - * Free a GHashIterator. - * - * \param ghi The iterator to free. - */ -void BLI_ghashIterator_free(GHashIterator *ghi); +GHashIterator *BLI_ghashIterator_new(GHash *gh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; -/** - * Retrieve the key from an iterator. - * - * \param ghi The iterator. - * \return The key at the current index, or NULL if the - * iterator is done. - */ -void *BLI_ghashIterator_getKey(GHashIterator *ghi); -/** - * Retrieve the value from an iterator. - * - * \param ghi The iterator. - * \return The value at the current index, or NULL if the - * iterator is done. - */ -void *BLI_ghashIterator_getValue(GHashIterator *ghi); -/** - * Steps the iterator to the next index. - * - * \param ghi The iterator. - */ -void BLI_ghashIterator_step(GHashIterator *ghi); -/** - * Determine if an iterator is done (has reached the end of - * the hash table). - * - * \param ghi The iterator. - * \return True if done, False otherwise. - */ -bool BLI_ghashIterator_done(GHashIterator *ghi); +void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh); +void BLI_ghashIterator_free(GHashIterator *ghi); + +void *BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT; +void *BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT; +void **BLI_ghashIterator_getValue_p(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT; + +void BLI_ghashIterator_step(GHashIterator *ghi); +bool BLI_ghashIterator_done(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT; #define GHASH_ITER(gh_iter_, ghash_) \ for (BLI_ghashIterator_init(&gh_iter_, ghash_); \ @@ -155,10 +112,18 @@ int BLI_ghashutil_strcmp(const void *a, const void *b); unsigned int BLI_ghashutil_inthash(const void *ptr); int BLI_ghashutil_intcmp(const void *a, const void *b); -GHash *BLI_ghash_ptr_new(const char *info); -GHash *BLI_ghash_str_new(const char *info); -GHash *BLI_ghash_int_new(const char *info); -GHash *BLI_ghash_pair_new(const char *info); +GHash *BLI_ghash_ptr_new_ex(const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_str_new_ex(const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_str_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_int_new_ex(const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_pair_new_ex(const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GHash *BLI_ghash_pair_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; typedef struct GHashPair { const void *first; @@ -170,6 +135,62 @@ unsigned int BLI_ghashutil_pairhash(const void *ptr); int BLI_ghashutil_paircmp(const void *a, const void *b); void BLI_ghashutil_pairfree(void *ptr); + +/* *** */ + +typedef struct GSet GSet; + +typedef GHashHashFP GSetHashFP; +typedef GHashCmpFP GSetCmpFP; +typedef GHashKeyFreeFP GSetKeyFreeFP; + +/* so we can cast but compiler sees as different */ +typedef struct GSetIterator { + GHashIterator _ghi +#ifdef __GNUC__ + __attribute__ ((deprecated)) +#endif + ; +} GSetIterator; + +GSet *BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +int BLI_gset_size(GSet *gs) ATTR_WARN_UNUSED_RESULT; +void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp); +void BLI_gset_insert(GSet *gh, void *key); +bool BLI_gset_reinsert(GSet *gh, void *key, GSetKeyFreeFP keyfreefp); +bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT; +bool BLI_gset_remove(GSet *gs, void *key, GSetKeyFreeFP keyfreefp); +void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp, + const unsigned int nentries_reserve); +void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp); + +GSet *BLI_gset_ptr_new_ex(const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GSet *BLI_gset_ptr_new(const char *info); +GSet *BLI_gset_pair_new_ex(const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GSet *BLI_gset_pair_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; + +/* rely on inline api for now */ +BLI_INLINE GSetIterator *BLI_gsetIterator_new(GSet *gs) { return (GSetIterator *)BLI_ghashIterator_new((GHash *)gs); } +BLI_INLINE void BLI_gsetIterator_init(GSetIterator *gsi, GSet *gs) { BLI_ghashIterator_init((GHashIterator *)gsi, (GHash *)gs); } +BLI_INLINE void BLI_gsetIterator_free(GSetIterator *gsi) { BLI_ghashIterator_free((GHashIterator *)gsi); } +BLI_INLINE void *BLI_gsetIterator_getKey(GSetIterator *gsi) { return BLI_ghashIterator_getKey((GHashIterator *)gsi); } +BLI_INLINE void BLI_gsetIterator_step(GSetIterator *gsi) { BLI_ghashIterator_step((GHashIterator *)gsi); } +BLI_INLINE bool BLI_gsetIterator_done(GSetIterator *gsi) { return BLI_ghashIterator_done((GHashIterator *)gsi); } + +#define GSET_ITER(gs_iter_, gset_) \ + for (BLI_gsetIterator_init(&gs_iter_, gset_); \ + BLI_gsetIterator_done(&gs_iter_) == false; \ + BLI_gsetIterator_step(&gs_iter_)) + +#define GSET_ITER_INDEX(gs_iter_, gset_, i_) \ + for (BLI_gsetIterator_init(&gs_iter_, gset_), i_ = 0; \ + BLI_gsetIterator_done(&gs_iter_) == false; \ + BLI_gsetIterator_step(&gs_iter_), i_++) + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/BLI_jitter.h b/source/blender/blenlib/BLI_jitter.h index 432bf73ad90..936a5260a68 100644 --- a/source/blender/blenlib/BLI_jitter.h +++ b/source/blender/blenlib/BLI_jitter.h @@ -33,8 +33,8 @@ */ void BLI_jitter_init(float *jitarr, int num); -void BLI_jitterate1(float *jit1, float *jit2, int num, float rad1); -void BLI_jitterate2(float *jit1, float *jit2, int num, float rad2); +void BLI_jitterate1(float *jit1, float *jit2, int num, float radius1); +void BLI_jitterate2(float *jit1, float *jit2, int num, float radius2); #endif diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h index 8441413fba9..b55ab432a12 100644 --- a/source/blender/blenlib/BLI_kdopbvh.h +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -87,7 +87,7 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis); void BLI_bvhtree_free(BVHTree *tree); /* construct: first insert points, then call balance */ -int BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints); +void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints); void BLI_bvhtree_balance(BVHTree *tree); /* update: first update points/nodes, then call update_tree to refit the bounding volumes */ diff --git a/source/blender/blenlib/BLI_kdtree.h b/source/blender/blenlib/BLI_kdtree.h index b687d98e6ad..e3c81021351 100644 --- a/source/blender/blenlib/BLI_kdtree.h +++ b/source/blender/blenlib/BLI_kdtree.h @@ -31,6 +31,8 @@ * \author Brecht van Lommel */ +#include "BLI_compiler_attrs.h" + struct KDTree; typedef struct KDTree KDTree; @@ -40,22 +42,19 @@ typedef struct KDTreeNearest { float co[3]; } KDTreeNearest; -/* Creates or free a kdtree */ -KDTree *BLI_kdtree_new(int maxsize); +KDTree *BLI_kdtree_new(unsigned int maxsize); void BLI_kdtree_free(KDTree *tree); -/* Construction: first insert points, then call balance. Normal is optional. */ -void BLI_kdtree_insert(KDTree *tree, int index, const float co[3], const float nor[3]); -void BLI_kdtree_balance(KDTree *tree); - -/* Find nearest returns index, and -1 if no node is found. - * Find n nearest returns number of points found, with results in nearest. - * Normal is optional, but if given will limit results to points in normal direction from co. */ -int BLI_kdtree_find_nearest(KDTree *tree, const float co[3], const float nor[3], KDTreeNearest *nearest); -int BLI_kdtree_find_n_nearest(KDTree *tree, int n, const float co[3], const float nor[3], KDTreeNearest *nearest); - -/* Range search returns number of points found, with results in nearest */ -/* Normal is optional, but if given will limit results to points in normal direction from co. */ -/* Remember to free nearest after use! */ -int BLI_kdtree_range_search(KDTree *tree, float range, const float co[3], const float nor[3], KDTreeNearest **nearest); -#endif +void BLI_kdtree_insert(KDTree *tree, int index, const float co[3], const float nor[3]) ATTR_NONNULL(1, 3); +void BLI_kdtree_balance(KDTree *tree) ATTR_NONNULL(1); + +int BLI_kdtree_find_nearest(KDTree *tree, const float co[3], const float nor[3], + KDTreeNearest *r_nearest) ATTR_NONNULL(1, 2); +int BLI_kdtree_find_nearest_n(KDTree *tree, const float co[3], const float nor[3], + KDTreeNearest *r_nearest, + unsigned int n) ATTR_NONNULL(1, 2, 4); +int BLI_kdtree_range_search(KDTree *tree, const float co[3], const float nor[3], + KDTreeNearest **r_nearest, + float range) ATTR_NONNULL(1, 2, 4) ATTR_WARN_UNUSED_RESULT; + +#endif /* __BLI_KDTREE_H__ */ diff --git a/source/blender/blenlib/BLI_lasso.h b/source/blender/blenlib/BLI_lasso.h index 0addd463a70..28f21e5bd85 100644 --- a/source/blender/blenlib/BLI_lasso.h +++ b/source/blender/blenlib/BLI_lasso.h @@ -34,8 +34,8 @@ struct rcti; -void BLI_lasso_boundbox(struct rcti *rect, const int mcords[][2], const short moves); -bool BLI_lasso_is_point_inside(const int mcords[][2], const short moves, const int sx, const int sy, const int error_value); -bool BLI_lasso_is_edge_inside(const int mcords[][2], const short moves, int x0, int y0, int x1, int y1, const int error_value); +void BLI_lasso_boundbox(struct rcti *rect, const int mcords[][2], const unsigned int moves); +bool BLI_lasso_is_point_inside(const int mcords[][2], const unsigned int moves, const int sx, const int sy, const int error_value); +bool BLI_lasso_is_edge_inside(const int mcords[][2], const unsigned int moves, int x0, int y0, int x1, int y1, const int error_value); #endif diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h index 3e7fdc8bf75..2ca363ee780 100644 --- a/source/blender/blenlib/BLI_linklist.h +++ b/source/blender/blenlib/BLI_linklist.h @@ -36,6 +36,7 @@ */ struct MemArena; +struct BLI_mempool; typedef void (*LinkNodeFreeFP)(void *link); typedef void (*LinkNodeApplyFP)(void *link, void *userdata); @@ -53,13 +54,26 @@ struct LinkNode *BLI_linklist_find(struct LinkNode *list, int index); void BLI_linklist_reverse(struct LinkNode **listp); +void BLI_linklist_prepend_nlink(struct LinkNode **listp, void *ptr, struct LinkNode *nlink); void BLI_linklist_prepend(struct LinkNode **listp, void *ptr); -void BLI_linklist_append(struct LinkNode **listp, void *ptr); void BLI_linklist_prepend_arena(struct LinkNode **listp, void *ptr, struct MemArena *ma); +void BLI_linklist_prepend_pool(struct LinkNode **listp, void *ptr, struct BLI_mempool *mempool); + +void BLI_linklist_append_nlink(LinkNode **listp, void *ptr, LinkNode *nlink); +void BLI_linklist_append(struct LinkNode **listp, void *ptr); +void BLI_linklist_append_arena(LinkNode **listp, void *ptr, struct MemArena *ma); +void BLI_linklist_append_pool(LinkNode **listp, void *ptr, struct BLI_mempool *mempool); + +void *BLI_linklist_pop(struct LinkNode **listp); +void *BLI_linklist_pop_pool(struct LinkNode **listp, struct BLI_mempool *mempool); void BLI_linklist_insert_after(struct LinkNode **listp, void *ptr); void BLI_linklist_free(struct LinkNode *list, LinkNodeFreeFP freefunc); void BLI_linklist_freeN(struct LinkNode *list); +void BLI_linklist_free_pool(LinkNode *list, LinkNodeFreeFP freefunc, struct BLI_mempool *mempool); void BLI_linklist_apply(struct LinkNode *list, LinkNodeApplyFP applyfunc, void *userdata); -#endif +#define BLI_linklist_prepend_alloca(listp, ptr) \ + BLI_linklist_prepend_nlink(listp, ptr, alloca(sizeof(LinkNode))) + +#endif /* __BLI_LINKLIST_H__ */ diff --git a/source/blender/blenlib/BLI_linklist_stack.h b/source/blender/blenlib/BLI_linklist_stack.h new file mode 100644 index 00000000000..ca050883018 --- /dev/null +++ b/source/blender/blenlib/BLI_linklist_stack.h @@ -0,0 +1,159 @@ +/* + * ***** 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_LINKLIST_STACK_H__ +#define __BLI_LINKLIST_STACK_H__ + +/** \file BLI_linklist_stack.h + * \ingroup bli + * \brief BLI_LINKSTACK_*** wrapper macros for using a \a LinkNode + * to store a stack of pointers, using a single linked list + * allocated from a mempool. + * + * \note These macros follow STACK_* macros defined in 'BLI_utildefines.h' + * and should be kept (mostly) interchangeable. + * + * \note _##var##_type is a dummy var only used for typechecks. + */ + +/* -------------------------------------------------------------------- */ +/* Linked Stack using BLI_mempool + * + * Uses mempool for storage. + */ + +/** \name Linked Stack (mempool) + * \{ */ + +#define BLI_LINKSTACK_DECLARE(var, type) \ + LinkNode *var; \ + BLI_mempool *_##var##_pool; \ + type _##var##_type + +#define BLI_LINKSTACK_INIT(var) { \ + var = NULL; \ + _##var##_pool = BLI_mempool_create(sizeof(LinkNode), 1, 64, 0); \ +} (void)0 + +#define BLI_LINKSTACK_SIZE(var) \ + 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)) +#define BLI_LINKSTACK_POP(var) \ + (var ? (typeof(_##var##_type))BLI_linklist_pop_pool(&(var), _##var##_pool) : NULL) +#define BLI_LINKSTACK_POP_ELSE(var, 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)) +#define BLI_LINKSTACK_POP(var) \ + (var ? BLI_linklist_pop_pool(&(var), _##var##_pool) : NULL) +#define BLI_LINKSTACK_POP_ELSE(var, 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); \ + SWAP(LinkNode *, var_a, var_b); \ + 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; \ + var = NULL; (void)var; \ + (void)&(_##var##_type); \ +} (void)0 + +#include "BLI_linklist.h" +#include "BLI_mempool.h" + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/* Linked Stack, using stack memory (alloca) + * + * alloca never frees, pop'd items are stored in a free-list for reuse. + * only use for lists small enough to fit on the stack. + */ + + +/** \name Linked Stack (alloca) + * \{ */ + +#ifdef __GNUC__ +# define _BLI_SMALLSTACK_CAST(var) (typeof(_##var##_type)) +#else +# define _BLI_SMALLSTACK_CAST(var) +#endif + +#define BLI_SMALLSTACK_DECLARE(var, type) \ + LinkNode *_##var##_stack = NULL, *_##var##_free = NULL, *_##var##_temp = NULL; \ + type _##var##_type + +#define BLI_SMALLSTACK_PUSH(var, data) \ +{ \ + CHECK_TYPE_PAIR(data, _##var##_type); \ + if (_##var##_free) { \ + _##var##_temp = _##var##_free; \ + _##var##_free = _##var##_free->next; \ + } \ + else { \ + _##var##_temp = alloca(sizeof(LinkNode)); \ + } \ + _##var##_temp->next = _##var##_stack; \ + _##var##_temp->link = data; \ + _##var##_stack = _##var##_temp; \ +} (void)0 + +/* internal use, no null check */ +#define _BLI_SMALLSTACK_DEL(var) \ + (void)((_##var##_temp = _##var##_stack->next), \ + (_##var##_stack->next = _##var##_free), \ + (_##var##_free = _##var##_stack), \ + (_##var##_stack = _##var##_temp)) \ + +/* check for typeof() */ +#define BLI_SMALLSTACK_POP(var) \ + (_BLI_SMALLSTACK_CAST(var) ((_##var##_stack) ? \ + (_BLI_SMALLSTACK_DEL(var), (_##var##_free->link)) : NULL)) + +#define BLI_SMALLSTACK_FREE(var) { \ + (void)&(_##var##_type); \ +} (void)0 + +#include "BLI_alloca.h" + +/** \} */ + +#endif /* __BLI_LINKLIST_STACK_H__ */ + diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index 4c7ddf7ba66..0927620a2c6 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -60,6 +60,8 @@ void BLI_freelistN(struct ListBase *listbase); void BLI_addtail(struct ListBase *listbase, void *vlink); void BLI_remlink(struct ListBase *listbase, void *vlink); bool BLI_remlink_safe(struct ListBase *listbase, void *vlink); +void *BLI_pophead(ListBase *listbase); +void *BLI_poptail(ListBase *listbase); void BLI_addhead(struct ListBase *listbase, void *vlink); void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink); @@ -72,7 +74,8 @@ void BLI_freelinkN(struct ListBase *listbase, void *vlink); void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src); void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src); void BLI_reverselist(struct ListBase *lb); -void BLI_rotatelist(struct ListBase *lb, void *vlink); +void BLI_rotatelist_first(struct ListBase *lb, void *vlink); +void BLI_rotatelist_last(struct ListBase *lb, void *vlink); /* create a generic list node containing link to provided data */ struct LinkData *BLI_genericNodeN(void *data); diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index 69dbd3253f0..1cb28d25b6c 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -222,6 +222,7 @@ MINLINE int power_of_2_max_i(int n); MINLINE int power_of_2_min_i(int n); MINLINE int divide_round_i(int a, int b); +MINLINE int mod_i(int i, int n); MINLINE float shell_angle_to_dist(const float angle); diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 6cb7103be9b..f815716148b 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -34,6 +34,7 @@ extern "C" { #endif +#include "BLI_compiler_attrs.h" #include "BLI_math_inline.h" #if BLI_MATH_DO_INLINE @@ -61,6 +62,14 @@ float area_quad_v3(const float a[3], const float b[3], const float c[3], const f float area_poly_v3(int nr, float verts[][3], const float normal[3]); float area_poly_v2(int nr, float verts[][2]); +/********************************* Planes **********************************/ + +void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3]); +void plane_to_point_normal_v3(const float plane[4], float r_plane_co[3], float r_plane_no[3]); +MINLINE float plane_point_side_v3(const float plane[4], const float co[3]); + +/********************************* Volume **********************************/ + float volume_tetrahedron_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]); int is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]); @@ -73,15 +82,15 @@ float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2]); void closest_to_line_segment_v2(float closest[2], const float p[2], const float l1[2], const float l2[2]); -float dist_to_plane_normalized_v3(const float p[3], const float plane_co[3], const float plane_no_unit[3]); -float dist_to_plane_v3(const float p[3], const float plane_co[3], const float plane_no[3]); +float dist_squared_to_plane_v3(const float p[3], const float plane[4]); +float dist_to_plane_v3(const float p[3], const float plane[4]); float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3]); float dist_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3]); float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]); float closest_to_line_v3(float r[3], const float p[3], const float l1[3], const float l2[3]); float closest_to_line_v2(float r[2], const float p[2], const float l1[2], const float l2[2]); void closest_to_line_segment_v3(float r[3], const float p[3], const float l1[3], const float l2[3]); -void closest_to_plane_v3(float r[3], const float plane_co[3], const float plane_no_unit[3], const float pt[3]); +void closest_to_plane_v3(float close_r[3], const float plane[4], const float pt[3]); /* Set 'r' to the point in triangle (t1, t2, t3) closest to point 'p' */ void closest_on_tri_to_point_v3(float r[3], const float p[3], const float t1[3], const float t2[3], const float t3[3]); @@ -89,6 +98,10 @@ void closest_on_tri_to_point_v3(float r[3], const float p[3], const float t1[3], float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3]); float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2]); + +float line_plane_factor_v3(const float plane_co[3], const float plane_no[3], + const float l1[3], const float l2[3]); + void limit_dist_v3(float v1[3], float v2[3], const float dist); /******************************* Intersection ********************************/ @@ -120,8 +133,9 @@ bool isect_ray_plane_v3(const float p1[3], const float d[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, const int clip); +bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3]); bool isect_line_plane_v3(float out[3], const float l1[3], const float l2[3], - const float plane_co[3], const float plane_no[3], const bool no_flip); + const float plane_co[3], const float plane_no[3]); void isect_plane_plane_v3(float r_isect_co[3], float r_isect_no[3], const float plane_a_co[3], const float plane_a_no[3], @@ -130,6 +144,9 @@ void isect_plane_plane_v3(float r_isect_co[3], float r_isect_no[3], /* line/ray triangle */ bool isect_line_tri_v3(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2]); +bool isect_line_tri_epsilon_v3(const float p1[3], const float p2[3], + const float v0[3], const float v1[3], const float v2[3], + float *r_lambda, float r_uv[2], const float epsilon); bool isect_ray_tri_v3(const float p1[3], const float d[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2]); bool isect_ray_tri_threshold_v3(const float p1[3], const float d[3], @@ -138,8 +155,8 @@ bool isect_ray_tri_epsilon_v3(const float p1[3], const float d[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2], const float epsilon); /* point in polygon */ -bool isect_point_poly_v2(const float pt[2], const float verts[][2], const int nr); -bool isect_point_poly_v2_int(const int pt[2], const int verts[][2], const int nr); +bool isect_point_poly_v2(const float pt[2], const float verts[][2], const unsigned int nr, const bool use_holes); +bool isect_point_poly_v2_int(const int pt[2], const int verts[][2], const unsigned int nr, const bool use_holes); int isect_point_quad_v2(const float p[2], const float a[2], const float b[2], const float c[2], const float d[2]); @@ -171,7 +188,10 @@ bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4]); bool clip_segment_v3_plane_n(float p1[3], float p2[3], float plane_array[][4], const int plane_tot); void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int, void *), void *userData); - +void fill_poly_v2i_n( + const int xmin, const int ymin, const int xmax, const int ymax, + const int polyXY[][2], const int polyCorners, + void (*callback)(int, int, void *), void *userData); /****************************** Interpolation ********************************/ /* tri or quad, d can be NULL */ @@ -277,11 +297,7 @@ float form_factor_hemi_poly(float p[3], float n[3], bool axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3]); void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3]); -float axis_dominant_v3_max(int *r_axis_a, int *r_axis_b, const float axis[3]) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -#endif -; +float axis_dominant_v3_max(int *r_axis_a, int *r_axis_b, const float axis[3]) ATTR_WARN_UNUSED_RESULT; MINLINE int max_axis_v3(const float vec[3]); MINLINE int min_axis_v3(const float vec[3]); diff --git a/source/blender/blenlib/BLI_math_interp.h b/source/blender/blenlib/BLI_math_interp.h index 21975763779..43ef64214ad 100644 --- a/source/blender/blenlib/BLI_math_interp.h +++ b/source/blender/blenlib/BLI_math_interp.h @@ -26,8 +26,12 @@ * */ -#ifndef BLI_MATH_INTERP -#define BLI_MATH_INTERP +#ifndef __BLI_MATH_INTERP_H__ +#define __BLI_MATH_INTERP_H__ + +/** \file BLI_math_interp.h + * \ingroup bli + */ void BLI_bicubic_interpolation_fl(const float *buffer, float *output, int width, int height, int components, float u, float v); @@ -41,4 +45,4 @@ void BLI_bilinear_interpolation_fl(const float *buffer, float *output, int width void BLI_bilinear_interpolation_char(const unsigned char *buffer, unsigned char *output, int width, int height, int components, float u, float v); -#endif +#endif /* __BLI_MATH_INTERP_H__ */ diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index c305cc9a030..b04af44156f 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -94,6 +94,8 @@ void mul_v4_m4v4(float r[4], float M[4][4], const float v[4]); void mul_project_m4_v3(float M[4][4], float vec[3]); void mul_v2_project_m4_v3(float r[2], float M[4][4], const float vec[3]); +void mul_m3_v2(float m[3][3], float r[2]); +void mul_v2_m3v2(float r[2], float m[3][3], float v[2]); void mul_m3_v3(float M[3][3], float r[3]); void mul_v3_m3v3(float r[3], float M[3][3], const float a[3]); void mul_v2_m3v3(float r[2], float M[3][3], const float a[3]); diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h index b3702d10d87..42161279bfd 100644 --- a/source/blender/blenlib/BLI_math_rotation.h +++ b/source/blender/blenlib/BLI_math_rotation.h @@ -66,7 +66,7 @@ float normalize_qt(float q[4]); float normalize_qt_qt(float q1[4], const float q2[4]); /* comparison */ -int is_zero_qt(float q[4]); +bool is_zero_qt(const float q[4]); /* interpolation */ void interp_qt_qtqt(float q[4], const float a[4], const float b[4], const float t); @@ -104,7 +104,8 @@ void quat_to_axis_angle(float axis[3], float *angle, const float q[4]); void mat3_to_axis_angle(float axis[3], float *angle, float M[3][3]); void mat4_to_axis_angle(float axis[3], float *angle, float M[4][4]); -void single_axis_angle_to_mat3(float R[3][3], const char axis, const float angle); +void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle); +void angle_to_mat2(float R[2][2], const float angle); /******************************** XYZ Eulers *********************************/ @@ -163,13 +164,13 @@ typedef struct DualQuat { float scale_weight; } DualQuat; -void copy_dq_dq(DualQuat *r, DualQuat *dq); +void copy_dq_dq(DualQuat *r, const DualQuat *dq); void normalize_dq(DualQuat *dq, float totw); -void add_weighted_dq_dq(DualQuat *r, DualQuat *dq, float weight); +void add_weighted_dq_dq(DualQuat *r, const DualQuat *dq, float weight); void mul_v3m3_dq(float r[3], float R[3][3], DualQuat *dq); void mat4_to_dquat(DualQuat *r, float base[4][4], float M[4][4]); -void dquat_to_mat4(float R[4][4], DualQuat *dq); +void dquat_to_mat4(float R[4][4], const DualQuat *dq); void quat_apply_track(float quat[4], short axis, short upflag); void vec_apply_track(float vec[3], short axis); diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index e163c06440c..675ba88fc72 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -34,6 +34,7 @@ extern "C" { #endif +#include "BLI_compiler_attrs.h" #include "BLI_math_inline.h" /************************************* Init ***********************************/ @@ -43,11 +44,6 @@ extern "C" { # pragma GCC diagnostic ignored "-Wredundant-decls" #endif -#ifdef __GNUC__ -# define UNUSED_RESULT_ATTR __attribute__((warn_unused_result)) -#else -# define UNUSED_RESULT_ATTR -#endif MINLINE void zero_v2(float r[2]); MINLINE void zero_v3(float r[3]); @@ -117,10 +113,10 @@ MINLINE void mul_v3_v3(float r[3], const float a[3]); MINLINE void mul_v3_v3v3(float r[3], const float a[3], const float b[3]); MINLINE void mul_v4_fl(float r[4], float f); MINLINE void mul_v4_v4fl(float r[3], const float a[3], float f); -MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3]) UNUSED_RESULT_ATTR; -MINLINE float dot_m3_v3_row_x(float M[3][3], const float a[3]) UNUSED_RESULT_ATTR; -MINLINE float dot_m3_v3_row_y(float M[3][3], const float a[3]) UNUSED_RESULT_ATTR; -MINLINE float dot_m3_v3_row_z(float M[3][3], const float a[3]) UNUSED_RESULT_ATTR; +MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float dot_m3_v3_row_x(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float dot_m3_v3_row_y(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float dot_m3_v3_row_z(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f); MINLINE void madd_v3_v3v3(float r[3], const float a[3], const float b[3]); @@ -139,10 +135,10 @@ MINLINE void negate_v4_v4(float r[4], const float a[3]); MINLINE void negate_v3_short(short r[3]); -MINLINE float dot_v2v2(const float a[2], const float b[2]) UNUSED_RESULT_ATTR; -MINLINE float dot_v3v3(const float a[3], const float b[3]) UNUSED_RESULT_ATTR; +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 cross_v2v2(const float a[2], const float b[2]) UNUSED_RESULT_ATTR; +MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]); MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3]); @@ -151,20 +147,20 @@ MINLINE void star_m3_v3(float rmat[3][3], float a[3]); /*********************************** Length **********************************/ -MINLINE float len_squared_v2(const float v[2]) UNUSED_RESULT_ATTR; -MINLINE float len_squared_v3(const float v[3]) UNUSED_RESULT_ATTR; -MINLINE float len_manhattan_v2(const float v[2]) UNUSED_RESULT_ATTR; -MINLINE int len_manhattan_v2_int(const int v[2]) UNUSED_RESULT_ATTR; -MINLINE float len_manhattan_v3(const float v[3]) UNUSED_RESULT_ATTR; -MINLINE float len_v2(const float a[2]) UNUSED_RESULT_ATTR; -MINLINE float len_v2v2(const float a[2], const float b[2]) UNUSED_RESULT_ATTR; -MINLINE float len_squared_v2v2(const float a[2], const float b[2]) UNUSED_RESULT_ATTR; -MINLINE float len_squared_v3v3(const float a[3], const float b[3]) UNUSED_RESULT_ATTR; -MINLINE float len_manhattan_v2v2(const float a[2], const float b[2]) UNUSED_RESULT_ATTR; -MINLINE int len_manhattan_v2v2_int(const int a[2], const int b[2]) UNUSED_RESULT_ATTR; -MINLINE float len_manhattan_v3v3(const float a[3], const float b[3]) UNUSED_RESULT_ATTR; -MINLINE float len_v3(const float a[3]) UNUSED_RESULT_ATTR; -MINLINE float len_v3v3(const float a[3], const float b[3]) UNUSED_RESULT_ATTR; +MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float len_manhattan_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE int len_manhattan_v2_int(const int v[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE float len_manhattan_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float len_manhattan_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE int len_manhattan_v2v2_int(const int a[2], const int b[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE float len_manhattan_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float normalize_v2(float r[2]); MINLINE float normalize_v2_v2(float r[2], const float a[2]); @@ -196,35 +192,41 @@ void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2]); /********************************* Comparison ********************************/ -MINLINE int is_zero_v3(const float a[3]) UNUSED_RESULT_ATTR; -MINLINE int is_zero_v4(const float a[4]) UNUSED_RESULT_ATTR; -MINLINE int is_one_v3(const float a[3]) UNUSED_RESULT_ATTR; +MINLINE bool is_zero_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool is_zero_v4(const float a[4]) ATTR_WARN_UNUSED_RESULT; + +MINLINE bool is_finite_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool is_finite_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool is_finite_v4(const float a[4]) ATTR_WARN_UNUSED_RESULT; + +MINLINE bool is_one_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT; -MINLINE int equals_v2v2(const float v1[2], const float v2[2]) UNUSED_RESULT_ATTR; -MINLINE int equals_v3v3(const float a[3], const float b[3]) UNUSED_RESULT_ATTR; -MINLINE int compare_v2v2(const float a[2], const float b[2], const float limit) UNUSED_RESULT_ATTR; -MINLINE int compare_v3v3(const float a[3], const float b[3], const float limit) UNUSED_RESULT_ATTR; -MINLINE int compare_len_v3v3(const float a[3], const float b[3], const float limit) UNUSED_RESULT_ATTR; +MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE bool compare_v2v2(const float a[2], const float b[2], const float limit) ATTR_WARN_UNUSED_RESULT; +MINLINE bool compare_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT; +MINLINE bool compare_len_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT; -MINLINE int compare_v4v4(const float a[4], const float b[4], const float limit) UNUSED_RESULT_ATTR; -MINLINE int equals_v4v4(const float a[4], const float b[4]) UNUSED_RESULT_ATTR; +MINLINE bool compare_v4v4(const float a[4], const float b[4], const float limit) ATTR_WARN_UNUSED_RESULT; +MINLINE bool equals_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT; -MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2]) UNUSED_RESULT_ATTR; +MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2]) ATTR_WARN_UNUSED_RESULT; /********************************** Angles ***********************************/ /* - angle with 2 arguments is angle between vector */ /* - angle with 3 arguments is angle between 3 points at the middle point */ /* - angle_normalized_* is faster equivalent if vectors are normalized */ -float angle_v2v2(const float a[2], const float b[2]) UNUSED_RESULT_ATTR; -float angle_signed_v2v2(const float v1[2], const float v2[2]) UNUSED_RESULT_ATTR; -float angle_v2v2v2(const float a[2], const float b[2], const float c[2]) UNUSED_RESULT_ATTR; -float angle_normalized_v2v2(const float a[2], const float b[2]) UNUSED_RESULT_ATTR; -float angle_v3v3(const float a[3], const float b[3]) UNUSED_RESULT_ATTR; -float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) UNUSED_RESULT_ATTR; -float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) UNUSED_RESULT_ATTR; -float angle_normalized_v3v3(const float v1[3], const float v2[3]) UNUSED_RESULT_ATTR; -float angle_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) UNUSED_RESULT_ATTR; +float angle_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; +float angle_signed_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT; +float angle_v2v2v2(const float a[2], const float b[2], const float c[2]) ATTR_WARN_UNUSED_RESULT; +float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; +float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT; +float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT; +float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) ATTR_WARN_UNUSED_RESULT; +float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT; +float angle_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT; void angle_tri_v3(float angles[3], const float v1[3], const float v2[3], const float v3[3]); void angle_quad_v3(float angles[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3]); void angle_poly_v3(float *angles, const float *verts[3], int len); @@ -260,7 +262,7 @@ void axis_sort_v3(const float axis_values[3], int r_axis_order[3]); /***************************** Array Functions *******************************/ /* attempted to follow fixed length vertex functions. names could be improved*/ -double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size) UNUSED_RESULT_ATTR; +double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size) ATTR_WARN_UNUSED_RESULT; float normalize_vn_vn(float *array_tar, const float *array_src, const int size); float normalize_vn(float *array_tar, const int size); void range_vn_i(int *array_tar, const int size, const int start); @@ -291,7 +293,6 @@ void fill_vn_fl(float *array_tar, const int size, const float val); #ifdef BLI_MATH_GCC_WARN_PRAGMA # pragma GCC diagnostic pop #endif -#undef UNUSED_RESULT_ATTR #ifdef __cplusplus } diff --git a/source/blender/blenlib/BLI_memarena.h b/source/blender/blenlib/BLI_memarena.h index d54dab42e05..9ff4883c89c 100644 --- a/source/blender/blenlib/BLI_memarena.h +++ b/source/blender/blenlib/BLI_memarena.h @@ -41,62 +41,28 @@ extern "C" { #endif +#include "BLI_compiler_attrs.h" + /* A reasonable standard buffer size, big * enough to not cause much internal fragmentation, * small enough not to waste resources */ #define BLI_MEMARENA_STD_BUFSIZE (1 << 14) -/* some GNU attributes are only available from GCC 4.3 */ -#define MEM_GNU_ATTRIBUTES (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 403)) - struct MemArena; typedef struct MemArena MemArena; -struct MemArena *BLI_memarena_new(const int bufsize, const char *name) -#if MEM_GNU_ATTRIBUTES -__attribute__((malloc)) -__attribute__((warn_unused_result)) -__attribute__((nonnull(2))) -#endif -; - -void BLI_memarena_free(struct MemArena *ma) -#if MEM_GNU_ATTRIBUTES -__attribute__((nonnull(1))) -#endif -; - -void BLI_memarena_use_malloc(struct MemArena *ma) -#if MEM_GNU_ATTRIBUTES -__attribute__((nonnull(1))) -#endif -; -void BLI_memarena_use_calloc(struct MemArena *ma) -#if MEM_GNU_ATTRIBUTES -__attribute__((nonnull(1))) -#endif -; - -void BLI_memarena_use_align(struct MemArena *ma, const int align) -#if MEM_GNU_ATTRIBUTES -__attribute__((nonnull(1))) -#endif -; +struct MemArena *BLI_memarena_new(const int bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2) ATTR_MALLOC; +void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1); +void BLI_memarena_use_malloc(struct MemArena *ma) ATTR_NONNULL(1); +void BLI_memarena_use_calloc(struct MemArena *ma) ATTR_NONNULL(1); +void BLI_memarena_use_align(struct MemArena *ma, const int align) ATTR_NONNULL(1); +void *BLI_memarena_alloc(struct MemArena *ma, int size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2); -void *BLI_memarena_alloc(struct MemArena *ma, int size) -#if MEM_GNU_ATTRIBUTES -__attribute__((malloc)) -__attribute__((warn_unused_result)) -__attribute__((nonnull(1))) -__attribute__((alloc_size(2))) -#endif -; +void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1); #ifdef __cplusplus } #endif - -#endif - +#endif /* __BLI_MEMARENA_H__ */ diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h index 1c470d59062..3fab77f2cb2 100644 --- a/source/blender/blenlib/BLI_mempool.h +++ b/source/blender/blenlib/BLI_mempool.h @@ -39,6 +39,8 @@ extern "C" { #endif +#include "BLI_compiler_attrs.h" + struct BLI_mempool; struct BLI_mempool_chunk; @@ -48,81 +50,33 @@ typedef struct BLI_mempool BLI_mempool; * first four bytes of the elements never contain the character string * 'free'. use with care.*/ -BLI_mempool *BLI_mempool_create(int esize, int totelem, int pchunk, int flag) -#ifdef __GNUC__ -__attribute__((malloc)) -__attribute__((warn_unused_result)) -#endif -; -void *BLI_mempool_alloc(BLI_mempool *pool) -#ifdef __GNUC__ -__attribute__((malloc)) -__attribute__((warn_unused_result)) -__attribute__((nonnull(1))) -#endif -; -void *BLI_mempool_calloc(BLI_mempool *pool) -#ifdef __GNUC__ -__attribute__((malloc)) -__attribute__((warn_unused_result)) -__attribute__((nonnull(1))) -#endif -; -void BLI_mempool_free(BLI_mempool *pool, void *addr) -#ifdef __GNUC__ -__attribute__((nonnull(1, 2))) -#endif -; -void BLI_mempool_destroy(BLI_mempool *pool) -#ifdef __GNUC__ -__attribute__((nonnull(1))) -#endif -; -int BLI_mempool_count(BLI_mempool *pool) -#ifdef __GNUC__ -__attribute__((nonnull(1))) -#endif -; -void *BLI_mempool_findelem(BLI_mempool *pool, int index) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull(1))) -#endif -; -void BLI_mempool_as_table(BLI_mempool *pool, void **data) -#ifdef __GNUC__ -__attribute__((nonnull(1, 2))) -#endif -; - -void **BLI_mempool_as_tableN(BLI_mempool *pool, const char *allocstr) -#ifdef __GNUC__ -__attribute__((malloc)) -__attribute__((warn_unused_result)) -__attribute__((nonnull(1, 2))) -#endif -; +BLI_mempool *BLI_mempool_create(unsigned int esize, unsigned int totelem, + unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +void *BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +void *BLI_mempool_calloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1, 2); +void BLI_mempool_clear_ex(BLI_mempool *pool, + const int totelem_reserve) ATTR_NONNULL(1); +void BLI_mempool_clear(BLI_mempool *pool) ATTR_NONNULL(1); +void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1); +int BLI_mempool_count(BLI_mempool *pool) ATTR_NONNULL(1); +void *BLI_mempool_findelem(BLI_mempool *pool, unsigned int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); -void BLI_mempool_as_array(BLI_mempool *pool, void *data) -#ifdef __GNUC__ -__attribute__((nonnull(1, 2))) -#endif -; +void BLI_mempool_as_table(BLI_mempool *pool, void **data) ATTR_NONNULL(1, 2); +void **BLI_mempool_as_tableN(BLI_mempool *pool, const char *allocstr) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); +void BLI_mempool_as_array(BLI_mempool *pool, void *data) ATTR_NONNULL(1, 2); +void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); -void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr) -#ifdef __GNUC__ -__attribute__((malloc)) -__attribute__((warn_unused_result)) -__attribute__((nonnull(1, 2))) +#ifdef DEBUG +void BLI_mempool_set_memory_debug(void); #endif -; /** iteration stuff. note: this may easy to produce bugs with **/ /* private structure */ typedef struct BLI_mempool_iter { BLI_mempool *pool; struct BLI_mempool_chunk *curchunk; - int curindex; + unsigned int curindex; } BLI_mempool_iter; /* flag */ @@ -131,17 +85,8 @@ enum { BLI_MEMPOOL_ALLOW_ITER = (1 << 1) }; -void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) -#ifdef __GNUC__ -__attribute__((nonnull(1, 2))) -#endif -; -void *BLI_mempool_iterstep(BLI_mempool_iter *iter) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull(1))) -#endif -; +void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL(); +void *BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); #ifdef __cplusplus } diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index cb812fe8595..d4c5d5fed9f 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -35,6 +35,8 @@ extern "C" { #endif +#include "BLI_compiler_attrs.h" + struct ListBase; struct direntry; @@ -90,17 +92,9 @@ void BLI_split_dirfile(const char *string, char *dir, char *file, const size_t d void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen); void BLI_split_file_part(const char *string, char *file, const size_t filelen); void BLI_path_append(char *__restrict dst, const size_t maxlen, - const char *__restrict file) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; + const char *__restrict file) ATTR_NONNULL(); void BLI_join_dirfile(char *__restrict string, const size_t maxlen, - const char *__restrict dir, const char *__restrict file) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; + const char *__restrict dir, const char *__restrict file) ATTR_NONNULL(); const char *BLI_path_basename(const char *path); typedef enum bli_rebase_state { @@ -122,6 +116,7 @@ bool BLI_testextensie_array(const char *str, const char **ext_array); bool BLI_testextensie_glob(const char *str, const char *ext_fnmatch); bool BLI_replace_extension(char *path, size_t maxlen, const char *ext); bool BLI_ensure_extension(char *path, size_t maxlen, const char *ext); +bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename); void BLI_uniquename(struct ListBase *list, void *vlink, const char *defname, char delim, short name_offs, short len); bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name), void *arg, const char * defname, char delim, char *name, short name_len); @@ -131,11 +126,7 @@ void BLI_stringenc(char *string, const char *head, const char *tail, unsigned sh int BLI_split_name_num(char *left, int *nr, const char *name, const char delim); /* make sure path separators conform to system one */ -void BLI_clean(char *path) -#ifdef __GNUC__ -__attribute__((nonnull(1))) -#endif -; +void BLI_clean(char *path) ATTR_NONNULL(); /** * dir can be any input, like from buttons, and this function @@ -181,11 +172,7 @@ bool BLI_path_is_rel(const char *path); # define BLI_path_ncmp strncmp #endif -void BLI_char_switch(char *string, char from, char to) -#ifdef __GNUC__ -__attribute__((nonnull(1))) -#endif -; +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); diff --git a/source/blender/blenlib/BLI_scanfill.h b/source/blender/blenlib/BLI_scanfill.h index 21197670640..e7d2130e473 100644 --- a/source/blender/blenlib/BLI_scanfill.h +++ b/source/blender/blenlib/BLI_scanfill.h @@ -46,20 +46,13 @@ typedef struct ScanFillContext { ListBase filledgebase; ListBase fillfacebase; - /* simple optimization for allocating thousands of small memory blocks - * only to be used within loops, and not by one function at a time - * free in the end, with argument '-1' - */ -#define MEM_ELEM_BLOCKSIZE 16384 - struct mem_elements *melem__cur; - int melem__offs; /* the current free address */ - ListBase melem__lb; - /* private */ struct ScanFillVertLink *_scdata; + struct MemArena *arena; } ScanFillContext; -/* note; changing this also might affect the undo copy in editmesh.c */ +#define BLI_SCANFILL_ARENA_SIZE 16384 + typedef struct ScanFillVert { struct ScanFillVert *next, *prev; union { @@ -68,10 +61,10 @@ typedef struct ScanFillVert { intptr_t l; unsigned int u; } tmp; - float co[3]; /* vertex location */ - float xy[2]; /* 2D copy of vertex location (using dominant axis) */ - unsigned int keyindex; /* original index #, for restoring key information */ - short poly_nr; + float co[3]; /* vertex location */ + float xy[2]; /* 2D projection of vertex location */ + unsigned int keyindex; /* index, caller can use how it likes to match the scanfill result with own data */ + unsigned short poly_nr; unsigned char edge_tot; /* number of edges using this vertex */ unsigned char f; } ScanFillVert; @@ -79,7 +72,7 @@ typedef struct ScanFillVert { typedef struct ScanFillEdge { struct ScanFillEdge *next, *prev; struct ScanFillVert *v1, *v2; - short poly_nr; + unsigned short poly_nr; unsigned char f; union { unsigned char c; @@ -91,7 +84,7 @@ typedef struct ScanFillFace { struct ScanFillVert *v1, *v2, *v3; } ScanFillFace; -/* scanfill.c: used in displist only... */ +/* scanfill.c */ struct ScanFillVert *BLI_scanfill_vert_add(ScanFillContext *sf_ctx, const float vec[3]); struct ScanFillEdge *BLI_scanfill_edge_add(ScanFillContext *sf_ctx, struct ScanFillVert *v1, struct ScanFillVert *v2); @@ -108,11 +101,14 @@ enum { BLI_SCANFILL_CALC_HOLES = (1 << 2) }; void BLI_scanfill_begin(ScanFillContext *sf_ctx); -int BLI_scanfill_calc(ScanFillContext *sf_ctx, const int flag); -int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, +unsigned int BLI_scanfill_calc(ScanFillContext *sf_ctx, const int flag); +unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float nor_proj[3]); void BLI_scanfill_end(ScanFillContext *sf_ctx); +void BLI_scanfill_begin_arena(ScanFillContext *sf_ctx, struct MemArena *arena); +void BLI_scanfill_end_arena(ScanFillContext *sf_ctx, struct MemArena *arena); + /* These callbacks are needed to make the lib finction properly */ void BLI_setErrorCallBack(void (*f)(const char *)); diff --git a/source/blender/blenlib/BLI_smallhash.h b/source/blender/blenlib/BLI_smallhash.h index 275599a612c..4f5446043da 100644 --- a/source/blender/blenlib/BLI_smallhash.h +++ b/source/blender/blenlib/BLI_smallhash.h @@ -37,6 +37,8 @@ /* based on a doubling non-chaining approach */ +#include "BLI_compiler_attrs.h" + typedef struct { uintptr_t key; void *val; @@ -59,27 +61,15 @@ typedef struct { unsigned int i; } SmallHashIter; -#ifdef __GNUC__ -# define ATTR_NONULL_FIRST __attribute__((nonnull(1))) -# define ATTR_UNUSED_RESULT __attribute__((warn_unused_result)) -#else -# define ATTR_NONULL_FIRST -# define ATTR_UNUSED_RESULT -#endif - - -void BLI_smallhash_init(SmallHash *hash) ATTR_NONULL_FIRST; -void BLI_smallhash_release(SmallHash *hash) ATTR_NONULL_FIRST; -void BLI_smallhash_insert(SmallHash *hash, uintptr_t key, void *item) ATTR_NONULL_FIRST; -void BLI_smallhash_remove(SmallHash *hash, uintptr_t key) ATTR_NONULL_FIRST; -void *BLI_smallhash_lookup(SmallHash *hash, uintptr_t key) ATTR_NONULL_FIRST ATTR_UNUSED_RESULT; -int BLI_smallhash_haskey(SmallHash *hash, uintptr_t key) ATTR_NONULL_FIRST; -int BLI_smallhash_count(SmallHash *hash) ATTR_NONULL_FIRST; -void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key) ATTR_NONULL_FIRST ATTR_UNUSED_RESULT; -void *BLI_smallhash_iternew(SmallHash *hash, SmallHashIter *iter, uintptr_t *key) ATTR_NONULL_FIRST ATTR_UNUSED_RESULT; +void BLI_smallhash_init(SmallHash *hash) ATTR_NONNULL(1); +void BLI_smallhash_release(SmallHash *hash) ATTR_NONNULL(1); +void BLI_smallhash_insert(SmallHash *hash, uintptr_t key, void *item) ATTR_NONNULL(1); +void BLI_smallhash_remove(SmallHash *hash, uintptr_t key) ATTR_NONNULL(1); +void *BLI_smallhash_lookup(SmallHash *hash, uintptr_t key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; +int BLI_smallhash_haskey(SmallHash *hash, uintptr_t key) ATTR_NONNULL(1); +int BLI_smallhash_count(SmallHash *hash) ATTR_NONNULL(1); +void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; +void *BLI_smallhash_iternew(SmallHash *hash, SmallHashIter *iter, uintptr_t *key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; /* void BLI_smallhash_print(SmallHash *hash); */ /* UNUSED */ -#undef ATTR_NONULL_FIRST -#undef ATTR_UNUSED_RESULT - #endif /* __BLI_SMALLHASH_H__ */ diff --git a/source/blender/compositor/operations/COM_MixColorOperation.h b/source/blender/blenlib/BLI_sort.h index 1409d726f03..4df17d98a4b 100644 --- a/source/blender/compositor/operations/COM_MixColorOperation.h +++ b/source/blender/blenlib/BLI_sort.h @@ -1,5 +1,5 @@ /* - * Copyright 2011, Blender Foundation. + * ***** 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 @@ -15,31 +15,31 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Benoit Bolsee, + * Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** */ -#ifndef _COM_MixColorOperation_h -#define _COM_MixColorOperation_h -#include "COM_MixBaseOperation.h" +#ifndef __BLI_SORT_H__ +#define __BLI_SORT_H__ - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. +/** \file BLI_sort.h + * \ingroup bli */ -class MixColorOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixColorOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); -}; +/* Quick sort reentrant */ +typedef int (*BLI_sort_cmp_t)(void *ctx, const void *a, const void *b); + +void BLI_qsort_r(void *a, size_t n, size_t es, void *thunk, BLI_sort_cmp_t cmp) +#ifdef __GNUC__ +__attribute__((nonnull(1, 5))) #endif +; + +#endif /* __BLI_SORT_H__ */ diff --git a/source/blender/blenlib/BLI_sort_utils.h b/source/blender/blenlib/BLI_sort_utils.h new file mode 100644 index 00000000000..e08f4e5ac83 --- /dev/null +++ b/source/blender/blenlib/BLI_sort_utils.h @@ -0,0 +1,61 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_SORT_UTILS_H__ +#define __BLI_SORT_UTILS_H__ + +/** \file BLI_sort_utils.h + * \ingroup bli + */ + +/** + * \note keep \a sort_value first, + * so cmp functions can be reused. + */ +struct SortPointerByFloat { + float sort_value; + void *data; +}; + +struct SortIntByFloat { + float sort_value; + int data; +}; + +struct SortPointerByInt { + int sort_value; + void *data; +}; + +struct SortIntByInt { + int sort_value; + int data; +}; + +int BLI_sortutil_cmp_float(const void *a_, const void *b_); +int BLI_sortutil_cmp_float_reverse(const void *a_, const void *b_); + +int BLI_sortutil_cmp_int(const void *a_, const void *b_); +int BLI_sortutil_cmp_int_reverse(const void *a_, const void *b_); + +#endif /* __BLI_SORT_UTILS_H__ */ diff --git a/source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.h b/source/blender/blenlib/BLI_strict_flags.h index 9d3ab156555..5c5a6f45f0c 100644 --- a/source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.h +++ b/source/blender/blenlib/BLI_strict_flags.h @@ -1,5 +1,5 @@ /* - * Copyright 2012, Blender Foundation. + * ***** 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 @@ -15,34 +15,27 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Dalai Felinto + * ***** END GPL LICENSE BLOCK ***** */ -#ifndef _COM_ConvertPremulToStraightOperation_h -#define _COM_ConvertPremulToStraightOperation_h -#include "COM_NodeOperation.h" +#ifndef __BLI_STRICT_FLAGS_H__ +#define __BLI_STRICT_FLAGS_H__ - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. +/** \file BLI_strict_flags.h + * \ingroup bli + * \brief Strict compiler flags for areas of code we want + * to ensure don't do conversions without us knowing about it. */ -class ConvertPremulToStraightOperation : public NodeOperation { -private: - SocketReader *m_inputColor; -public: - /** - * Default constructor - */ - ConvertPremulToStraightOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - void initExecution(); - void deinitExecution(); -}; +#ifdef __GNUC__ +# pragma GCC diagnostic error "-Wsign-conversion" +# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 /* gcc4.6+ only */ +# pragma GCC diagnostic error "-Wsign-compare" +# pragma GCC diagnostic error "-Wconversion" +# endif +# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 /* gcc4.8+ only (behavior changed to ignore globals)*/ +# pragma GCC diagnostic error "-Wshadow" +# endif #endif + +#endif /* __BLI_STRICT_FLAGS_H__ */ diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index 6c66d2f4e18..b995f2565e1 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -38,152 +38,43 @@ extern "C" { #endif -char *BLI_strdupn(const char *str, const size_t len) -#ifdef __GNUC__ -__attribute__((malloc)) -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +#include "BLI_compiler_attrs.h" -char *BLI_strdup(const char *str) -#ifdef __GNUC__ -__attribute__((malloc)) -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +char *BLI_strdupn(const char *str, const size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -char *BLI_strdupcat(const char *__restrict str1, const char *__restrict str2) -#ifdef __GNUC__ -__attribute__((malloc)) -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +char *BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC; -char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; +char *BLI_strdupcat(const char *__restrict str1, const char *__restrict str2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC; -size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, const size_t maxncpy) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL(); -size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict prefix) -#ifdef __GNUC__ -__attribute__((malloc)) -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -char *BLI_replacestrN(const char *__restrict str, const char *__restrict substr_old, const char *__restrict substr_new) -#ifdef __GNUC__ -__attribute__((malloc)) -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict prefix) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC; -size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 3, 4))) -__attribute__((nonnull)) -#endif -; +char *BLI_replacestrN(const char *__restrict str, const char *__restrict substr_old, const char *__restrict substr_new) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC; -size_t BLI_vsnprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, va_list arg) -#ifdef __GNUC__ -__attribute__ ((format(printf, 3, 0))) -#endif -; - -char *BLI_sprintfN(const char *__restrict format, ...) -#ifdef __GNUC__ -__attribute__((malloc)) -__attribute__ ((format(printf, 1, 2))) -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...) ATTR_NONNULL() ATTR_PRINTF_FORMAT(3, 4); -size_t BLI_strescape(char *__restrict dst, const char *__restrict src, const size_t maxncpy) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; +size_t BLI_vsnprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, va_list arg) ATTR_PRINTF_FORMAT(3, 0); -int BLI_strcaseeq(const char *a, const char *b) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; +char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC ATTR_PRINTF_FORMAT(1, 2); -char *BLI_strcasestr(const char *s, const char *find) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; -int BLI_strcasecmp(const char *s1, const char *s2) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; -int BLI_strncasecmp(const char *s1, const char *s2, size_t len) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; -int BLI_natstrcmp(const char *s1, const char *s2) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; -size_t BLI_strnlen(const char *str, const size_t maxlen) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -__attribute__((nonnull)) -#endif -; -void BLI_timestr(double _time, char *str, size_t maxlen) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; +size_t BLI_strescape(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL(); -void BLI_ascii_strtolower(char *str, const size_t len) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; -void BLI_ascii_strtoupper(char *str, const size_t len) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; -int BLI_str_rstrip_float_zero(char *str, const char pad) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; +int BLI_strcaseeq(const char *a, const char *b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +char *BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +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(); +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(); + +void BLI_ascii_strtolower(char *str, const size_t len) ATTR_NONNULL(); +void BLI_ascii_strtoupper(char *str, const size_t len) ATTR_NONNULL(); +int BLI_str_rstrip_float_zero(char *str, const char pad) ATTR_NONNULL(); #ifdef __cplusplus } diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h index db32190494a..4aef2318683 100644 --- a/source/blender/blenlib/BLI_string_utf8.h +++ b/source/blender/blenlib/BLI_string_utf8.h @@ -31,57 +31,45 @@ extern "C" { #endif -#ifdef __GNUC__ -# define ATTR_NONULL __attribute__((nonnull)) -# define ATTR_NONULL_FIRST __attribute__((nonnull(1))) -# define ATTR_UNUSED_RESULT __attribute__((warn_unused_result)) -#else -# define ATTR_NONULL -# define ATTR_NONULL_FIRST -# define ATTR_UNUSED_RESULT -#endif +#include "BLI_compiler_attrs.h" -char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONULL; -char *BLI_strncat_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONULL; -int BLI_utf8_invalid_byte(const char *str, int length) ATTR_NONULL; -int BLI_utf8_invalid_strip(char *str, int length) ATTR_NONULL; +char *BLI_strncpy_utf8(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(); -int BLI_str_utf8_size(const char *p) ATTR_NONULL; /* warning, can return -1 on bad chars */ -int BLI_str_utf8_size_safe(const char *p) ATTR_NONULL; +int BLI_str_utf8_size(const char *p) ATTR_NONNULL(); /* warning, can return -1 on bad chars */ +int BLI_str_utf8_size_safe(const char *p) ATTR_NONNULL(); /* copied from glib */ -unsigned int BLI_str_utf8_as_unicode(const char *p) ATTR_NONULL; -unsigned int BLI_str_utf8_as_unicode_and_size(const char *__restrict p, size_t *__restrict index) ATTR_NONULL; -unsigned int BLI_str_utf8_as_unicode_and_size_safe(const char *__restrict p, size_t *__restrict index) ATTR_NONULL; -unsigned int BLI_str_utf8_as_unicode_step(const char *__restrict p, size_t *__restrict index) ATTR_NONULL; +unsigned int BLI_str_utf8_as_unicode(const char *p) ATTR_NONNULL(); +unsigned int BLI_str_utf8_as_unicode_and_size(const char *__restrict p, size_t *__restrict index) ATTR_NONNULL(); +unsigned int BLI_str_utf8_as_unicode_and_size_safe(const char *__restrict p, size_t *__restrict index) ATTR_NONNULL(); +unsigned int BLI_str_utf8_as_unicode_step(const char *__restrict p, size_t *__restrict index) ATTR_NONNULL(); size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf); -char *BLI_str_find_prev_char_utf8(const char *str, const char *p) ATTR_NONULL; -char *BLI_str_find_next_char_utf8(const char *p, const char *end) ATTR_NONULL_FIRST; -char *BLI_str_prev_char_utf8(const char *p) ATTR_NONULL; +char *BLI_str_find_prev_char_utf8(const char *str, const char *p) ATTR_NONNULL(); +char *BLI_str_find_next_char_utf8(const char *p, const char *end) ATTR_NONNULL(1); +char *BLI_str_prev_char_utf8(const char *p) ATTR_NONNULL(); /* wchar_t functions, copied from blenders own font.c originally */ -size_t BLI_wstrlen_utf8(const wchar_t *src) ATTR_NONULL; -size_t BLI_strlen_utf8_ex(const char *strc, size_t *r_len_bytes) ATTR_NONULL; -size_t BLI_strlen_utf8(const char *strc) ATTR_NONULL; -size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, size_t *r_len_bytes) ATTR_NONULL; -size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen) ATTR_NONULL; -size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst, const wchar_t *__restrict src, const size_t maxcpy) ATTR_NONULL; -size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst, const char *__restrict src, const size_t maxcpy) ATTR_NONULL; +size_t BLI_wstrlen_utf8(const wchar_t *src) ATTR_NONNULL(); +size_t BLI_strlen_utf8_ex(const char *strc, size_t *r_len_bytes) ATTR_NONNULL(); +size_t BLI_strlen_utf8(const char *strc) ATTR_NONNULL(); +size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, size_t *r_len_bytes) ATTR_NONNULL(); +size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen) ATTR_NONNULL(); +size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst, const wchar_t *__restrict src, const size_t maxcpy) ATTR_NONNULL(); +size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst, const char *__restrict src, const size_t maxcpy) ATTR_NONNULL(); /* count columns that character/string occupies, based on wcwidth.c */ int BLI_wcwidth(wchar_t ucs); -int BLI_wcswidth(const wchar_t *pwcs, size_t n) ATTR_NONULL; -int BLI_str_utf8_char_width(const char *p) ATTR_NONULL; /* warning, can return -1 on bad chars */ -int BLI_str_utf8_char_width_safe(const char *p) ATTR_NONULL; +int BLI_wcswidth(const wchar_t *pwcs, size_t n) ATTR_NONNULL(); +int BLI_str_utf8_char_width(const char *p) ATTR_NONNULL(); /* warning, can return -1 on bad chars */ +int BLI_str_utf8_char_width_safe(const char *p) ATTR_NONNULL(); #define BLI_UTF8_MAX 6 /* mem */ #define BLI_UTF8_WIDTH_MAX 2 /* columns */ #define BLI_UTF8_ERR ((unsigned int)-1) -#undef ATTR_NONULL -#undef ATTR_NONULL_FIRST -#undef ATTR_UNUSED_RESULT - #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h index 154986936a2..38ad0827246 100644 --- a/source/blender/blenlib/BLI_threads.h +++ b/source/blender/blenlib/BLI_threads.h @@ -50,6 +50,7 @@ struct ListBase; /*this is run once at startup*/ void BLI_threadapi_init(void); +void BLI_threadapi_exit(void); void BLI_init_threads(struct ListBase *threadbase, void *(*do_thread)(void *), int tot); int BLI_available_threads(struct ListBase *threadbase); diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index 63235ad9c82..c3a3c035ed3 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -113,7 +113,7 @@ /* can be used in simple macros */ #define CHECK_TYPE_INLINE(val, type) \ - ((void)(((type *)0) != (val))) + ((void)(((type)0) != (val))) #define SWAP(type, a, b) { \ type sw_ap; \ @@ -337,12 +337,6 @@ # define UNUSED_FUNCTION(x) UNUSED_ ## x #endif -#ifdef __GNUC__ -# define WARN_UNUSED __attribute__((warn_unused_result)) -#else -# define WARN_UNUSED -#endif - /*little macro so inline keyword works*/ #if defined(_MSC_VER) # define BLI_INLINE static __forceinline diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h index 20a4c3c274e..e75ec7eef2c 100644 --- a/source/blender/blenlib/BLI_winstuff.h +++ b/source/blender/blenlib/BLI_winstuff.h @@ -100,7 +100,6 @@ extern "C" { // not accepted by access() on windows //# define X_OK 1 # define F_OK 0 -# define PATH_MAX 4096 #endif #ifndef FREE_WINDOWS diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index b6b69116e67..65ba545ef13 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -25,7 +25,7 @@ # XXX allowing blenkernel and RNA includes in blenlib is a hack, # but needed in a few places atm (bpath.c for instance) -set(INC +set(INC . # ../blenkernel # dont add this back! ../makesdna @@ -54,6 +54,7 @@ set(SRC intern/boxpack2d.c intern/buffer.c intern/callbacks.c + intern/convexhull2d.c intern/cpu.c intern/dynlib.c intern/edgehash.c @@ -86,6 +87,8 @@ set(SRC intern/rct.c intern/scanfill.c intern/smallhash.c + intern/sort.c + intern/sort_utils.c intern/stack.c intern/storage.c intern/string.c @@ -98,14 +101,16 @@ set(SRC intern/voxel.c intern/winstuff.c - BLI_args.h BLI_alloca.h + BLI_args.h BLI_array.h BLI_bitmap.h BLI_blenlib.h - BLI_buffer.h BLI_boxpack2d.h + BLI_buffer.h BLI_callbacks.h + BLI_compiler_attrs.h + BLI_convexhull2d.h BLI_cpu.h BLI_dlrbTree.h BLI_dynlib.h @@ -125,6 +130,7 @@ set(SRC BLI_kdtree.h BLI_lasso.h BLI_linklist.h + BLI_linklist_stack.h BLI_listbase.h BLI_math.h BLI_math_base.h @@ -146,7 +152,10 @@ set(SRC BLI_rect.h BLI_scanfill.h BLI_smallhash.h + BLI_sort.h + BLI_sort_utils.h BLI_stack.h + BLI_strict_flags.h BLI_string.h BLI_string_cursor_utf8.h BLI_string_utf8.h @@ -159,6 +168,7 @@ set(SRC BLI_voxel.h BLI_winstuff.h PIL_time.h + PIL_time_utildefines.h ) if(WITH_BINRELOC) @@ -168,6 +178,10 @@ if(WITH_BINRELOC) add_definitions(-DWITH_BINRELOC) endif() +if(WITH_MEM_VALGRIND) + add_definitions(-DWITH_MEM_VALGRIND) +endif() + if(WIN32) list(APPEND INC ../../../intern/utfconv diff --git a/source/blender/blenlib/PIL_time.h b/source/blender/blenlib/PIL_time.h index c3e7e8486d9..158559fa3d9 100644 --- a/source/blender/blenlib/PIL_time.h +++ b/source/blender/blenlib/PIL_time.h @@ -51,44 +51,8 @@ double PIL_check_seconds_timer(void); */ void PIL_sleep_ms(int ms); -/** Utility defines for timing. - * requires BLI_utildefines.h for 'AT' - * TIMEIT_VALUE returns the time since TIMEIT_START was called. - */ -#define TIMEIT_START(var) \ - { \ - double _timeit_##var = PIL_check_seconds_timer(); \ - printf("time start (" #var "): " AT "\n"); \ - fflush(stdout); \ - { (void)0 - -#define TIMEIT_VALUE(var) (float)(PIL_check_seconds_timer() - _timeit_##var) - -#define TIMEIT_VALUE_PRINT(var) \ - { \ - printf("time update(" #var "): %.6f" " " AT "\n", TIMEIT_VALUE(var));\ - fflush(stdout); \ - } (void)0 - -#define TIMEIT_END(var) \ - } \ - printf("time end (" #var "): %.6f" " " AT "\n", TIMEIT_VALUE(var)); \ - fflush(stdout); \ -} (void)0 - -/** - * Given some function/expression: - * TIMEIT_BENCH(some_function(), some_unique_description); - */ -#define TIMEIT_BENCH(expr, id) \ - { \ - TIMEIT_START(id); \ - (expr); \ - TIMEIT_END(id); \ - } (void)0 - #ifdef __cplusplus } #endif -#endif /* !__PIL_TIME_H__ */ +#endif /* __PIL_TIME_H__ */ diff --git a/source/blender/blenlib/PIL_time_utildefines.h b/source/blender/blenlib/PIL_time_utildefines.h new file mode 100644 index 00000000000..135817f6a17 --- /dev/null +++ b/source/blender/blenlib/PIL_time_utildefines.h @@ -0,0 +1,96 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Campbell Barton + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenlib/PIL_time_utildefines.h + * \ingroup bli + * \brief Utility defines for timing/benchmarks. + */ + +#ifndef __PIL_TIME_UTILDEFINES_H__ +#define __PIL_TIME_UTILDEFINES_H__ + +#include "PIL_time.h" /* for PIL_check_seconds_timer */ +#include "BLI_utildefines.h" /* for AT */ + +#define TIMEIT_START(var) \ + { \ + double _timeit_##var = PIL_check_seconds_timer(); \ + printf("time start (" #var "): " AT "\n"); \ + fflush(stdout); \ + { (void)0 + +/** + * \return the time since TIMEIT_START was called. + */ +#define TIMEIT_VALUE(var) (float)(PIL_check_seconds_timer() - _timeit_##var) + +#define TIMEIT_VALUE_PRINT(var) \ + { \ + printf("time update(" #var "): %.6f" " " AT "\n", TIMEIT_VALUE(var));\ + fflush(stdout); \ + } (void)0 + +#define TIMEIT_END(var) \ + } \ + printf("time end (" #var "): %.6f" " " AT "\n", TIMEIT_VALUE(var)); \ + fflush(stdout); \ +} (void)0 + +/** + * Given some function/expression: + * TIMEIT_BENCH(some_function(), some_unique_description); + */ +#define TIMEIT_BENCH(expr, id) \ + { \ + TIMEIT_START(id); \ + (expr); \ + TIMEIT_END(id); \ + } (void)0 + +#define TIMEIT_BLOCK_INIT(id) \ + double _timeit_var_##id = 0; \ + (void) 0 + +#define TIMEIT_BLOCK_START(id) \ + { \ + double _timeit_block_start_##id = PIL_check_seconds_timer(); \ + { (void)0 + +#define TIMEIT_BLOCK_END(id) \ + } \ + _timeit_var_##id += (PIL_check_seconds_timer() - \ + _timeit_block_start_##id); \ + } (void)0 + +#define TIMEIT_BLOCK_STATS(id) \ + { \ + printf("%s time (in seconds): %f\n", #id, _timeit_var_##id); \ + fflush(stdout); \ + } (void)0 + +#endif /* __PIL_TIME_UTILDEFINES_H__ */ diff --git a/source/blender/blenlib/intern/BLI_array.c b/source/blender/blenlib/intern/BLI_array.c index 510bf072513..21d7a5a6d10 100644 --- a/source/blender/blenlib/intern/BLI_array.c +++ b/source/blender/blenlib/intern/BLI_array.c @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2008 Blender Foundation. * All rights reserved. diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 14dfbcffebe..fcca6cd59ba 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -23,12 +23,13 @@ * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** - * A general (pointer -> pointer) hash table ADT */ /** \file blender/blenlib/intern/BLI_ghash.c * \ingroup bli * + * A general (pointer -> pointer) hash table ADT + * * \note edgehash.c is based on this, make sure they stay in sync. */ @@ -42,16 +43,8 @@ #include "BLI_utildefines.h" #include "BLI_mempool.h" #include "BLI_ghash.h" +#include "BLI_strict_flags.h" -/***/ - -#ifdef __GNUC__ -# pragma GCC diagnostic error "-Wsign-conversion" -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 /* gcc4.6+ only */ -# pragma GCC diagnostic error "-Wsign-compare" -# pragma GCC diagnostic error "-Wconversion" -# endif -#endif const unsigned int hashsizes[] = { 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, @@ -60,206 +53,507 @@ const unsigned int hashsizes[] = { 268435459 }; +/* internal flag to ensure sets values aren't used */ +#ifndef NDEBUG +# define GHASH_FLAG_IS_SET (1 << 8) +# define IS_GHASH_ASSERT(gh) BLI_assert((gh->flag & GHASH_FLAG_IS_SET) == 0) +// # define IS_GSET_ASSERT(gs) BLI_assert((gs->flag & GHASH_FLAG_IS_SET) != 0) +#else +# define IS_GHASH_ASSERT(gh) +// # define IS_GSET_ASSERT(eh) +#endif + /***/ -GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) +typedef struct Entry { + struct Entry *next; + + void *key, *val; +} Entry; + +struct GHash { + GHashHashFP hashfp; + GHashCmpFP cmpfp; + + Entry **buckets; + struct BLI_mempool *entrypool; + unsigned int nbuckets; + unsigned int nentries; + unsigned int cursize, flag; +}; + + +/* -------------------------------------------------------------------- */ +/* GHash API */ + +/** \name Internal Utility API + * \{ */ + +/** + * Get the hash for a key. + */ +BLI_INLINE unsigned int ghash_keyhash(GHash *gh, const void *key) +{ + return gh->hashfp(key) % gh->nbuckets; +} + +/** + * Check if the number of items in the GHash is large enough to require more buckets. + */ +BLI_INLINE bool ghash_test_expand_buckets(const unsigned int nentries, const unsigned int nbuckets) +{ + return (nentries > nbuckets * 3); +} + +/** + * Expand buckets to the next size up. + */ +BLI_INLINE void ghash_resize_buckets(GHash *gh, const unsigned int nbuckets) +{ + Entry **buckets_old = gh->buckets; + Entry **buckets_new; + const unsigned int nbuckets_old = gh->nbuckets; + unsigned int i; + Entry *e; + + BLI_assert(gh->nbuckets != nbuckets); + + gh->nbuckets = nbuckets; + buckets_new = (Entry **)MEM_callocN(gh->nbuckets * sizeof(*gh->buckets), "buckets"); + + for (i = 0; i < nbuckets_old; i++) { + Entry *e_next; + for (e = buckets_old[i]; e; e = e_next) { + const unsigned hash = ghash_keyhash(gh, e->key); + e_next = e->next; + e->next = buckets_new[hash]; + buckets_new[hash] = e; + } + } + + gh->buckets = buckets_new; + MEM_freeN(buckets_old); +} + +/** + * Increase initial bucket size to match a reserved ammount. + */ +BLI_INLINE void ghash_buckets_reserve(GHash *gh, const unsigned int nentries_reserve) +{ + while (ghash_test_expand_buckets(nentries_reserve, gh->nbuckets)) { + gh->nbuckets = hashsizes[++gh->cursize]; + } +} + +/** + * Internal lookup function. + * Takes a hash argument to avoid calling #ghash_keyhash multiple times. + */ +BLI_INLINE Entry *ghash_lookup_entry_ex(GHash *gh, const void *key, + const unsigned int hash) +{ + Entry *e; + + for (e = gh->buckets[hash]; e; e = e->next) { + if (UNLIKELY(gh->cmpfp(key, e->key) == 0)) { + return e; + } + } + return NULL; +} + +/** + * Internal lookup function. Only wraps #ghash_lookup_entry_ex + */ +BLI_INLINE Entry *ghash_lookup_entry(GHash *gh, const void *key) +{ + const unsigned int hash = ghash_keyhash(gh, key); + return ghash_lookup_entry_ex(gh, key, hash); +} + +static GHash *ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, + const unsigned int nentries_reserve, + const unsigned int entry_size) { GHash *gh = MEM_mallocN(sizeof(*gh), info); + gh->hashfp = hashfp; gh->cmpfp = cmpfp; - gh->entrypool = BLI_mempool_create(sizeof(Entry), 64, 64, 0); - gh->cursize = 0; + gh->nbuckets = hashsizes[0]; /* gh->cursize */ gh->nentries = 0; - gh->nbuckets = hashsizes[gh->cursize]; + gh->cursize = 0; + gh->flag = 0; + + /* if we have reserved the number of elements that this hash will contain */ + if (nentries_reserve) { + ghash_buckets_reserve(gh, nentries_reserve); + } gh->buckets = MEM_callocN(gh->nbuckets * sizeof(*gh->buckets), "buckets"); + gh->entrypool = BLI_mempool_create(entry_size, 64, 64, 0); return gh; } -int BLI_ghash_size(GHash *gh) -{ - return (int)gh->nentries; -} - -void BLI_ghash_insert(GHash *gh, void *key, void *val) +/** + * Internal insert function. + * Takes a hash argument to avoid calling #ghash_keyhash multiple times. + */ +BLI_INLINE void ghash_insert_ex(GHash *gh, void *key, void *val, + unsigned int hash) { - unsigned int hash = gh->hashfp(key) % gh->nbuckets; Entry *e = (Entry *)BLI_mempool_alloc(gh->entrypool); + BLI_assert((gh->flag & GHASH_FLAG_ALLOW_DUPES) || (BLI_ghash_haskey(gh, key) == 0)); + IS_GHASH_ASSERT(gh); e->next = gh->buckets[hash]; e->key = key; e->val = val; gh->buckets[hash] = e; - if (UNLIKELY(++gh->nentries > gh->nbuckets / 2)) { - Entry **old = gh->buckets; - const unsigned nold = gh->nbuckets; - unsigned int i; - - gh->nbuckets = hashsizes[++gh->cursize]; - gh->buckets = (Entry **)MEM_callocN(gh->nbuckets * sizeof(*gh->buckets), "buckets"); - - for (i = 0; i < nold; i++) { - Entry *e_next; - for (e = old[i]; e; e = e_next) { - e_next = e->next; - hash = gh->hashfp(e->key) % gh->nbuckets; - e->next = gh->buckets[hash]; - gh->buckets[hash] = e; - } - } - - MEM_freeN(old); + if (UNLIKELY(ghash_test_expand_buckets(++gh->nentries, gh->nbuckets))) { + ghash_resize_buckets(gh, hashsizes[++gh->cursize]); } } -void *BLI_ghash_lookup(GHash *gh, const void *key) +/** + * Insert function that doesn't set the value (use for GSet) + */ +BLI_INLINE void ghash_insert_ex_keyonly(GHash *gh, void *key, + unsigned int hash) { - const unsigned int hash = gh->hashfp(key) % gh->nbuckets; - Entry *e; + Entry *e = (Entry *)BLI_mempool_alloc(gh->entrypool); + BLI_assert((gh->flag & GHASH_FLAG_ALLOW_DUPES) || (BLI_ghash_haskey(gh, key) == 0)); + e->next = gh->buckets[hash]; + e->key = key; + /* intentionally leave value unset */ + gh->buckets[hash] = e; - for (e = gh->buckets[hash]; e; e = e->next) { - if (gh->cmpfp(key, e->key) == 0) { - return e->val; - } + if (UNLIKELY(ghash_test_expand_buckets(++gh->nentries, gh->nbuckets))) { + ghash_resize_buckets(gh, hashsizes[++gh->cursize]); } - return NULL; } -bool BLI_ghash_remove(GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) +BLI_INLINE void ghash_insert(GHash *gh, void *key, void *val) +{ + const unsigned int hash = ghash_keyhash(gh, key); + ghash_insert_ex(gh, key, val, hash); +} + +/** + * Remove the entry and return it, caller must free from gh->entrypool. + */ +static Entry *ghash_remove_ex(GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, + unsigned int hash) { - unsigned int hash = gh->hashfp(key) % gh->nbuckets; Entry *e; - Entry *p = NULL; + Entry *e_prev = NULL; for (e = gh->buckets[hash]; e; e = e->next) { - if (gh->cmpfp(key, e->key) == 0) { - Entry *n = e->next; + if (UNLIKELY(gh->cmpfp(key, e->key) == 0)) { + Entry *e_next = e->next; if (keyfreefp) keyfreefp(e->key); if (valfreefp) valfreefp(e->val); - BLI_mempool_free(gh->entrypool, e); - /* correct but 'e' isn't used before return */ - /* e = n; *//*UNUSED*/ - if (p) p->next = n; - else gh->buckets[hash] = n; + if (e_prev) e_prev->next = e_next; + else gh->buckets[hash] = e_next; gh->nentries--; - return true; + return e; } - p = e; + e_prev = e; } - return false; + return NULL; } -void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) +/** + * Run free callbacks for freeing entries. + */ +static void ghash_free_cb(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) { unsigned int i; - if (keyfreefp || valfreefp) { - for (i = 0; i < gh->nbuckets; i++) { - Entry *e; + BLI_assert(keyfreefp || valfreefp); - for (e = gh->buckets[i]; e; ) { - Entry *n = e->next; + for (i = 0; i < gh->nbuckets; i++) { + Entry *e; - if (keyfreefp) keyfreefp(e->key); - if (valfreefp) valfreefp(e->val); + for (e = gh->buckets[i]; e; ) { + Entry *e_next = e->next; - e = n; - } + if (keyfreefp) keyfreefp(e->key); + if (valfreefp) valfreefp(e->val); + + e = e_next; } } +} +/** \} */ - gh->cursize = 0; - gh->nentries = 0; - gh->nbuckets = hashsizes[gh->cursize]; - MEM_freeN(gh->buckets); - gh->buckets = MEM_callocN(gh->nbuckets * sizeof(*gh->buckets), "buckets"); -} +/** \name Public API + * \{ */ -/* same as above but return the value, - * no free value argument since it will be returned */ -void *BLI_ghash_pop(GHash *gh, void *key, GHashKeyFreeFP keyfreefp) +/** + * Creates a new, empty GHash. + * + * \param hashfp Hash callback. + * \param cmpfp Comparison callback. + * \param info Identifier string for the GHash. + * \param nentries_reserve Optionally reserve the number of members that the hash will hold. + * Use this to avoid resizing buckets if the size is known or can be closely approximated. + * \return An empty GHash. + */ +GHash *BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, + const unsigned int nentries_reserve) { - unsigned int hash = gh->hashfp(key) % gh->nbuckets; - Entry *e; - Entry *p = NULL; + return ghash_new(hashfp, cmpfp, info, + nentries_reserve, + (unsigned int)sizeof(Entry)); +} - for (e = gh->buckets[hash]; e; e = e->next) { - if (gh->cmpfp(key, e->key) == 0) { - Entry *n = e->next; - void *value = e->val; +/** + * Wraps #BLI_ghash_new_ex with zero entries reserved. + */ +GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) +{ + return BLI_ghash_new_ex(hashfp, cmpfp, info, 0); +} - if (keyfreefp) keyfreefp(e->key); - BLI_mempool_free(gh->entrypool, e); +/** + * \return size of the GHash. + */ +int BLI_ghash_size(GHash *gh) +{ + return (int)gh->nentries; +} - /* correct but 'e' isn't used before return */ - /* e = n; *//*UNUSED*/ - if (p) p->next = n; - else gh->buckets[hash] = n; +/** + * Insert a key/value pair into the \a gh. + * + * \note Duplicates are not checked, + * the caller is expected to ensure elements are unique unless + * GHASH_FLAG_ALLOW_DUPES flag is set. + */ +void BLI_ghash_insert(GHash *gh, void *key, void *val) +{ + ghash_insert(gh, key, val); +} - gh->nentries--; - return value; - } - p = e; +/** + * Inserts a new value to a key that may already be in ghash. + * + * Avoids #BLI_ghash_remove, #BLI_ghash_insert calls (double lookups) + * + * \returns true if a new key has been added. + */ +bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) +{ + const unsigned int hash = ghash_keyhash(gh, key); + Entry *e = ghash_lookup_entry_ex(gh, key, hash); + if (e) { + if (keyfreefp) keyfreefp(e->key); + if (valfreefp) valfreefp(e->val); + e->key = key; + e->val = val; + return false; + } + else { + ghash_insert_ex(gh, key, val, hash); + return true; } - - return NULL; } -bool BLI_ghash_haskey(GHash *gh, const void *key) +/** + * Lookup the value of \a key in \a gh. + * + * \param key The key to lookup. + * \returns the value for \a key or NULL. + * + * \note When NULL is a valid value, use #BLI_ghash_lookup_p to differentiate a missing key + * from a key with a NULL value. (Avoids calling #BLI_ghash_haskey before #BLI_ghash_lookup) + */ +void *BLI_ghash_lookup(GHash *gh, const void *key) { - unsigned int hash = gh->hashfp(key) % gh->nbuckets; - Entry *e; + Entry *e = ghash_lookup_entry(gh, key); + IS_GHASH_ASSERT(gh); + return e ? e->val : NULL; +} - for (e = gh->buckets[hash]; e; e = e->next) - if (gh->cmpfp(key, e->key) == 0) - return true; +/** + * Lookup a pointer to the value of \a key in \a gh. + * + * \param key The key to lookup. + * \returns the pointer to value for \a key or NULL. + * + * \note This has 2 main benifits over #BLI_ghash_lookup. + * - A NULL return always means that \a key isn't in \a gh. + * - The value can be modified in-place without further function calls (faster). + */ +void **BLI_ghash_lookup_p(GHash *gh, const void *key) +{ + Entry *e = ghash_lookup_entry(gh, key); + IS_GHASH_ASSERT(gh); + return e ? &e->val : NULL; +} - return false; +/** + * Remove \a key from \a gh, or return false if the key wasn't found. + * + * \param key The key to remove. + * \param keyfreefp Optional callback to free the key. + * \param valfreefp Optional callback to free the value. + * \return true if \a key was removed from \a gh. + */ +bool BLI_ghash_remove(GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) +{ + const unsigned int hash = ghash_keyhash(gh, key); + Entry *e = ghash_remove_ex(gh, key, keyfreefp, valfreefp, hash); + if (e) { + BLI_mempool_free(gh->entrypool, e); + return true; + } + else { + return false; + } } -void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) +/* same as above but return the value, + * no free value argument since it will be returned */ +/** + * Remove \a key from \a gh, returning the value or NULL if the key wasn't found. + * + * \param key The key to remove. + * \param keyfreefp Optional callback to free the key. + * \return the value of \a key int \a gh or NULL. + */ +void *BLI_ghash_popkey(GHash *gh, void *key, GHashKeyFreeFP keyfreefp) { - unsigned int i; + const unsigned int hash = ghash_keyhash(gh, key); + Entry *e = ghash_remove_ex(gh, key, keyfreefp, NULL, hash); + IS_GHASH_ASSERT(gh); + if (e) { + void *val = e->val; + BLI_mempool_free(gh->entrypool, e); + return val; + } + else { + return NULL; + } +} - if (keyfreefp || valfreefp) { - for (i = 0; i < gh->nbuckets; i++) { - Entry *e; +/** + * \return true if the \a key is in \a gh. + */ +bool BLI_ghash_haskey(GHash *gh, const void *key) +{ + return (ghash_lookup_entry(gh, key) != NULL); +} - for (e = gh->buckets[i]; e; ) { - Entry *n = e->next; +/** + * Reset \a gh clearing all entries. + * + * \param keyfreefp Optional callback to free the key. + * \param valfreefp Optional callback to free the value. + * \param nentries_reserve Optionally reserve the number of members that the hash will hold. + */ +void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, + const unsigned int nentries_reserve) +{ + if (keyfreefp || valfreefp) + ghash_free_cb(gh, keyfreefp, valfreefp); - if (keyfreefp) keyfreefp(e->key); - if (valfreefp) valfreefp(e->val); + gh->nbuckets = hashsizes[0]; /* gh->cursize */ + gh->nentries = 0; + gh->cursize = 0; - e = n; - } - } + if (nentries_reserve) { + ghash_buckets_reserve(gh, nentries_reserve); } MEM_freeN(gh->buckets); + gh->buckets = MEM_callocN(gh->nbuckets * sizeof(*gh->buckets), "buckets"); + + BLI_mempool_clear_ex(gh->entrypool, nentries_reserve ? (int)nentries_reserve : -1); +} + +/** + * Wraps #BLI_ghash_clear_ex with zero entries reserved. + */ +void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) +{ + BLI_ghash_clear_ex(gh, keyfreefp, valfreefp, 0); +} + +/** + * Frees the GHash and its members. + * + * \param gh The GHash to free. + * \param keyfreefp Optional callback to free the key. + * \param valfreefp Optional callback to free the value. + */ +void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) +{ + BLI_assert((int)gh->nentries == BLI_mempool_count(gh->entrypool)); + if (keyfreefp || valfreefp) + ghash_free_cb(gh, keyfreefp, valfreefp); + + MEM_freeN(gh->buckets); BLI_mempool_destroy(gh->entrypool); - gh->buckets = NULL; - gh->nentries = 0; - gh->nbuckets = 0; MEM_freeN(gh); } -/***/ +/** + * Sets a GHash flag. + */ +void BLI_ghash_flag_set(GHash *gh, unsigned int flag) +{ + gh->flag |= flag; +} +/** + * Clear a GHash flag. + */ +void BLI_ghash_flag_clear(GHash *gh, unsigned int flag) +{ + gh->flag &= ~flag; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/* GHash Iterator API */ + +/** \name Iterator API + * \{ */ + +/** + * Create a new GHashIterator. The hash table must not be mutated + * while the iterator is in use, and the iterator will step exactly + * BLI_ghash_size(gh) times before becoming done. + * + * \param gh The GHash to iterate over. + * \return Pointer to a new DynStr. + */ GHashIterator *BLI_ghashIterator_new(GHash *gh) { GHashIterator *ghi = MEM_mallocN(sizeof(*ghi), "ghash iterator"); BLI_ghashIterator_init(ghi, gh); return ghi; } + +/** + * Init an already allocated GHashIterator. The hash table must not + * be mutated while the iterator is in use, and the iterator will + * step exactly BLI_ghash_size(gh) times before becoming done. + * + * \param ghi The GHashIterator to initialize. + * \param gh The GHash to iterate over. + */ void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh) { ghi->gh = gh; @@ -272,20 +566,58 @@ void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh) ghi->curEntry = ghi->gh->buckets[ghi->curBucket]; } } + +/** + * Free a GHashIterator. + * + * \param ghi The iterator to free. + */ void BLI_ghashIterator_free(GHashIterator *ghi) { MEM_freeN(ghi); } +/** + * Retrieve the key from an iterator. + * + * \param ghi The iterator. + * \return The key at the current index, or NULL if the + * iterator is done. + */ void *BLI_ghashIterator_getKey(GHashIterator *ghi) { return ghi->curEntry ? ghi->curEntry->key : NULL; } + +/** + * Retrieve the value from an iterator. + * + * \param ghi The iterator. + * \return The value at the current index, or NULL if the + * iterator is done. + */ void *BLI_ghashIterator_getValue(GHashIterator *ghi) { return ghi->curEntry ? ghi->curEntry->val : NULL; } +/** + * Retrieve the value from an iterator. + * + * \param ghi The iterator. + * \return The value at the current index, or NULL if the + * iterator is done. + */ +void **BLI_ghashIterator_getValue_p(GHashIterator *ghi) +{ + return ghi->curEntry ? &ghi->curEntry->val : NULL; +} + +/** + * Steps the iterator to the next index. + * + * \param ghi The iterator. + */ void BLI_ghashIterator_step(GHashIterator *ghi) { if (ghi->curEntry) { @@ -298,17 +630,44 @@ void BLI_ghashIterator_step(GHashIterator *ghi) } } } + +/** + * Determine if an iterator is done (has reached the end of + * the hash table). + * + * \param ghi The iterator. + * \return True if done, False otherwise. + */ bool BLI_ghashIterator_done(GHashIterator *ghi) { return ghi->curEntry == NULL; } +/** \} */ + + +/** \name Generic Key Hash & Comparison Functions + * \{ */ + /***/ +#if 0 +/* works but slower */ unsigned int BLI_ghashutil_ptrhash(const void *key) { return (unsigned int)(intptr_t)key; } +#else +/* based python3.3's pointer hashing function */ +unsigned int BLI_ghashutil_ptrhash(const void *key) +{ + size_t y = (size_t)key; + /* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid + * excessive hash collisions for dicts and sets */ + y = (y >> 4) | (y << (8 * sizeof(void *) - 4)); + return (unsigned int)y; +} +#endif int BLI_ghashutil_ptrcmp(const void *a, const void *b) { if (a == b) @@ -364,23 +723,6 @@ int BLI_ghashutil_strcmp(const void *a, const void *b) return strcmp(a, b); } -GHash *BLI_ghash_ptr_new(const char *info) -{ - return BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, info); -} -GHash *BLI_ghash_str_new(const char *info) -{ - return BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, info); -} -GHash *BLI_ghash_int_new(const char *info) -{ - return BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, info); -} -GHash *BLI_ghash_pair_new(const char *info) -{ - return BLI_ghash_new(BLI_ghashutil_pairhash, BLI_ghashutil_paircmp, info); -} - GHashPair *BLI_ghashutil_pairalloc(const void *first, const void *second) { GHashPair *pair = MEM_mallocN(sizeof(GHashPair), "GHashPair"); @@ -411,3 +753,176 @@ void BLI_ghashutil_pairfree(void *ptr) { MEM_freeN(ptr); } + +/** \} */ + + +/** \name Convenience GHash Creation Functions + * \{ */ + +GHash *BLI_ghash_ptr_new_ex(const char *info, + const unsigned int nentries_reserve) +{ + return BLI_ghash_new_ex(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, info, + nentries_reserve); +} +GHash *BLI_ghash_ptr_new(const char *info) +{ + return BLI_ghash_ptr_new_ex(info, 0); +} + +GHash *BLI_ghash_str_new_ex(const char *info, + const unsigned int nentries_reserve) +{ + return BLI_ghash_new_ex(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, info, + nentries_reserve); +} +GHash *BLI_ghash_str_new(const char *info) +{ + return BLI_ghash_str_new_ex(info, 0); +} + +GHash *BLI_ghash_int_new_ex(const char *info, + const unsigned int nentries_reserve) +{ + return BLI_ghash_new_ex(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, info, + nentries_reserve); +} +GHash *BLI_ghash_int_new(const char *info) +{ + return BLI_ghash_int_new_ex(info, 0); +} + +GHash *BLI_ghash_pair_new_ex(const char *info, + const unsigned int nentries_reserve) +{ + return BLI_ghash_new_ex(BLI_ghashutil_pairhash, BLI_ghashutil_paircmp, info, + nentries_reserve); +} +GHash *BLI_ghash_pair_new(const char *info) +{ + return BLI_ghash_pair_new_ex(info, 0); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/* GSet API */ + +/* Use ghash API to give 'set' functionality */ + +/* TODO: typical set functions + * isdisjoint/issubset/issuperset/union/intersection/difference etc */ + +/** \name GSet Functions + * \{ */ +GSet *BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info, + const unsigned int nentries_reserve) +{ + GSet *gs = (GSet *)ghash_new(hashfp, cmpfp, info, + nentries_reserve, + sizeof(Entry) - sizeof(void *)); +#ifndef NDEBUG + ((GHash *)gs)->flag |= GHASH_FLAG_IS_SET; +#endif + return gs; +} + +GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info) +{ + return BLI_gset_new_ex(hashfp, cmpfp, info, 0); +} + +int BLI_gset_size(GSet *gs) +{ + return (int)((GHash *)gs)->nentries; +} + +/** + * Adds the key to the set (no checks for unique keys!). + * Matching #BLI_ghash_insert + */ +void BLI_gset_insert(GSet *gs, void *key) +{ + const unsigned int hash = ghash_keyhash((GHash *)gs, key); + ghash_insert_ex_keyonly((GHash *)gs, key, hash); +} + +/** + * Adds the key to the set (duplicates are managed). + * Matching #BLI_ghash_reinsert + * + * \returns true if a new key has been added. + */ +bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp) +{ + const unsigned int hash = ghash_keyhash((GHash *)gs, key); + Entry *e = ghash_lookup_entry_ex((GHash *)gs, key, hash); + if (e) { + if (keyfreefp) keyfreefp(e->key); + e->key = key; + return false; + } + else { + ghash_insert_ex_keyonly((GHash *)gs, key, hash); + return true; + } +} + +bool BLI_gset_remove(GSet *gs, void *key, GSetKeyFreeFP keyfreefp) +{ + return BLI_ghash_remove((GHash *)gs, key, keyfreefp, NULL); +} + + +bool BLI_gset_haskey(GSet *gs, const void *key) +{ + return (ghash_lookup_entry((GHash *)gs, key) != NULL); +} + +void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp, + const unsigned int nentries_reserve) +{ + BLI_ghash_clear_ex((GHash *)gs, keyfreefp, NULL, + nentries_reserve); +} + +void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp) +{ + BLI_ghash_clear((GHash *)gs, keyfreefp, NULL); +} + +void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp) +{ + BLI_ghash_free((GHash *)gs, keyfreefp, NULL); +} +/** \} */ + + +/** \name Convenience GSet Creation Functions + * \{ */ + +GSet *BLI_gset_ptr_new_ex(const char *info, + const unsigned int nentries_reserve) +{ + return BLI_gset_new_ex(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, info, + nentries_reserve); +} +GSet *BLI_gset_ptr_new(const char *info) +{ + return BLI_gset_ptr_new_ex(info, 0); +} + +GSet *BLI_gset_pair_new_ex(const char *info, + const unsigned int nentries_reserve) +{ + return BLI_gset_new_ex(BLI_ghashutil_pairhash, BLI_ghashutil_paircmp, info, + nentries_reserve); +} +GSet *BLI_gset_pair_new(const char *info) +{ + return BLI_gset_pair_new_ex(info, 0); +} + +/** \} */ diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c index 0aaa3e13b3f..45bdeeedcf9 100644 --- a/source/blender/blenlib/intern/BLI_heap.c +++ b/source/blender/blenlib/intern/BLI_heap.c @@ -34,14 +34,7 @@ #include "BLI_utildefines.h" #include "BLI_memarena.h" #include "BLI_heap.h" - -#ifdef __GNUC__ -# pragma GCC diagnostic error "-Wsign-conversion" -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 /* gcc4.6+ only */ -# pragma GCC diagnostic error "-Wsign-compare" -# pragma GCC diagnostic error "-Wconversion" -# endif -#endif +#include "BLI_strict_flags.h" /***/ diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index a4c72aa26b0..80483fbfa38 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -36,6 +36,7 @@ #include "BLI_utildefines.h" #include "BLI_kdopbvh.h" #include "BLI_math.h" +#include "BLI_strict_flags.h" #ifdef _OPENMP #include <omp.h> @@ -65,8 +66,8 @@ struct BVHTree { int totleaf; /* leafs */ int totbranch; axis_t start_axis, stop_axis; /* KDOP_AXES array indices according to axis */ - axis_t axis; /* kdop type (6 => OBB, 7 => AABB, ...) */ - char tree_type; /* type of tree (4 => quadtree) */ + axis_t axis; /* kdop type (6 => OBB, 7 => AABB, ...) */ + char tree_type; /* type of tree (4 => quadtree) */ }; /* optimization, ensure we stay small */ @@ -77,7 +78,8 @@ BLI_STATIC_ASSERT((sizeof(void *) == 8 && sizeof(BVHTree) <= 48) || typedef struct BVHOverlapData { BVHTree *tree1, *tree2; BVHTreeOverlap *overlap; - int i, max_overlap; /* i is number of overlaps */ + unsigned int i; + unsigned int max_overlap; /* i is number of overlaps */ axis_t start_axis, stop_axis; } BVHOverlapData; @@ -437,7 +439,7 @@ static void refit_kdop_hull(BVHTree *tree, BVHNode *node, int start, int end) /* only supports x,y,z axis in the moment * but we should use a plain and simple function here for speed sake */ -static char get_largest_axis(float *bv) +static char get_largest_axis(const float *bv) { float middle_point[3]; @@ -497,9 +499,13 @@ static void bvhtree_print_tree(BVHTree *tree, BVHNode *node, int depth) axis_t axis_iter; for (i = 0; i < depth; i++) printf(" "); - printf(" - %d (%ld): ", node->index, node - tree->nodearray); - for (axis_iter = 2 * tree->start_axis; axis_iter < 2 * tree->stop_axis; axis_iter++) + printf(" - %d (%ld): ", node->index, (long int)(node - tree->nodearray)); + for (axis_iter = (axis_t)(2 * tree->start_axis); + axis_iter < (axis_t)(2 * tree->stop_axis); + axis_iter++) + { printf("%.3f ", node->bv[axis_iter]); + } printf("\n"); for (i = 0; i < tree->tree_type; i++) @@ -513,7 +519,7 @@ static void bvhtree_info(BVHTree *tree) printf("tree_type = %d, axis = %d, epsilon = %f\n", tree->tree_type, tree->axis, tree->epsilon); printf("nodes = %d, branches = %d, leafs = %d\n", tree->totbranch + tree->totleaf, tree->totbranch, tree->totleaf); printf("Memory per node = %ldbytes\n", sizeof(BVHNode) + sizeof(BVHNode *) * tree->tree_type + sizeof(float) * tree->axis); - printf("BV memory = %dbytes\n", MEM_allocN_len(tree->nodebv)); + printf("BV memory = %dbytes\n", (int)MEM_allocN_len(tree->nodebv)); printf("Total memory = %ldbytes\n", sizeof(BVHTree) + MEM_allocN_len(tree->nodes) + @@ -792,7 +798,7 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array, break; } - parent->totnode = k + 1; + parent->totnode = (char)(k + 1); } } } @@ -811,10 +817,9 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis) if (tree_type < 2) return NULL; - if (tree_type > MAX_TREETYPE) - return NULL; + BLI_assert(tree_type <= MAX_TREETYPE); - tree = (BVHTree *)MEM_callocN(sizeof(BVHTree), "BVHTree"); + tree = MEM_callocN(sizeof(BVHTree), "BVHTree"); /* tree epsilon must be >= FLT_EPSILON * so that tangent rays can still hit a bounding volume.. @@ -855,27 +860,27 @@ BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis) /* Allocate arrays */ numnodes = maxsize + implicit_needed_branches(tree_type, maxsize) + tree_type; - tree->nodes = (BVHNode **)MEM_callocN(sizeof(BVHNode *) * numnodes, "BVHNodes"); + tree->nodes = MEM_callocN(sizeof(BVHNode *) * (size_t)numnodes, "BVHNodes"); if (!tree->nodes) { MEM_freeN(tree); return NULL; } - - tree->nodebv = (float *)MEM_callocN(sizeof(float) * axis * numnodes, "BVHNodeBV"); + + tree->nodebv = MEM_callocN(sizeof(float) * (size_t)(axis * numnodes), "BVHNodeBV"); if (!tree->nodebv) { MEM_freeN(tree->nodes); MEM_freeN(tree); } - tree->nodechild = (BVHNode **)MEM_callocN(sizeof(BVHNode *) * tree_type * numnodes, "BVHNodeBV"); + tree->nodechild = MEM_callocN(sizeof(BVHNode *) * (size_t)(tree_type * numnodes), "BVHNodeBV"); if (!tree->nodechild) { MEM_freeN(tree->nodebv); MEM_freeN(tree->nodes); MEM_freeN(tree); } - tree->nodearray = (BVHNode *)MEM_callocN(sizeof(BVHNode) * numnodes, "BVHNodeArray"); + tree->nodearray = MEM_callocN(sizeof(BVHNode) * (size_t)numnodes, "BVHNodeArray"); if (!tree->nodearray) { MEM_freeN(tree->nodechild); @@ -915,7 +920,7 @@ void BLI_bvhtree_balance(BVHTree *tree) BVHNode **leafs_array = tree->nodes; /* This function should only be called once (some big bug goes here if its being called more than once per tree) */ - assert(tree->totbranch == 0); + BLI_assert(tree->totbranch == 0); /* Build the implicit tree */ non_recursive_bvh_div_nodes(tree, branches_array, leafs_array, tree->totleaf); @@ -930,19 +935,14 @@ void BLI_bvhtree_balance(BVHTree *tree) /* bvhtree_info(tree); */ } -int BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints) +void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints) { axis_t axis_iter; BVHNode *node = NULL; /* insert should only possible as long as tree->totbranch is 0 */ - if (tree->totbranch > 0) - return 0; - - if (tree->totleaf + 1 >= MEM_allocN_len(tree->nodes) / sizeof(*(tree->nodes))) - return 0; - - /* TODO check if have enough nodes in array */ + BLI_assert(tree->totbranch <= 0); + BLI_assert((size_t)tree->totleaf < MEM_allocN_len(tree->nodes) / sizeof(*(tree->nodes))); node = tree->nodes[tree->totleaf] = &(tree->nodearray[tree->totleaf]); tree->totleaf++; @@ -955,8 +955,6 @@ int BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoint node->bv[(2 * axis_iter)] -= tree->epsilon; /* minimum */ node->bv[(2 * axis_iter) + 1] += tree->epsilon; /* maximum */ } - - return 1; } @@ -1012,10 +1010,10 @@ float BLI_bvhtree_getepsilon(const BVHTree *tree) * overlap - is it possible for 2 bv's to collide ? */ static int tree_overlap(BVHNode *node1, BVHNode *node2, axis_t start_axis, axis_t stop_axis) { - float *bv1 = node1->bv; - float *bv2 = node2->bv; + const float *bv1 = node1->bv; + const float *bv2 = node2->bv; - float *bv1_end = bv1 + (stop_axis << 1); + const float *bv1_end = bv1 + (stop_axis << 1); bv1 += start_axis << 1; bv2 += start_axis << 1; @@ -1045,7 +1043,7 @@ static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2) if (data->i >= data->max_overlap) { /* try to make alloc'ed memory bigger */ - data->overlap = realloc(data->overlap, sizeof(BVHTreeOverlap) * data->max_overlap * 2); + data->overlap = realloc(data->overlap, sizeof(BVHTreeOverlap) * (size_t)data->max_overlap * 2); if (!data->overlap) { printf("Out of Memory in traverse\n"); @@ -1099,13 +1097,13 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, unsigned int data = MEM_callocN(sizeof(BVHOverlapData *) * tree1->tree_type, "BVHOverlapData_star"); for (j = 0; j < tree1->tree_type; j++) { - data[j] = (BVHOverlapData *)MEM_callocN(sizeof(BVHOverlapData), "BVHOverlapData"); + data[j] = MEM_callocN(sizeof(BVHOverlapData), "BVHOverlapData"); /* init BVHOverlapData */ - data[j]->overlap = (BVHTreeOverlap *)malloc(sizeof(BVHTreeOverlap) * max_ii(tree1->totleaf, tree2->totleaf)); + data[j]->overlap = malloc(sizeof(BVHTreeOverlap) * (size_t)max_ii(tree1->totleaf, tree2->totleaf)); data[j]->tree1 = tree1; data[j]->tree2 = tree2; - data[j]->max_overlap = max_ii(tree1->totleaf, tree2->totleaf); + data[j]->max_overlap = (unsigned int)max_ii(tree1->totleaf, tree2->totleaf); data[j]->i = 0; data[j]->start_axis = min_axis(tree1->start_axis, tree2->start_axis); data[j]->stop_axis = min_axis(tree1->stop_axis, tree2->stop_axis); @@ -1119,7 +1117,7 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, unsigned int for (j = 0; j < tree1->tree_type; j++) total += data[j]->i; - to = overlap = (BVHTreeOverlap *)MEM_callocN(sizeof(BVHTreeOverlap) * total, "BVHTreeOverlap"); + to = overlap = MEM_callocN(sizeof(BVHTreeOverlap) * total, "BVHTreeOverlap"); for (j = 0; j < tree1->tree_type; j++) { memcpy(to, data[j]->overlap, data[j]->i * sizeof(BVHTreeOverlap)); diff --git a/source/blender/blenlib/intern/BLI_kdtree.c b/source/blender/blenlib/intern/BLI_kdtree.c index dd54fe681b0..57227dc5d5f 100644 --- a/source/blender/blenlib/intern/BLI_kdtree.c +++ b/source/blender/blenlib/intern/BLI_kdtree.c @@ -30,28 +30,37 @@ #include "BLI_math.h" #include "BLI_kdtree.h" #include "BLI_utildefines.h" +#include "BLI_strict_flags.h" typedef struct KDTreeNode { struct KDTreeNode *left, *right; float co[3], nor[3]; int index; - short d; + unsigned int d; /* range is only (0-2) */ } KDTreeNode; struct KDTree { KDTreeNode *nodes; - int totnode; + unsigned int totnode; KDTreeNode *root; }; -KDTree *BLI_kdtree_new(int maxsize) +#define KD_STACK_INIT 100 /* initial size for array (on the stack) */ +#define KD_NEAR_ALLOC_INC 100 /* alloc increment for collecting nearest */ +#define KD_FOUND_ALLOC_INC 50 /* alloc increment for collecting nearest */ + +/** + * Creates or free a kdtree + */ +KDTree *BLI_kdtree_new(unsigned int maxsize) { KDTree *tree; - tree = MEM_callocN(sizeof(KDTree), "KDTree"); - tree->nodes = MEM_callocN(sizeof(KDTreeNode) * maxsize, "KDTreeNode"); + tree = MEM_mallocN(sizeof(KDTree), "KDTree"); + tree->nodes = MEM_mallocN(sizeof(KDTreeNode) * maxsize, "KDTreeNode"); tree->totnode = 0; + tree->root = NULL; return tree; } @@ -64,20 +73,32 @@ void BLI_kdtree_free(KDTree *tree) } } +/** + * Construction: first insert points, then call balance. Normal is optional. + */ void BLI_kdtree_insert(KDTree *tree, int index, const float co[3], const float nor[3]) { KDTreeNode *node = &tree->nodes[tree->totnode++]; - node->index = index; + /* note, array isn't calloc'd, + * need to initialize all struct members */ + + node->left = node->right = NULL; copy_v3_v3(node->co, co); - if (nor) copy_v3_v3(node->nor, nor); + if (nor) + copy_v3_v3(node->nor, nor); + else + zero_v3(node->nor); + + node->index = index; + node->d = 0; } -static KDTreeNode *kdtree_balance(KDTreeNode *nodes, int totnode, int axis) +static KDTreeNode *kdtree_balance(KDTreeNode *nodes, unsigned int totnode, unsigned int axis) { KDTreeNode *node; float co; - int left, right, median, i, j; + unsigned int left, right, median, i, j; if (totnode <= 0) return NULL; @@ -98,7 +119,9 @@ static KDTreeNode *kdtree_balance(KDTreeNode *nodes, int totnode, int axis) while (nodes[++i].co[axis] < co) ; while (nodes[--j].co[axis] > co && j > left) ; - if (i >= j) break; + if (i >= j) + break; + SWAP(KDTreeNode, nodes[i], nodes[j]); } @@ -143,18 +166,33 @@ static float squared_distance(const float v2[3], const float v1[3], const float return dist; } -int BLI_kdtree_find_nearest(KDTree *tree, const float co[3], const float nor[3], KDTreeNearest *nearest) +static KDTreeNode **realloc_nodes(KDTreeNode **stack, unsigned int *totstack, const bool is_alloc) +{ + KDTreeNode **stack_new = MEM_mallocN((*totstack + KD_NEAR_ALLOC_INC) * sizeof(KDTreeNode *), "KDTree.treestack"); + memcpy(stack_new, stack, *totstack * sizeof(KDTreeNode *)); + // memset(stack_new + *totstack, 0, sizeof(KDTreeNode *) * KD_NEAR_ALLOC_INC); + if (is_alloc) + MEM_freeN(stack); + *totstack += KD_NEAR_ALLOC_INC; + return stack_new; +} + +/** + * Find nearest returns index, and -1 if no node is found. + */ +int BLI_kdtree_find_nearest(KDTree *tree, const float co[3], const float nor[3], + KDTreeNearest *r_nearest) { KDTreeNode *root, *node, *min_node; - KDTreeNode **stack, *defaultstack[100]; + KDTreeNode **stack, *defaultstack[KD_STACK_INIT]; float min_dist, cur_dist; - int totstack, cur = 0; + unsigned int totstack, cur = 0; if (!tree->root) return -1; stack = defaultstack; - totstack = 100; + totstack = KD_STACK_INIT; root = tree->root; min_node = root; @@ -208,20 +246,15 @@ int BLI_kdtree_find_nearest(KDTree *tree, const float co[3], const float nor[3], if (node->left) stack[cur++] = node->left; } - if (cur + 3 > totstack) { - KDTreeNode **temp = MEM_callocN((totstack + 100) * sizeof(KDTreeNode *), "psys_treestack"); - memcpy(temp, stack, totstack * sizeof(KDTreeNode *)); - if (stack != defaultstack) - MEM_freeN(stack); - stack = temp; - totstack += 100; + if (UNLIKELY(cur + 3 > totstack)) { + stack = realloc_nodes(stack, &totstack, defaultstack != stack); } } - if (nearest) { - nearest->index = min_node->index; - nearest->dist = sqrt(min_dist); - copy_v3_v3(nearest->co, min_node->co); + if (r_nearest) { + r_nearest->index = min_node->index; + r_nearest->dist = sqrtf(min_dist); + copy_v3_v3(r_nearest->co, min_node->co); } if (stack != defaultstack) @@ -230,9 +263,10 @@ int BLI_kdtree_find_nearest(KDTree *tree, const float co[3], const float nor[3], return min_node->index; } -static void add_nearest(KDTreeNearest *ptn, int *found, int n, int index, float dist, float *co) +static void add_nearest(KDTreeNearest *ptn, unsigned int *found, unsigned int n, int index, + float dist, const float *co) { - int i; + unsigned int i; if (*found < n) (*found)++; @@ -248,24 +282,32 @@ static void add_nearest(KDTreeNearest *ptn, int *found, int n, int index, float copy_v3_v3(ptn[i].co, co); } -/* finds the nearest n entries in tree to specified coordinates */ -int BLI_kdtree_find_n_nearest(KDTree *tree, int n, const float co[3], const float nor[3], KDTreeNearest *nearest) +/** + * Find n nearest returns number of points found, with results in nearest. + * Normal is optional, but if given will limit results to points in normal direction from co. + * + * \param r_nearest An array of nearest, sized at least \a n. + */ +int BLI_kdtree_find_nearest_n(KDTree *tree, const float co[3], const float nor[3], + KDTreeNearest r_nearest[], + unsigned int n) { KDTreeNode *root, *node = NULL; - KDTreeNode **stack, *defaultstack[100]; + KDTreeNode **stack, *defaultstack[KD_STACK_INIT]; float cur_dist; - int i, totstack, cur = 0, found = 0; + unsigned int totstack, cur = 0; + unsigned int i, found = 0; - if (!tree->root) + if (!tree->root || n == 0) return 0; stack = defaultstack; - totstack = 100; + totstack = KD_STACK_INIT; root = tree->root; cur_dist = squared_distance(root->co, co, root->nor, nor); - add_nearest(nearest, &found, n, root->index, cur_dist, root->co); + add_nearest(r_nearest, &found, n, root->index, cur_dist, root->co); if (co[root->d] < root->co[root->d]) { if (root->right) @@ -288,11 +330,11 @@ int BLI_kdtree_find_n_nearest(KDTree *tree, int n, const float co[3], const floa if (cur_dist < 0.0f) { cur_dist = -cur_dist * cur_dist; - if (found < n || -cur_dist < nearest[found - 1].dist) { + if (found < n || -cur_dist < r_nearest[found - 1].dist) { cur_dist = squared_distance(node->co, co, node->nor, nor); - if (found < n || cur_dist < nearest[found - 1].dist) - add_nearest(nearest, &found, n, node->index, cur_dist, node->co); + if (found < n || cur_dist < r_nearest[found - 1].dist) + add_nearest(r_nearest, &found, n, node->index, cur_dist, node->co); if (node->left) stack[cur++] = node->left; @@ -303,10 +345,10 @@ int BLI_kdtree_find_n_nearest(KDTree *tree, int n, const float co[3], const floa else { cur_dist = cur_dist * cur_dist; - if (found < n || cur_dist < nearest[found - 1].dist) { + if (found < n || cur_dist < r_nearest[found - 1].dist) { cur_dist = squared_distance(node->co, co, node->nor, nor); - if (found < n || cur_dist < nearest[found - 1].dist) - add_nearest(nearest, &found, n, node->index, cur_dist, node->co); + if (found < n || cur_dist < r_nearest[found - 1].dist) + add_nearest(r_nearest, &found, n, node->index, cur_dist, node->co); if (node->right) stack[cur++] = node->right; @@ -314,23 +356,18 @@ int BLI_kdtree_find_n_nearest(KDTree *tree, int n, const float co[3], const floa if (node->left) stack[cur++] = node->left; } - if (cur + 3 > totstack) { - KDTreeNode **temp = MEM_callocN((totstack + 100) * sizeof(KDTreeNode *), "psys_treestack"); - memcpy(temp, stack, totstack * sizeof(KDTreeNode *)); - if (stack != defaultstack) - MEM_freeN(stack); - stack = temp; - totstack += 100; + if (UNLIKELY(cur + 3 > totstack)) { + stack = realloc_nodes(stack, &totstack, defaultstack != stack); } } for (i = 0; i < found; i++) - nearest[i].dist = sqrt(nearest[i].dist); + r_nearest[i].dist = sqrtf(r_nearest[i].dist); if (stack != defaultstack) MEM_freeN(stack); - return found; + return (int)found; } static int range_compare(const void *a, const void *b) @@ -345,38 +382,45 @@ static int range_compare(const void *a, const void *b) else return 0; } -static void add_in_range(KDTreeNearest **ptn, int found, int *totfoundstack, int index, float dist, float *co) +static void add_in_range(KDTreeNearest **ptn, unsigned int found, unsigned int *totfoundstack, int index, float dist, float *co) { KDTreeNearest *to; if (found >= *totfoundstack) { - KDTreeNearest *temp = MEM_callocN((*totfoundstack + 50) * sizeof(KDTreeNode), "psys_treefoundstack"); + KDTreeNearest *temp = MEM_mallocN((*totfoundstack + KD_FOUND_ALLOC_INC) * sizeof(KDTreeNode), "KDTree.treefoundstack"); memcpy(temp, *ptn, *totfoundstack * sizeof(KDTreeNearest)); if (*ptn) MEM_freeN(*ptn); *ptn = temp; - *totfoundstack += 50; + *totfoundstack += KD_FOUND_ALLOC_INC; } to = (*ptn) + found; to->index = index; - to->dist = sqrt(dist); + to->dist = sqrtf(dist); copy_v3_v3(to->co, co); } -int BLI_kdtree_range_search(KDTree *tree, float range, const float co[3], const float nor[3], KDTreeNearest **nearest) + +/** + * Range search returns number of points found, with results in nearest + * Normal is optional, but if given will limit results to points in normal direction from co. + * Remember to free nearest after use! + */ +int BLI_kdtree_range_search(KDTree *tree, const float co[3], const float nor[3], + KDTreeNearest **r_nearest, float range) { KDTreeNode *root, *node = NULL; - KDTreeNode **stack, *defaultstack[100]; + KDTreeNode **stack, *defaultstack[KD_STACK_INIT]; KDTreeNearest *foundstack = NULL; float range2 = range * range, dist2; - int totstack, cur = 0, found = 0, totfoundstack = 0; + unsigned int totstack, cur = 0, found = 0, totfoundstack = 0; if (!tree || !tree->root) return 0; stack = defaultstack; - totstack = 100; + totstack = KD_STACK_INIT; root = tree->root; @@ -421,13 +465,8 @@ int BLI_kdtree_range_search(KDTree *tree, float range, const float co[3], const stack[cur++] = node->right; } - if (cur + 3 > totstack) { - KDTreeNode **temp = MEM_callocN((totstack + 100) * sizeof(KDTreeNode *), "psys_treestack"); - memcpy(temp, stack, totstack * sizeof(KDTreeNode *)); - if (stack != defaultstack) - MEM_freeN(stack); - stack = temp; - totstack += 100; + if (UNLIKELY(cur + 3 > totstack)) { + stack = realloc_nodes(stack, &totstack, defaultstack != stack); } } @@ -437,7 +476,7 @@ int BLI_kdtree_range_search(KDTree *tree, float range, const float co[3], const if (found) qsort(foundstack, found, sizeof(KDTreeNearest), range_compare); - *nearest = foundstack; + *r_nearest = foundstack; - return found; + return (int)found; } diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c index b08fbe17a43..66fcfd21fbb 100644 --- a/source/blender/blenlib/intern/BLI_linklist.c +++ b/source/blender/blenlib/intern/BLI_linklist.c @@ -34,6 +34,7 @@ #include "MEM_guardedalloc.h" #include "BLI_linklist.h" #include "BLI_memarena.h" +#include "BLI_mempool.h" int BLI_linklist_length(LinkNode *list) { @@ -88,18 +89,39 @@ void BLI_linklist_reverse(LinkNode **listp) *listp = rhead; } -void BLI_linklist_prepend(LinkNode **listp, void *ptr) +/** + * A version of prepend that takes the allocated link. + */ +void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink) { - LinkNode *nlink = MEM_mallocN(sizeof(*nlink), "nlink"); nlink->link = ptr; - nlink->next = *listp; *listp = nlink; } -void BLI_linklist_append(LinkNode **listp, void *ptr) +void BLI_linklist_prepend(LinkNode **listp, void *ptr) { LinkNode *nlink = MEM_mallocN(sizeof(*nlink), "nlink"); + BLI_linklist_prepend_nlink(listp, ptr, nlink); +} + +void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, MemArena *ma) +{ + LinkNode *nlink = BLI_memarena_alloc(ma, sizeof(*nlink)); + BLI_linklist_prepend_nlink(listp, ptr, nlink); +} + +void BLI_linklist_prepend_pool(LinkNode **listp, void *ptr, BLI_mempool *mempool) +{ + LinkNode *nlink = BLI_mempool_alloc(mempool); + BLI_linklist_prepend_nlink(listp, ptr, nlink); +} + +/** + * A version of append that takes the allocated link. + */ +void BLI_linklist_append_nlink(LinkNode **listp, void *ptr, LinkNode *nlink) +{ LinkNode *node = *listp; nlink->link = ptr; @@ -116,13 +138,46 @@ void BLI_linklist_append(LinkNode **listp, void *ptr) } } -void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, MemArena *ma) +void BLI_linklist_append(LinkNode **listp, void *ptr) +{ + LinkNode *nlink = MEM_mallocN(sizeof(*nlink), "nlink"); + BLI_linklist_append_nlink(listp, ptr, nlink); +} + +void BLI_linklist_append_arena(LinkNode **listp, void *ptr, MemArena *ma) { LinkNode *nlink = BLI_memarena_alloc(ma, sizeof(*nlink)); - nlink->link = ptr; - - nlink->next = *listp; - *listp = nlink; + BLI_linklist_append_nlink(listp, ptr, nlink); +} + +void BLI_linklist_append_pool(LinkNode **listp, void *ptr, BLI_mempool *mempool) +{ + LinkNode *nlink = BLI_mempool_alloc(mempool); + BLI_linklist_append_nlink(listp, ptr, nlink); +} + +void *BLI_linklist_pop(struct LinkNode **listp) +{ + /* intentionally no NULL check */ + void *link = (*listp)->link; + void *next = (*listp)->next; + + MEM_freeN((*listp)); + + *listp = next; + return link; +} + +void *BLI_linklist_pop_pool(struct LinkNode **listp, struct BLI_mempool *mempool) +{ + /* intentionally no NULL check */ + void *link = (*listp)->link; + void *next = (*listp)->next; + + BLI_mempool_free(mempool, (*listp)); + + *listp = next; + return link; } void BLI_linklist_insert_after(LinkNode **listp, void *ptr) @@ -155,6 +210,19 @@ void BLI_linklist_free(LinkNode *list, LinkNodeFreeFP freefunc) } } +void BLI_linklist_free_pool(LinkNode *list, LinkNodeFreeFP freefunc, struct BLI_mempool *mempool) +{ + while (list) { + LinkNode *next = list->next; + + if (freefunc) + freefunc(list->link); + BLI_mempool_free(mempool, list); + + list = next; + } +} + void BLI_linklist_freeN(LinkNode *list) { while (list) { diff --git a/source/blender/blenlib/intern/BLI_memarena.c b/source/blender/blenlib/intern/BLI_memarena.c index ef10cb805ad..4a6712201a9 100644 --- a/source/blender/blenlib/intern/BLI_memarena.c +++ b/source/blender/blenlib/intern/BLI_memarena.c @@ -30,17 +30,16 @@ * \ingroup bli */ +#include <string.h> + #include "MEM_guardedalloc.h" #include "BLI_memarena.h" #include "BLI_linklist.h" +#include "BLI_strict_flags.h" -#ifdef __GNUC__ -# pragma GCC diagnostic error "-Wsign-conversion" -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 /* gcc4.6+ only */ -# pragma GCC diagnostic error "-Wsign-compare" -# pragma GCC diagnostic error "-Wconversion" -# endif +#ifdef WITH_MEM_VALGRIND +# include "valgrind/memcheck.h" #endif struct MemArena { @@ -61,6 +60,10 @@ MemArena *BLI_memarena_new(const int bufsize, const char *name) ma->align = 8; ma->name = name; +#ifdef WITH_MEM_VALGRIND + VALGRIND_CREATE_MEMPOOL(ma, 0, false); +#endif + return ma; } @@ -83,12 +86,27 @@ void BLI_memarena_use_align(struct MemArena *ma, const int align) void BLI_memarena_free(MemArena *ma) { BLI_linklist_freeN(ma->bufs); + +#ifdef WITH_MEM_VALGRIND + VALGRIND_DESTROY_MEMPOOL(ma); +#endif + MEM_freeN(ma); } /* amt must be power of two */ #define PADUP(num, amt) (((num) + ((amt) - 1)) & ~((amt) - 1)) +/* align alloc'ed memory (needed if align > 8) */ +static void memarena_curbuf_align(MemArena *ma) +{ + unsigned char *tmp; + + tmp = (unsigned char *)PADUP( (intptr_t) ma->curbuf, ma->align); + ma->cursize -= (int)(tmp - ma->curbuf); + ma->curbuf = tmp; +} + void *BLI_memarena_alloc(MemArena *ma, int size) { void *ptr; @@ -98,8 +116,6 @@ void *BLI_memarena_alloc(MemArena *ma, int size) size = PADUP(size, ma->align); if (size > ma->cursize) { - unsigned char *tmp; - if (size > ma->bufsize - (ma->align - 1)) { ma->cursize = PADUP(size + 1, ma->align); } @@ -112,16 +128,51 @@ void *BLI_memarena_alloc(MemArena *ma, int size) ma->curbuf = MEM_mallocN((size_t)ma->cursize, ma->name); BLI_linklist_prepend(&ma->bufs, ma->curbuf); - - /* align alloc'ed memory (needed if align > 8) */ - tmp = (unsigned char *)PADUP( (intptr_t) ma->curbuf, ma->align); - ma->cursize -= (int)(tmp - ma->curbuf); - ma->curbuf = tmp; + memarena_curbuf_align(ma); } ptr = ma->curbuf; ma->curbuf += size; ma->cursize -= size; +#ifdef WITH_MEM_VALGRIND + VALGRIND_MEMPOOL_ALLOC(ma, ptr, size); +#endif + return ptr; } + +/** + * Clear for reuse, avoids re-allocation when an arena may + * otherwise be free'd and recreated. + */ +void BLI_memarena_clear(MemArena *ma) +{ + if (ma->bufs) { + unsigned char *curbuf_prev; + int curbuf_used; + + if (ma->bufs->next) { + BLI_linklist_freeN(ma->bufs->next); + ma->bufs->next = NULL; + } + + curbuf_prev = ma->curbuf; + ma->curbuf = ma->bufs->link; + memarena_curbuf_align(ma); + + /* restore to original size */ + curbuf_used = (int)(curbuf_prev - ma->curbuf); + ma->cursize += curbuf_used; + + if (ma->use_calloc) { + memset(ma->curbuf, 0, (size_t)curbuf_used); + } + } + +#ifdef WITH_MEM_VALGRIND + VALGRIND_DESTROY_MEMPOOL(ma); + VALGRIND_CREATE_MEMPOOL(ma, 0, false); +#endif + +} diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c index bb326a23d59..261e53f0f55 100644 --- a/source/blender/blenlib/intern/BLI_mempool.c +++ b/source/blender/blenlib/intern/BLI_mempool.c @@ -31,6 +31,9 @@ * Simple, fast memory allocator for allocating many elements of the same size. */ +#include <string.h> +#include <stdlib.h> + #include "BLI_utildefines.h" #include "BLI_listbase.h" @@ -40,15 +43,10 @@ #include "MEM_guardedalloc.h" -#include <string.h> -#include <stdlib.h> +#include "BLI_strict_flags.h" /* keep last */ -#ifdef __GNUC__ -# pragma GCC diagnostic error "-Wsign-conversion" -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 /* gcc4.6+ only */ -# pragma GCC diagnostic error "-Wsign-compare" -# pragma GCC diagnostic error "-Wconversion" -# endif +#ifdef WITH_MEM_VALGRIND +# include "valgrind/memcheck.h" #endif /* note: copied from BLO_blend_defs.h, don't use here because we're in BLI */ @@ -65,37 +63,185 @@ /* currently totalloc isnt used */ // #define USE_TOTALLOC +/* when undefined, merge the allocs for BLI_mempool_chunk and its data */ +// #define USE_DATA_PTR + +#ifndef NDEBUG +static bool mempool_debug_memset = false; +#endif + +/** + * A free element from #BLI_mempool_chunk. Data is cast to this type and stored in + * #BLI_mempool.free as a single linked list, each item #BLI_mempool.esize large. + * + * Each element represents a block which BLI_mempool_alloc may return. + */ typedef struct BLI_freenode { struct BLI_freenode *next; int freeword; /* used to identify this as a freed node */ } BLI_freenode; +/** + * A chunk of memory in the mempool stored in + * #BLI_mempool.chunks as a double linked list. + */ typedef struct BLI_mempool_chunk { struct BLI_mempool_chunk *next, *prev; - void *data; +#ifdef USE_DATA_PTR + void *_data; +#endif } BLI_mempool_chunk; +/** + * The mempool, stores and tracks memory \a chunks and elements within those chunks \a free. + */ struct BLI_mempool { struct ListBase chunks; - int esize; /* element size in bytes */ - int csize; /* chunk size in bytes */ - int pchunk; /* number of elements per chunk */ - int flag; + unsigned int esize; /* element size in bytes */ + unsigned int csize; /* chunk size in bytes */ + unsigned int pchunk; /* number of elements per chunk */ + unsigned int flag; /* keeps aligned to 16 bits */ - BLI_freenode *free; /* free element list. Interleaved into chunk datas. */ - int totalloc, totused; /* total number of elements allocated in total, - * and currently in use */ + BLI_freenode *free; /* free element list. Interleaved into chunk datas. */ + unsigned int maxchunks; /* use to know how many chunks to keep for BLI_mempool_clear */ + unsigned int totused; /* number of elements currently in use */ +#ifdef USE_TOTALLOC + unsigned int totalloc; /* number of elements allocated in total */ +#endif }; #define MEMPOOL_ELEM_SIZE_MIN (sizeof(void *) * 2) -BLI_mempool *BLI_mempool_create(int esize, int totelem, int pchunk, int flag) +#ifdef USE_DATA_PTR +# define CHUNK_DATA(chunk) (chunk)->_data +#else +# define CHUNK_DATA(chunk) (CHECK_TYPE_INLINE(chunk, BLI_mempool_chunk *), (void *)((chunk) + 1)) +#endif + +/** + * \return the number of chunks to allocate based on how many elements are needed. + */ +BLI_INLINE unsigned int mempool_maxchunks(const unsigned int totelem, const unsigned int pchunk) { - BLI_mempool *pool = NULL; - BLI_freenode *lasttail = NULL, *curnode = NULL; - int i, j, maxchunks; + return totelem / pchunk + 1; +} + +static BLI_mempool_chunk *mempool_chunk_alloc(BLI_mempool *pool) +{ + BLI_mempool_chunk *mpchunk; +#ifdef USE_DATA_PTR + if (pool->flag & BLI_MEMPOOL_SYSMALLOC) { + mpchunk = malloc(sizeof(BLI_mempool_chunk)); + CHUNK_DATA(mpchunk) = malloc((size_t)pool->csize); + } + else { + mpchunk = MEM_mallocN(sizeof(BLI_mempool_chunk), "BLI_Mempool Chunk"); + CHUNK_DATA(mpchunk) = MEM_mallocN((size_t)pool->csize, "BLI Mempool Chunk Data"); + } +#else + if (pool->flag & BLI_MEMPOOL_SYSMALLOC) { + mpchunk = malloc(sizeof(BLI_mempool_chunk) + (size_t)pool->csize); + } + else { + mpchunk = MEM_mallocN(sizeof(BLI_mempool_chunk) + (size_t)pool->csize, "BLI_Mempool Chunk"); + } +#endif + + return mpchunk; +} + +/** + * Initialize a chunk and add into \a pool->chunks + * + * \param pool The pool to add the chunk into. + * \param mpchunk The new uninitialized chunk (can be malloc'd) + * \param lasttail The last element of the previous chunk + * (used when building free chunks initially) + * \return The last chunk, + */ +static BLI_freenode *mempool_chunk_add(BLI_mempool *pool, BLI_mempool_chunk *mpchunk, + BLI_freenode *lasttail) +{ + BLI_freenode *curnode = NULL; + const unsigned int pchunk_last = pool->pchunk - 1; char *addr; + unsigned int j; + + mpchunk->next = mpchunk->prev = NULL; + BLI_addtail(&(pool->chunks), mpchunk); + + if (pool->free == NULL) { + pool->free = CHUNK_DATA(mpchunk); /* start of the list */ + if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) { + pool->free->freeword = FREEWORD; + } + } + + /* loop through the allocated data, building the pointer structures */ + for (addr = CHUNK_DATA(mpchunk), j = 0; j != pchunk_last; j++) { + curnode = ((BLI_freenode *)addr); + addr += pool->esize; + curnode->next = (BLI_freenode *)addr; + if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) { + if (j != pchunk_last) + curnode->next->freeword = FREEWORD; + curnode->freeword = FREEWORD; + } + } + + /* terminate the list, + * will be overwritten if 'curnode' gets passed in again as 'lasttail' */ + curnode->next = NULL; + +#ifdef USE_TOTALLOC + pool->totalloc += pool->pchunk; +#endif + + /* final pointer in the previously allocated chunk is wrong */ + if (lasttail) { + lasttail->next = CHUNK_DATA(mpchunk); + if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) { + lasttail->freeword = FREEWORD; + } + } + + return curnode; +} + +static void mempool_chunk_free(BLI_mempool_chunk *mpchunk, const unsigned int flag) +{ + if (flag & BLI_MEMPOOL_SYSMALLOC) { +#ifdef USE_DATA_PTR + free(CHUNK_DATA(mpchunk)); +#endif + free(mpchunk); + } + else { +#ifdef USE_DATA_PTR + MEM_freeN(CHUNK_DATA(mpchunk)); +#endif + MEM_freeN(mpchunk); + } +} + +static void mempool_chunk_free_all(ListBase *chunks, const unsigned int flag) +{ + BLI_mempool_chunk *mpchunk, *mpchunk_next; + + for (mpchunk = chunks->first; mpchunk; mpchunk = mpchunk_next) { + mpchunk_next = mpchunk->next; + mempool_chunk_free(mpchunk, flag); + } + chunks->first = chunks->last = NULL; +} + +BLI_mempool *BLI_mempool_create(unsigned int esize, unsigned int totelem, + unsigned int pchunk, unsigned int flag) +{ + BLI_mempool *pool = NULL; + BLI_freenode *lasttail = NULL; + unsigned int i, maxchunks; /* allocate the pool structure */ if (flag & BLI_MEMPOOL_SYSMALLOC) { @@ -117,68 +263,29 @@ BLI_mempool *BLI_mempool_create(int esize, int totelem, int pchunk, int flag) pool->esize = esize; } + maxchunks = mempool_maxchunks(totelem, pchunk); + pool->flag = flag; pool->pchunk = pchunk; pool->csize = esize * pchunk; pool->chunks.first = pool->chunks.last = NULL; + pool->free = NULL; /* mempool_chunk_add assigns */ + pool->maxchunks = maxchunks; +#ifdef USE_TOTALLOC pool->totalloc = 0; +#endif pool->totused = 0; - maxchunks = totelem / pchunk + 1; - if (maxchunks == 0) { - maxchunks = 1; - } - /* allocate the actual chunks */ for (i = 0; i < maxchunks; i++) { - BLI_mempool_chunk *mpchunk; - - if (flag & BLI_MEMPOOL_SYSMALLOC) { - mpchunk = malloc(sizeof(BLI_mempool_chunk)); - mpchunk->data = malloc((size_t)pool->csize); - } - else { - mpchunk = MEM_mallocN(sizeof(BLI_mempool_chunk), "BLI_Mempool Chunk"); - mpchunk->data = MEM_mallocN((size_t)pool->csize, "BLI Mempool Chunk Data"); - } - - mpchunk->next = mpchunk->prev = NULL; - BLI_addtail(&(pool->chunks), mpchunk); - - if (i == 0) { - pool->free = mpchunk->data; /* start of the list */ - if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) { - pool->free->freeword = FREEWORD; - } - } - - /* loop through the allocated data, building the pointer structures */ - for (addr = mpchunk->data, j = 0; j < pool->pchunk; j++) { - curnode = ((BLI_freenode *)addr); - addr += pool->esize; - curnode->next = (BLI_freenode *)addr; - if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) { - if (j != pool->pchunk - 1) - curnode->next->freeword = FREEWORD; - curnode->freeword = FREEWORD; - } - } - /* final pointer in the previously allocated chunk is wrong */ - if (lasttail) { - lasttail->next = mpchunk->data; - if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) { - lasttail->freeword = FREEWORD; - } - } + BLI_mempool_chunk *mpchunk = mempool_chunk_alloc(pool); + lasttail = mempool_chunk_add(pool, mpchunk, lasttail); + } - /* set the end of this chunks memory to the new tail for next iteration */ - lasttail = curnode; -#ifdef USE_TOTALLOC - pool->totalloc += pool->pchunk; +#ifdef WITH_MEM_VALGRIND + VALGRIND_CREATE_MEMPOOL(pool, 0, false); #endif - } - /* terminate the list */ - curnode->next = NULL; + return pool; } @@ -189,46 +296,9 @@ void *BLI_mempool_alloc(BLI_mempool *pool) pool->totused++; if (!(pool->free)) { - BLI_freenode *curnode = NULL; - char *addr; - int j; - /* need to allocate a new chunk */ - BLI_mempool_chunk *mpchunk; - - if (pool->flag & BLI_MEMPOOL_SYSMALLOC) { - mpchunk = malloc(sizeof(BLI_mempool_chunk)); - mpchunk->data = malloc((size_t)pool->csize); - } - else { - mpchunk = MEM_mallocN(sizeof(BLI_mempool_chunk), "BLI_Mempool Chunk"); - mpchunk->data = MEM_mallocN((size_t)pool->csize, "BLI_Mempool Chunk Data"); - } - - mpchunk->next = mpchunk->prev = NULL; - BLI_addtail(&(pool->chunks), mpchunk); - - pool->free = mpchunk->data; /* start of the list */ - - if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) { - pool->free->freeword = FREEWORD; - } - - for (addr = mpchunk->data, j = 0; j < pool->pchunk; j++) { - curnode = ((BLI_freenode *)addr); - addr += pool->esize; - curnode->next = (BLI_freenode *)addr; - - if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) { - curnode->freeword = FREEWORD; - if (j != pool->pchunk - 1) - curnode->next->freeword = FREEWORD; - } - } - curnode->next = NULL; /* terminate the list */ -#ifdef USE_TOTALLOC - pool->totalloc += pool->pchunk; -#endif + BLI_mempool_chunk *mpchunk = mempool_chunk_alloc(pool); + mempool_chunk_add(pool, mpchunk, NULL); } retval = pool->free; @@ -238,7 +308,11 @@ void *BLI_mempool_alloc(BLI_mempool *pool) } pool->free = pool->free->next; - //memset(retval, 0, pool->esize); + +#ifdef WITH_MEM_VALGRIND + VALGRIND_MEMPOOL_ALLOC(pool, retval, pool->esize); +#endif + return retval; } @@ -258,6 +332,27 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr) { BLI_freenode *newhead = addr; +#ifndef NDEBUG + { + BLI_mempool_chunk *chunk; + bool found = false; + for (chunk = pool->chunks.first; chunk; chunk = chunk->next) { + if (ARRAY_HAS_ITEM((char *)addr, (char *)CHUNK_DATA(chunk), pool->csize)) { + found = true; + break; + } + } + if (!found) { + BLI_assert(!"Attempt to free data which is not in pool.\n"); + } + } + + /* enable for debugging */ + if (UNLIKELY(mempool_debug_memset)) { + memset(addr, 255, pool->esize); + } +#endif + if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) { #ifndef NDEBUG /* this will detect double free's */ @@ -271,55 +366,52 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr) pool->totused--; +#ifdef WITH_MEM_VALGRIND + VALGRIND_MEMPOOL_FREE(pool, addr); +#endif + /* nothing is in use; free all the chunks except the first */ - if (pool->totused == 0) { + if (UNLIKELY(pool->totused == 0)) { BLI_freenode *curnode = NULL; char *tmpaddr = NULL; - int i; - - BLI_mempool_chunk *mpchunk = NULL; - BLI_mempool_chunk *first = pool->chunks.first; - - BLI_remlink(&pool->chunks, first); - - if (pool->flag & BLI_MEMPOOL_SYSMALLOC) { - for (mpchunk = pool->chunks.first; mpchunk; mpchunk = mpchunk->next) { - free(mpchunk->data); - } - BLI_freelist(&(pool->chunks)); - } - else { - for (mpchunk = pool->chunks.first; mpchunk; mpchunk = mpchunk->next) { - MEM_freeN(mpchunk->data); - } - BLI_freelistN(&(pool->chunks)); - } + unsigned int i; + BLI_mempool_chunk *first; + first = BLI_pophead(&pool->chunks); + mempool_chunk_free_all(&pool->chunks, pool->flag); BLI_addtail(&pool->chunks, first); #ifdef USE_TOTALLOC pool->totalloc = pool->pchunk; #endif - pool->free = first->data; /* start of the list */ - for (tmpaddr = first->data, i = 0; i < pool->pchunk; i++) { + /* temp alloc so valgrind doesn't complain when setting free'd blocks 'next' */ +#ifdef WITH_MEM_VALGRIND + VALGRIND_MEMPOOL_ALLOC(pool, CHUNK_DATA(first), pool->csize); +#endif + pool->free = CHUNK_DATA(first); /* start of the list */ + for (tmpaddr = CHUNK_DATA(first), i = 0; i < pool->pchunk; i++) { curnode = ((BLI_freenode *)tmpaddr); tmpaddr += pool->esize; curnode->next = (BLI_freenode *)tmpaddr; } curnode->next = NULL; /* terminate the list */ + +#ifdef WITH_MEM_VALGRIND + VALGRIND_MEMPOOL_FREE(pool, CHUNK_DATA(first)); +#endif } } int BLI_mempool_count(BLI_mempool *pool) { - return pool->totused; + return (int)pool->totused; } -void *BLI_mempool_findelem(BLI_mempool *pool, int index) +void *BLI_mempool_findelem(BLI_mempool *pool, unsigned int index) { BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER); - if ((index >= 0) && (index < pool->totused)) { + if (index < pool->totused) { /* we could have some faster mem chunk stepping code inline */ BLI_mempool_iter iter; void *elem; @@ -337,6 +429,7 @@ void *BLI_mempool_findelem(BLI_mempool *pool, int index) * Fill in \a data with pointers to each element of the mempool, * to create lookup table. * + * \param pool Pool to create a table from. * \param data array of pointers at least the size of 'pool->totused' */ void BLI_mempool_as_table(BLI_mempool *pool, void **data) @@ -349,7 +442,7 @@ void BLI_mempool_as_table(BLI_mempool *pool, void **data) while ((elem = BLI_mempool_iterstep(&iter))) { *p++ = elem; } - BLI_assert((p - data) == pool->totused); + BLI_assert((unsigned int)(p - data) == pool->totused); } /** @@ -375,7 +468,7 @@ void BLI_mempool_as_array(BLI_mempool *pool, void *data) memcpy(p, elem, (size_t)pool->esize); p += pool->esize; } - BLI_assert((p - (char *)data) == pool->totused * pool->esize); + BLI_assert((unsigned int)(p - (char *)data) == pool->totused * pool->esize); } /** @@ -388,6 +481,9 @@ void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr) return data; } +/** + * Create a new mempool iterator, \a BLI_MEMPOOL_ALLOW_ITER flag must be set. + */ void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) { BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER); @@ -406,11 +502,11 @@ static void *bli_mempool_iternext(BLI_mempool_iter *iter) if (!iter->curchunk || !iter->pool->totused) return NULL; - ret = ((char *)iter->curchunk->data) + iter->pool->esize * iter->curindex; + ret = ((char *)CHUNK_DATA(iter->curchunk)) + (iter->pool->esize * iter->curindex); iter->curindex++; - if (iter->curindex >= iter->pool->pchunk) { + if (iter->curindex == iter->pool->pchunk) { iter->curchunk = iter->curchunk->next; iter->curindex = 0; } @@ -433,23 +529,22 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter) /* optimized version of code above */ +/** + * Step over the iterator, returning the mempool item or NULL. + */ void *BLI_mempool_iterstep(BLI_mempool_iter *iter) { BLI_freenode *ret; - if (UNLIKELY(iter->pool->totused == 0)) { - return NULL; - } - do { if (LIKELY(iter->curchunk)) { - ret = (BLI_freenode *)(((char *)iter->curchunk->data) + iter->pool->esize * iter->curindex); + ret = (BLI_freenode *)(((char *)CHUNK_DATA(iter->curchunk)) + (iter->pool->esize * iter->curindex)); } else { return NULL; } - if (UNLIKELY(++iter->curindex >= iter->pool->pchunk)) { + if (UNLIKELY(++iter->curindex == iter->pool->pchunk)) { iter->curindex = 0; iter->curchunk = iter->curchunk->next; } @@ -461,27 +556,85 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter) #endif /** + * Empty the pool, as if it were just created. + * + * \param pool The pool to clear. + * \param totelem_reserve Optionally reserve how many items should be kept from clearing. + */ +void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve) +{ + BLI_mempool_chunk *mpchunk; + BLI_mempool_chunk *mpchunk_next; + unsigned int maxchunks; + + ListBase chunks_temp; + BLI_freenode *lasttail = NULL; + +#ifdef WITH_MEM_VALGRIND + VALGRIND_DESTROY_MEMPOOL(pool); + VALGRIND_CREATE_MEMPOOL(pool, 0, false); +#endif + + if (totelem_reserve == -1) { + maxchunks = pool->maxchunks; + } + else { + maxchunks = mempool_maxchunks((unsigned int)totelem_reserve, pool->pchunk); + } + + /* free all after pool->maxchunks */ + + for (mpchunk = BLI_findlink(&pool->chunks, (int)maxchunks); mpchunk; mpchunk = mpchunk_next) { + mpchunk_next = mpchunk->next; + BLI_remlink(&pool->chunks, mpchunk); + mempool_chunk_free(mpchunk, pool->flag); + } + + /* re-initialize */ + pool->free = NULL; + pool->totused = 0; +#ifdef USE_TOTALLOC + pool->totalloc = 0; +#endif + + chunks_temp = pool->chunks; + pool->chunks.first = pool->chunks.last = NULL; + + while ((mpchunk = BLI_pophead(&chunks_temp))) { + lasttail = mempool_chunk_add(pool, mpchunk, lasttail); + } +} + +/** + * Wrap #BLI_mempool_clear_ex with no reserve set. + */ +void BLI_mempool_clear(BLI_mempool *pool) +{ + BLI_mempool_clear_ex(pool, -1); +} + +/** * Free the mempool its self (and all elements). */ void BLI_mempool_destroy(BLI_mempool *pool) { - BLI_mempool_chunk *mpchunk = NULL; - BLI_mempool_chunk *mpchunk_next; + mempool_chunk_free_all(&pool->chunks, pool->flag); + +#ifdef WITH_MEM_VALGRIND + VALGRIND_DESTROY_MEMPOOL(pool); +#endif if (pool->flag & BLI_MEMPOOL_SYSMALLOC) { - for (mpchunk = pool->chunks.first; mpchunk; mpchunk = mpchunk_next) { - mpchunk_next = mpchunk->next; - free(mpchunk->data); - free(mpchunk); - } free(pool); } else { - for (mpchunk = pool->chunks.first; mpchunk; mpchunk = mpchunk_next) { - mpchunk_next = mpchunk->next; - MEM_freeN(mpchunk->data); - MEM_freeN(mpchunk); - } MEM_freeN(pool); } } + +#ifndef NDEBUG +void BLI_mempool_set_memory_debug(void) +{ + mempool_debug_memset = true; +} +#endif diff --git a/source/blender/blenlib/intern/boxpack2d.c b/source/blender/blenlib/intern/boxpack2d.c index 8a97fdcab67..8707be46196 100644 --- a/source/blender/blenlib/intern/boxpack2d.c +++ b/source/blender/blenlib/intern/boxpack2d.c @@ -27,7 +27,9 @@ #include <stdlib.h> /* for qsort */ #include "MEM_guardedalloc.h" -#include "BLI_boxpack2d.h" +#include "BLI_strict_flags.h" + +#include "BLI_boxpack2d.h" /* own include */ /* BoxPacker for backing 2D rectangles into a square * @@ -154,7 +156,7 @@ static int vertex_sort(const void *p1, const void *p2) * len - the number of boxes in the array. * tot_width and tot_height are set so you can normalize the data. * */ -void BLI_box_pack_2D(BoxPack *boxarray, const int len, float *tot_width, float *tot_height) +void BLI_box_pack_2d(BoxPack *boxarray, const int len, float *tot_width, float *tot_height) { BoxVert *vert; /* the current vert */ int box_index, verts_pack_len, i, j, k, isect; @@ -169,11 +171,11 @@ void BLI_box_pack_2D(BoxPack *boxarray, const int len, float *tot_width, float * } /* Sort boxes, biggest first */ - qsort(boxarray, len, sizeof(BoxPack), box_areasort); + qsort(boxarray, (size_t)len, sizeof(BoxPack), box_areasort); /* add verts to the boxes, these are only used internally */ - vert = vertarray = MEM_mallocN(len * 4 * sizeof(BoxVert), "BoxPack Verts"); - vertex_pack_indices = MEM_mallocN(len * 3 * sizeof(int), "BoxPack Indices"); + vert = vertarray = MEM_mallocN((size_t)len * 4 * sizeof(BoxVert), "BoxPack Verts"); + vertex_pack_indices = MEM_mallocN((size_t)len * 3 * sizeof(int), "BoxPack Indices"); for (box = boxarray, box_index = 0, i = 0; box_index < len; box_index++, box++) { @@ -241,7 +243,7 @@ void BLI_box_pack_2D(BoxPack *boxarray, const int len, float *tot_width, float * box_width = box->w; box_height = box->h; - qsort(vertex_pack_indices, verts_pack_len, sizeof(int), vertex_sort); + qsort(vertex_pack_indices, (size_t)verts_pack_len, sizeof(int), vertex_sort); /* Pack the box in with the others */ /* sort the verts */ @@ -318,7 +320,7 @@ void BLI_box_pack_2D(BoxPack *boxarray, const int len, float *tot_width, float * (*tot_height) = max_ff(BOXTOP(box), (*tot_height)); /* Place the box */ - vert->free &= ~quad_flags[j]; + vert->free &= (short)~quad_flags[j]; switch (j) { case TR: diff --git a/source/blender/blenlib/intern/buffer.c b/source/blender/blenlib/intern/buffer.c index 36fb04a7bb7..4e570823319 100644 --- a/source/blender/blenlib/intern/buffer.c +++ b/source/blender/blenlib/intern/buffer.c @@ -18,6 +18,10 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/blenlib/intern/buffer.c + * \ingroup bli + */ + #include "MEM_guardedalloc.h" #include "BLI_buffer.h" diff --git a/source/blender/blenlib/intern/callbacks.c b/source/blender/blenlib/intern/callbacks.c index 614a9a63d90..719809e6bcd 100644 --- a/source/blender/blenlib/intern/callbacks.c +++ b/source/blender/blenlib/intern/callbacks.c @@ -20,6 +20,10 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/blenlib/intern/callbacks.c + * \ingroup bli + */ + #include "BLI_utildefines.h" #include "BLI_listbase.h" #include "BLI_callbacks.h" diff --git a/source/blender/blenlib/intern/convexhull2d.c b/source/blender/blenlib/intern/convexhull2d.c new file mode 100644 index 00000000000..5669a302bd8 --- /dev/null +++ b/source/blender/blenlib/intern/convexhull2d.c @@ -0,0 +1,338 @@ +/* + * ***** 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/convexhull2d.c + * \ingroup bli + */ + + +#include <stdlib.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_convexhull2d.h" +#include "BLI_math.h" +#include "BLI_strict_flags.h" +#include "BLI_utildefines.h" + +/* Copyright 2001, softSurfer (www.softsurfer.com) + * This code may be freely used and modified for any purpose + * providing that this copyright notice is included with it. + * SoftSurfer makes no warranty for this code, and cannot be held + * liable for any real or imagined damage resulting from its use. + * Users of this code must verify correctness for their application. + * http://softsurfer.com/Archive/algorithm_0203/algorithm_0203.htm + */ + +/** \name Main Convex-Hull Calculation + * \{ */ + +/** + * tests if a point is Left|On|Right of an infinite line. + * Input: three points P0, P1, and P2 + * \returns > 0.0 for P2 left of the line through P0 and P1. + * = 0.0 for P2 on the line. + * < 0.0 for P2 right of the line. + */ +static float is_left(const float p0[2], const float p1[2], const float p2[2]) +{ + return (p1[0] - p0[0]) * (p2[1] - p0[1]) - (p2[0] - p0[0]) * (p1[1] - p0[1]); +} + +/** + * A.M. Andrew's monotone chain 2D convex hull algorithm + * + * \param points An array of 2D points presorted by increasing x and y-coords. + * \param n The number of points in points. + * \param r_points An array of the convex hull vertex indices (max is n). + * \returns the number of points in r_points. + */ +int BLI_convexhull_2d_sorted(const float (*points)[2], const int n, int r_points[]) +{ + /* the output array r_points[] will be used as the stack */ + int bot = 0; + int top = -1; /* indices for bottom and top of the stack */ + int i; /* array scan index */ + int minmin, minmax; + int maxmin, maxmax; + float xmax; + + /* Get the indices of points with min x-coord and min|max y-coord */ + float xmin = points[0][0]; + for (i = 1; i < n; i++) { + if (points[i][0] != xmin) { + break; + } + } + + minmin = 0; + minmax = i - 1; + if (minmax == n - 1) { /* degenerate case: all x-coords == xmin */ + r_points[++top] = minmin; + if (points[minmax][1] != points[minmin][1]) /* a nontrivial segment */ + r_points[++top] = minmax; + r_points[++top] = minmin; /* add polygon endpoint */ + return top + 1; + } + + /* Get the indices of points with max x-coord and min|max y-coord */ + + maxmax = n - 1; + xmax = points[n - 1][0]; + for (i = n - 2; i >= 0; i--) { + if (points[i][0] != xmax) { + break; + } + } + maxmin = i + 1; + + /* Compute the lower hull on the stack r_points */ + r_points[++top] = minmin; /* push minmin point onto stack */ + i = minmax; + while (++i <= maxmin) { + /* the lower line joins points[minmin] with points[maxmin] */ + if (is_left(points[minmin], points[maxmin], points[i]) >= 0 && i < maxmin) { + continue; /* ignore points[i] above or on the lower line */ + } + + while (top > 0) { /* there are at least 2 points on the stack */ + /* test if points[i] is left of the line at the stack top */ + if (is_left(points[r_points[top - 1]], points[r_points[top]], points[i]) > 0.0f) { + break; /* points[i] is a new hull vertex */ + } + else { + top--; /* pop top point off stack */ + } + } + + r_points[++top] = i; /* push points[i] onto stack */ + } + + /* Next, compute the upper hull on the stack r_points above the bottom hull */ + if (maxmax != maxmin) { /* if distinct xmax points */ + r_points[++top] = maxmax; /* push maxmax point onto stack */ + } + + bot = top; /* the bottom point of the upper hull stack */ + i = maxmin; + while (--i >= minmax) { + /* the upper line joins points[maxmax] with points[minmax] */ + if (is_left(points[maxmax], points[minmax], points[i]) >= 0 && i > minmax) { + continue; /* ignore points[i] below or on the upper line */ + } + + while (top > bot) { /* at least 2 points on the upper stack */ + /* test if points[i] is left of the line at the stack top */ + if (is_left(points[r_points[top - 1]], points[r_points[top]], points[i]) > 0.0f) { + break; /* points[i] is a new hull vertex */ + } + else { + top--; /* pop top point off stack */ + } + } + + if (points[i][0] == points[r_points[0]][0] && points[i][1] == points[r_points[0]][1]) { + return top + 1; /* special case (mgomes) */ + } + + r_points[++top] = i; /* push points[i] onto stack */ + } + + if (minmax != minmin) { + r_points[++top] = minmin; /* push joining endpoint onto stack */ + } + + return top + 1; +} + +struct PointRef { + const float *pt; /* 2d vector */ +}; + +static int pointref_cmp_x(const void *a_, const void *b_) +{ + const struct PointRef *a = a_; + const struct PointRef *b = b_; + if (a->pt[0] > b->pt[0]) return 1; + else if (a->pt[0] < b->pt[0]) return -1; + else return 0; +} + +static int pointref_cmp_y(const void *a_, const void *b_) +{ + const struct PointRef *a = a_; + const struct PointRef *b = b_; + if (a->pt[1] > b->pt[1]) return 1; + else if (a->pt[1] < b->pt[1]) return -1; + else return 0; +} + +/** + * A.M. Andrew's monotone chain 2D convex hull algorithm + * + * \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). + * \returns the number of points in r_points. + */ +int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[]) +{ + struct PointRef *points_ref = MEM_mallocN(sizeof(*points_ref) * (size_t)n, __func__); + float (*points_sort)[2] = MEM_mallocN(sizeof(*points_sort) * (size_t)n, __func__); + int *points_map; + int tot, i; + + for (i = 0; i < n; i++) { + points_ref[i].pt = points[i]; + } + + /* Sort the points by X, then by Y (required by the algorithm) */ + qsort(points_ref, (size_t)n, sizeof(struct PointRef), pointref_cmp_x); + qsort(points_ref, (size_t)n, sizeof(struct PointRef), pointref_cmp_y); + + for (i = 0; i < n; i++) { + memcpy(points_sort[i], points_ref[i].pt, sizeof(float[2])); + } + + tot = BLI_convexhull_2d_sorted((const float (*)[2])points_sort, n, r_points); + + /* map back to the original index values */ + points_map = (int *)points_sort; /* abuse float array for temp storage */ + for (i = 0; i < tot; i++) { + points_map[i] = (int)((const float(*)[2])points_ref[r_points[i]].pt - points); + } + + memcpy(r_points, points_map, (size_t)tot * sizeof(*points_map)); + + MEM_freeN(points_ref); + MEM_freeN(points_sort); + + return tot; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/* Helper functions */ + +/** \name Utility Convex-Hull Functions + * \{ */ + +/** + * \return The best angle for fitting the convex hull to an axis aligned bounding box. + * + * Intended to be used with #BLI_convexhull_2d + * + * \param points Orded hull points + * (result of #BLI_convexhull_2d mapped to a contiguous array). + * + * \note we could return the index of the best edge too if its needed. + */ +float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned int n) +{ + unsigned int i, i_prev; + float area_best = FLT_MAX; + float angle_best = 0.0f; + + i_prev = n - 1; + for (i = 0; i < n; i++) { + const float *ev_a = points_hull[i]; + const float *ev_b = points_hull[i_prev]; + float dvec[2]; + + sub_v2_v2v2(dvec, ev_a, ev_b); + if (normalize_v2(dvec) != 0.0f) { + float mat[2][2]; + float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {-FLT_MAX, -FLT_MAX}; + + unsigned int j; + const float angle = atan2f(dvec[0], dvec[1]); + float area; + + angle_to_mat2(mat, angle); + + for (j = 0; j < n; j++) { + float tvec[2]; + mul_v2_m2v2(tvec, mat, points_hull[j]); + + min[0] = min_ff(min[0], tvec[0]); + min[1] = min_ff(min[1], tvec[1]); + + max[0] = max_ff(max[0], tvec[0]); + max[1] = max_ff(max[1], tvec[1]); + + area = (max[0] - min[0]) * (max[1] - min[1]); + if (area > area_best) { + break; + } + } + + if (area < area_best) { + area_best = area; + angle_best = angle; + } + } + + i_prev = i; + } + + return angle_best; +} + +/** + * Wrap #BLI_convexhull_aabb_fit_hull_2d and do the convex hull calculation. + * + * \param points arbitrary 2d points. + */ +float BLI_convexhull_aabb_fit_points_2d(const float (*points)[2], unsigned int n) +{ + int *index_map; + int tot; + + float angle; + + index_map = MEM_mallocN(sizeof(*index_map) * n, __func__); + + tot = BLI_convexhull_2d((const float (*)[2])points, (int)n, index_map); + + if (tot) { + float (*points_hull)[2]; + int j; + + points_hull = MEM_mallocN(sizeof(*points_hull) * (size_t)tot, __func__); + for (j = 0; j < tot; j++) { + copy_v2_v2(points_hull[j], points[index_map[j]]); + } + + angle = BLI_convexhull_aabb_fit_hull_2d((const float (*)[2])points_hull, (unsigned int)tot); + MEM_freeN(points_hull); + } + else { + angle = 0.0f; + } + + MEM_freeN(index_map); + + return angle; +} + +/** \} */ diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c index a3360921ee4..b26e007b3e6 100644 --- a/source/blender/blenlib/intern/edgehash.c +++ b/source/blender/blenlib/intern/edgehash.c @@ -18,12 +18,13 @@ * Contributor(s): Daniel Dunbar, Joseph Eagar * * ***** END GPL LICENSE BLOCK ***** - * A general (pointer -> pointer) hash table ADT */ /** \file blender/blenlib/intern/edgehash.c * \ingroup bli * + * A general (pointer -> pointer) hash table ADT + * * \note Based on 'BLI_ghash.c', make sure these stay in sync. */ @@ -37,14 +38,7 @@ #include "BLI_utildefines.h" #include "BLI_edgehash.h" #include "BLI_mempool.h" - -#ifdef __GNUC__ -# pragma GCC diagnostic error "-Wsign-conversion" -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 /* gcc4.6+ only */ -# pragma GCC diagnostic error "-Wsign-compare" -# pragma GCC diagnostic error "-Wconversion" -# endif -#endif +#include "BLI_strict_flags.h" /**************inlined code************/ static const unsigned int _ehash_hashsizes[] = { @@ -54,7 +48,15 @@ static const unsigned int _ehash_hashsizes[] = { 268435459 }; -#define EDGE_HASH(v0, v1) ((v0 * 39) ^ (v1 * 31)) +/* internal flag to ensure sets values aren't used */ +#ifndef NDEBUG +# define EDGEHASH_FLAG_IS_SET (1 << 8) +# define IS_EDGEHASH_ASSERT(eh) BLI_assert((eh->flag & EDGEHASH_FLAG_IS_SET) == 0) +// # define IS_EDGESET_ASSERT(es) BLI_assert((es->flag & EDGEHASH_FLAG_IS_SET) != 0) +#else +# define IS_EDGEHASH_ASSERT(eh) +// # define IS_EDGESET_ASSERT(es) +#endif /* ensure v0 is smaller */ #define EDGE_ORD(v0, v1) \ @@ -66,131 +68,340 @@ static const unsigned int _ehash_hashsizes[] = { /***/ -typedef struct EdgeEntry EdgeEntry; -struct EdgeEntry { - EdgeEntry *next; +typedef struct EdgeEntry { + struct EdgeEntry *next; unsigned int v0, v1; void *val; -}; +} EdgeEntry; struct EdgeHash { EdgeEntry **buckets; BLI_mempool *epool; - unsigned int nbuckets, nentries, cursize; + unsigned int nbuckets, nentries; + unsigned int cursize, flag; }; -/***/ -EdgeHash *BLI_edgehash_new(void) +/* -------------------------------------------------------------------- */ +/* EdgeHash API */ + +/** \name Internal Utility API + * \{ */ + +/** + * Get the hash for a key. + */ +BLI_INLINE unsigned int edgehash_keyhash(EdgeHash *eh, unsigned int v0, unsigned int v1) { - EdgeHash *eh = MEM_callocN(sizeof(*eh), "EdgeHash"); - eh->cursize = 0; - eh->nentries = 0; - eh->nbuckets = _ehash_hashsizes[eh->cursize]; - - eh->buckets = MEM_callocN(eh->nbuckets * sizeof(*eh->buckets), "eh buckets 2"); - eh->epool = BLI_mempool_create(sizeof(EdgeEntry), 512, 512, BLI_MEMPOOL_SYSMALLOC); + BLI_assert(v0 < v1); - return eh; + return ((v0 * 39) ^ (v1 * 31)) % eh->nbuckets; } +/** + * Check if the number of items in the GHash is large enough to require more buckets. + */ +BLI_INLINE bool edgehash_test_expand_buckets(const unsigned int nentries, const unsigned int nbuckets) +{ + return (nentries > nbuckets * 3); +} -void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val) +/** + * Expand buckets to the next size up. + */ +BLI_INLINE void edgehash_resize_buckets(EdgeHash *eh, const unsigned int nbuckets) +{ + EdgeEntry **buckets_old = eh->buckets; + EdgeEntry **buckets_new; + const unsigned int nbuckets_old = eh->nbuckets; + unsigned int i; + EdgeEntry *e; + + BLI_assert(eh->nbuckets != nbuckets); + + eh->nbuckets = nbuckets; + buckets_new = MEM_callocN(eh->nbuckets * sizeof(*eh->buckets), "eh buckets"); + + for (i = 0; i < nbuckets_old; i++) { + EdgeEntry *e_next; + for (e = buckets_old[i]; e; e = e_next) { + const unsigned hash = edgehash_keyhash(eh, e->v0, e->v1); + e_next = e->next; + e->next = buckets_new[hash]; + buckets_new[hash] = e; + } + } + + eh->buckets = buckets_new; + MEM_freeN(buckets_old); +} + +/** + * Increase initial bucket size to match a reserved ammount. + */ +BLI_INLINE void edgehash_buckets_reserve(EdgeHash *eh, const unsigned int nentries_reserve) +{ + while (edgehash_test_expand_buckets(nentries_reserve, eh->nbuckets)) { + eh->nbuckets = _ehash_hashsizes[++eh->cursize]; + } +} + +/** + * Internal lookup function. + * Takes a hash argument to avoid calling #ghash_keyhash multiple times. + */ +BLI_INLINE EdgeEntry *edgehash_lookup_entry_ex(EdgeHash *eh, unsigned int v0, unsigned int v1, + const unsigned int hash) +{ + EdgeEntry *e; + BLI_assert(v0 < v1); + for (e = eh->buckets[hash]; e; e = e->next) { + if (UNLIKELY(v0 == e->v0 && v1 == e->v1)) { + return e; + } + } + return NULL; +} + +/** + * Internal lookup function. Only wraps #edgehash_lookup_entry_ex + */ +BLI_INLINE EdgeEntry *edgehash_lookup_entry(EdgeHash *eh, unsigned int v0, unsigned int v1) { unsigned int hash; + EDGE_ORD(v0, v1); /* ensure v0 is smaller */ + hash = edgehash_keyhash(eh, v0, v1); + return edgehash_lookup_entry_ex(eh, v0, v1, hash); +} + + +static EdgeHash *edgehash_new(const char *info, + const unsigned int nentries_reserve, + const unsigned int entry_size) +{ + EdgeHash *eh = MEM_mallocN(sizeof(*eh), info); + + eh->nbuckets = _ehash_hashsizes[0]; /* eh->cursize */ + eh->nentries = 0; + eh->cursize = 0; + eh->flag = 0; + + /* if we have reserved the number of elements that this hash will contain */ + if (nentries_reserve) { + edgehash_buckets_reserve(eh, nentries_reserve); + } + + eh->buckets = MEM_callocN(eh->nbuckets * sizeof(*eh->buckets), "eh buckets"); + eh->epool = BLI_mempool_create(entry_size, 512, 512, BLI_MEMPOOL_SYSMALLOC); + + return eh; +} + +/** + * Internal insert function. + * Takes a hash argument to avoid calling #edgehash_keyhash multiple times. + */ +BLI_INLINE void edgehash_insert_ex(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val, + unsigned int hash) +{ EdgeEntry *e = BLI_mempool_alloc(eh->epool); + BLI_assert((eh->flag & EDGEHASH_FLAG_ALLOW_DUPES) || (BLI_edgehash_haskey(eh, v0, v1) == 0)); + IS_EDGEHASH_ASSERT(eh); + /* this helps to track down errors with bad edge data */ + BLI_assert(v0 < v1); BLI_assert(v0 != v1); - EDGE_ORD(v0, v1); /* ensure v0 is smaller */ + e->next = eh->buckets[hash]; + e->v0 = v0; + e->v1 = v1; + e->val = val; + eh->buckets[hash] = e; - hash = EDGE_HASH(v0, v1) % eh->nbuckets; + if (UNLIKELY(edgehash_test_expand_buckets(++eh->nentries, eh->nbuckets))) { + edgehash_resize_buckets(eh, _ehash_hashsizes[++eh->cursize]); + } +} + +/** + * Insert function that doesn't set the value (use for EdgeSet) + */ +BLI_INLINE void edgehash_insert_ex_keyonly(EdgeHash *eh, unsigned int v0, unsigned int v1, + unsigned int hash) +{ + EdgeEntry *e = BLI_mempool_alloc(eh->epool); + + BLI_assert((eh->flag & EDGEHASH_FLAG_ALLOW_DUPES) || (BLI_edgehash_haskey(eh, v0, v1) == 0)); + + /* this helps to track down errors with bad edge data */ + BLI_assert(v0 < v1); + BLI_assert(v0 != v1); e->next = eh->buckets[hash]; e->v0 = v0; e->v1 = v1; - e->val = val; + /* intentionally leave value unset */ eh->buckets[hash] = e; - if (UNLIKELY(++eh->nentries > eh->nbuckets / 2)) { - EdgeEntry **old = eh->buckets; - const unsigned int nold = eh->nbuckets; - unsigned int i; + if (UNLIKELY(edgehash_test_expand_buckets(++eh->nentries, eh->nbuckets))) { + edgehash_resize_buckets(eh, _ehash_hashsizes[++eh->cursize]); + } +} - eh->nbuckets = _ehash_hashsizes[++eh->cursize]; - eh->buckets = MEM_callocN(eh->nbuckets * sizeof(*eh->buckets), "eh buckets"); - - for (i = 0; i < nold; i++) { - EdgeEntry *e_next; - for (e = old[i]; e; e = e_next) { - e_next = e->next; - hash = EDGE_HASH(e->v0, e->v1) % eh->nbuckets; - e->next = eh->buckets[hash]; - eh->buckets[hash] = e; - } - } +BLI_INLINE void edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val) +{ + unsigned int hash; + EDGE_ORD(v0, v1); /* ensure v0 is smaller */ + hash = edgehash_keyhash(eh, v0, v1); + edgehash_insert_ex(eh, v0, v1, val, hash); +} + +/** + * Run free callbacks for freeing entries. + */ +static void edgehash_free_cb(EdgeHash *eh, EdgeHashFreeFP valfreefp) +{ + unsigned int i; + + BLI_assert(valfreefp); + + for (i = 0; i < eh->nbuckets; i++) { + EdgeEntry *e; + + for (e = eh->buckets[i]; e; ) { + EdgeEntry *e_next = e->next; - MEM_freeN(old); + if (valfreefp) valfreefp(e->val); + + e = e_next; + } } } -void **BLI_edgehash_lookup_p(EdgeHash *eh, unsigned int v0, unsigned int v1) +/** \} */ + + +/** \name Public API + * \{ */ + +/* Public API */ + +EdgeHash *BLI_edgehash_new_ex(const char *info, + const unsigned int nentries_reserve) +{ + return edgehash_new(info, + nentries_reserve, + sizeof(EdgeEntry)); +} + +EdgeHash *BLI_edgehash_new(const char *info) +{ + return BLI_edgehash_new_ex(info, 0); +} + +/** + * Insert edge (\a v0, \a v1) into hash with given value, does + * not check for duplicates. + */ +void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val) +{ + edgehash_insert(eh, v0, v1, val); +} + +/** + * Assign a new value to a key that may already be in edgehash. + */ +bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val) { unsigned int hash; EdgeEntry *e; + IS_EDGEHASH_ASSERT(eh); + EDGE_ORD(v0, v1); /* ensure v0 is smaller */ + hash = edgehash_keyhash(eh, v0, v1); - hash = EDGE_HASH(v0, v1) % eh->nbuckets; - for (e = eh->buckets[hash]; e; e = e->next) - if (v0 == e->v0 && v1 == e->v1) - return &e->val; + e = edgehash_lookup_entry_ex(eh, v0, v1, hash); + if (e) { + e->val = val; + return false; + } + else { + edgehash_insert_ex(eh, v0, v1, val, hash); + return true; + } +} - return NULL; +/** + * Return pointer to value for given edge (\a v0, \a v1), + * or NULL if key does not exist in hash. + */ +void **BLI_edgehash_lookup_p(EdgeHash *eh, unsigned int v0, unsigned int v1) +{ + EdgeEntry *e = edgehash_lookup_entry(eh, v0, v1); + IS_EDGEHASH_ASSERT(eh); + return e ? &e->val : NULL; } +/** + * Return value for given edge (\a v0, \a v1), or NULL if + * if key does not exist in hash. (If need exists + * to differentiate between key-value being NULL and + * lack of key then see BLI_edgehash_lookup_p(). + */ void *BLI_edgehash_lookup(EdgeHash *eh, unsigned int v0, unsigned int v1) { - void **value_p = BLI_edgehash_lookup_p(eh, v0, v1); - - return value_p ? *value_p : NULL; + EdgeEntry *e = edgehash_lookup_entry(eh, v0, v1); + IS_EDGEHASH_ASSERT(eh); + return e ? e->val : NULL; } +/** + * Return boolean true/false if edge (v0,v1) in hash. + */ bool BLI_edgehash_haskey(EdgeHash *eh, unsigned int v0, unsigned int v1) { - return BLI_edgehash_lookup_p(eh, v0, v1) != NULL; + return (edgehash_lookup_entry(eh, v0, v1) != NULL); } +/** + * Return number of keys in hash. + */ int BLI_edgehash_size(EdgeHash *eh) { return (int)eh->nentries; } -void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP valfreefp) +/** + * Remove all edges from hash. + */ +void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP valfreefp, + const unsigned int nentries_reserve) { - unsigned int i; - - for (i = 0; i < eh->nbuckets; i++) { - EdgeEntry *e; - - for (e = eh->buckets[i]; e; ) { - EdgeEntry *n = e->next; - - if (valfreefp) valfreefp(e->val); - BLI_mempool_free(eh->epool, e); - - e = n; - } - eh->buckets[i] = NULL; - } + if (valfreefp) + edgehash_free_cb(eh, valfreefp); + eh->nbuckets = _ehash_hashsizes[0]; /* eh->cursize */ eh->nentries = 0; + eh->cursize = 0; + + if (nentries_reserve) { + edgehash_buckets_reserve(eh, nentries_reserve); + } + + MEM_freeN(eh->buckets); + eh->buckets = MEM_callocN(eh->nbuckets * sizeof(*eh->buckets), "eh buckets"); + + BLI_mempool_clear_ex(eh->epool, nentries_reserve ? (int)nentries_reserve : -1); } void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP valfreefp) { - BLI_edgehash_clear(eh, valfreefp); + BLI_assert((int)eh->nentries == BLI_mempool_count(eh->epool)); + + if (valfreefp) + edgehash_free_cb(eh, valfreefp); BLI_mempool_destroy(eh->epool); @@ -199,7 +410,24 @@ void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP valfreefp) } -/***/ +void BLI_edgehash_flag_set(EdgeHash *eh, unsigned int flag) +{ + eh->flag |= flag; +} + +void BLI_edgehash_flag_clear(EdgeHash *eh, unsigned int flag) +{ + eh->flag &= ~flag; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/* EdgeHash Iterator API */ + +/** \name Iterator API + * \{ */ struct EdgeHashIterator { EdgeHash *eh; @@ -207,6 +435,12 @@ struct EdgeHashIterator { EdgeEntry *curEntry; }; + +/** + * 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. + */ EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) { EdgeHashIterator *ehi = MEM_mallocN(sizeof(*ehi), "eh iter"); @@ -221,11 +455,18 @@ EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) } return ehi; } + +/** + * Free an EdgeHashIterator. + */ void BLI_edgehashIterator_free(EdgeHashIterator *ehi) { MEM_freeN(ehi); } +/** + * Retrieve the key from an iterator. + */ void BLI_edgehashIterator_getKey(EdgeHashIterator *ehi, unsigned int *v0_r, unsigned int *v1_r) { if (ehi->curEntry) { @@ -233,11 +474,26 @@ void BLI_edgehashIterator_getKey(EdgeHashIterator *ehi, unsigned int *v0_r, unsi *v1_r = ehi->curEntry->v1; } } + +/** + * Retrieve the value from an iterator. + */ void *BLI_edgehashIterator_getValue(EdgeHashIterator *ehi) { return ehi->curEntry ? ehi->curEntry->val : NULL; } +/** + * Retrieve the pointer to the value from an iterator. + */ +void **BLI_edgehashIterator_getValue_p(EdgeHashIterator *ehi) +{ + return ehi->curEntry ? &ehi->curEntry->val : NULL; +} + +/** + * Set the value for an iterator. + */ void BLI_edgehashIterator_setValue(EdgeHashIterator *ehi, void *val) { if (ehi->curEntry) { @@ -245,6 +501,9 @@ void BLI_edgehashIterator_setValue(EdgeHashIterator *ehi, void *val) } } +/** + * Steps the iterator to the next index. + */ void BLI_edgehashIterator_step(EdgeHashIterator *ehi) { if (ehi->curEntry) { @@ -259,7 +518,88 @@ void BLI_edgehashIterator_step(EdgeHashIterator *ehi) } } } + +/** + * Determine if an iterator is done. + */ bool BLI_edgehashIterator_isDone(EdgeHashIterator *ehi) { return (ehi->curEntry == NULL); } + +/** \} */ + +/* -------------------------------------------------------------------- */ +/* EdgeSet API */ + +/* Use edgehash API to give 'set' functionality */ + +/** \name EdgeSet Functions + * \{ */ +EdgeSet *BLI_edgeset_new_ex(const char *info, + const unsigned int nentries_reserve) +{ + EdgeSet *es = (EdgeSet *)edgehash_new(info, + nentries_reserve, + sizeof(EdgeEntry) - sizeof(void *)); +#ifndef NDEBUG + ((EdgeHash *)es)->flag |= EDGEHASH_FLAG_IS_SET; +#endif + return es; +} + +EdgeSet *BLI_edgeset_new(const char *info) +{ + return BLI_edgeset_new_ex(info, 0); +} + +int BLI_edgeset_size(EdgeSet *es) +{ + return (int)((EdgeHash *)es)->nentries; +} + +/** + * Adds the key to the set (no checks for unique keys!). + * Matching #BLI_edgehash_insert + */ +void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1) +{ + unsigned int hash; + EDGE_ORD(v0, v1); /* ensure v0 is smaller */ + hash = edgehash_keyhash((EdgeHash *)es, v0, v1); + edgehash_insert_ex_keyonly((EdgeHash *)es, v0, v1, hash); +} + +/** + * Assign a new value to a key that may already be in edgehash. + */ +bool BLI_edgeset_reinsert(EdgeSet *es, unsigned int v0, unsigned int v1) +{ + unsigned int hash; + EdgeEntry *e; + + EDGE_ORD(v0, v1); /* ensure v0 is smaller */ + hash = edgehash_keyhash((EdgeHash *)es, v0, v1); + + e = edgehash_lookup_entry_ex((EdgeHash *)es, v0, v1, hash); + if (e) { + return false; + } + else { + edgehash_insert_ex_keyonly((EdgeHash *)es, v0, v1, hash); + return true; + } +} + +bool BLI_edgeset_haskey(EdgeSet *es, unsigned int v0, unsigned int v1) +{ + return (edgehash_lookup_entry((EdgeHash *)es, v0, v1) != NULL); +} + + +void BLI_edgeset_free(EdgeSet *es) +{ + BLI_edgehash_free((EdgeHash *)es, NULL); +} + +/** \} */ diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c index 4809ba59aaf..55726565f59 100644 --- a/source/blender/blenlib/intern/fileops.c +++ b/source/blender/blenlib/intern/fileops.c @@ -215,6 +215,11 @@ bool BLI_file_touch(const char *file) #ifdef WIN32 +static void callLocalErrorCallBack(const char *err) +{ + printf("%s\n", err); +} + static char str[MAXPATHLEN + 12]; FILE *BLI_fopen(const char *filename, const char *mode) diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c index 7f158bc3efb..6967742f89b 100644 --- a/source/blender/blenlib/intern/gsqueue.c +++ b/source/blender/blenlib/intern/gsqueue.c @@ -35,6 +35,7 @@ #include "BLI_utildefines.h" #include "BLI_gsqueue.h" +#include "BLI_strict_flags.h" typedef struct _GSQueueElem GSQueueElem; struct _GSQueueElem { @@ -93,7 +94,7 @@ int BLI_gsqueue_size(GSQueue *gq) */ void BLI_gsqueue_peek(GSQueue *gq, void *item_r) { - memcpy(item_r, &gq->head[1], gq->elem_size); + memcpy(item_r, &gq->head[1], (size_t)gq->elem_size); } /** @@ -114,7 +115,7 @@ void BLI_gsqueue_pop(GSQueue *gq, void *item_r) gq->head = gq->head->next; } - if (item_r) memcpy(item_r, &elem[1], gq->elem_size); + if (item_r) memcpy(item_r, &elem[1], (size_t)gq->elem_size); MEM_freeN(elem); } @@ -130,11 +131,11 @@ void BLI_gsqueue_push(GSQueue *gq, void *item) /* compare: prevent events added double in row */ if (!BLI_gsqueue_is_empty(gq)) { - if (0 == memcmp(item, &gq->head[1], gq->elem_size)) + if (0 == memcmp(item, &gq->head[1], (size_t)gq->elem_size)) return; } - elem = MEM_mallocN(sizeof(*elem) + gq->elem_size, "gqueue_push"); - memcpy(&elem[1], item, gq->elem_size); + elem = MEM_mallocN(sizeof(*elem) + (size_t)gq->elem_size, "gqueue_push"); + memcpy(&elem[1], item, (size_t)gq->elem_size); elem->next = NULL; if (BLI_gsqueue_is_empty(gq)) { @@ -154,8 +155,8 @@ void BLI_gsqueue_push(GSQueue *gq, void *item) */ void BLI_gsqueue_pushback(GSQueue *gq, void *item) { - GSQueueElem *elem = MEM_mallocN(sizeof(*elem) + gq->elem_size, "gqueue_push"); - memcpy(&elem[1], item, gq->elem_size); + GSQueueElem *elem = MEM_mallocN(sizeof(*elem) + (size_t)gq->elem_size, "gqueue_push"); + memcpy(&elem[1], item, (size_t)gq->elem_size); elem->next = gq->head; if (BLI_gsqueue_is_empty(gq)) { @@ -176,5 +177,3 @@ void BLI_gsqueue_free(GSQueue *gq) } MEM_freeN(gq); } - - diff --git a/source/blender/blenlib/intern/lasso.c b/source/blender/blenlib/intern/lasso.c index aa08a780394..e89f7fd795b 100644 --- a/source/blender/blenlib/intern/lasso.c +++ b/source/blender/blenlib/intern/lasso.c @@ -34,12 +34,13 @@ #include "BLI_math.h" #include "BLI_rect.h" +#include "BLI_strict_flags.h" #include "BLI_lasso.h" /* own include */ -void BLI_lasso_boundbox(rcti *rect, const int mcords[][2], const short moves) +void BLI_lasso_boundbox(rcti *rect, const int mcords[][2], const unsigned int moves) { - short a; + unsigned int a; rect->xmin = rect->xmax = mcords[0][0]; rect->ymin = rect->ymax = mcords[0][1]; @@ -53,28 +54,28 @@ void BLI_lasso_boundbox(rcti *rect, const int mcords[][2], const short moves) } -bool BLI_lasso_is_point_inside(const int mcords[][2], const short moves, +bool BLI_lasso_is_point_inside(const int mcords[][2], const unsigned int moves, const int sx, const int sy, const int error_value) { - if (sx == error_value) { + if (sx == error_value || moves == 0) { return false; } else { int pt[2] = {sx, sy}; - return isect_point_poly_v2_int(pt, mcords, moves); + return isect_point_poly_v2_int(pt, mcords, moves, true); } } /* edge version for lasso select. we assume boundbox check was done */ -bool BLI_lasso_is_edge_inside(const int mcords[][2], const short moves, +bool BLI_lasso_is_edge_inside(const int mcords[][2], const unsigned int moves, int x0, int y0, int x1, int y1, const int error_value) { int v1[2], v2[2]; - int a; + unsigned int a; - if (x0 == error_value || x1 == error_value) { + if (x0 == error_value || x1 == error_value || moves == 0) { return false; } diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c index ded4f31ae05..2c59b940f8c 100644 --- a/source/blender/blenlib/intern/listbase.c +++ b/source/blender/blenlib/intern/listbase.c @@ -129,6 +129,30 @@ bool BLI_remlink_safe(ListBase *listbase, void *vlink) } } +/** + * Removes the head from \a listbase and returns it. + */ +void *BLI_pophead(ListBase *listbase) +{ + Link *link; + if ((link = listbase->first)) { + BLI_remlink(listbase, link); + } + return link; +} + + +/** + * Removes the tail from \a listbase and returns it. + */ +void *BLI_poptail(ListBase *listbase) +{ + Link *link; + if ((link = listbase->last)) { + BLI_remlink(listbase, link); + } + return link; +} /** * Removes \a vlink from listbase and disposes of it. Assumes it is linked into there! @@ -557,19 +581,34 @@ void BLI_reverselist(ListBase *lb) /** * \param vlink Link to make first. */ -void BLI_rotatelist(ListBase *lb, void *vlink) +void BLI_rotatelist_first(ListBase *lb, void *vlink) { /* make circular */ - ((LinkData *)lb->first)->prev = lb->last; - ((LinkData *)lb->last)->next = lb->first; + ((Link *)lb->first)->prev = lb->last; + ((Link *)lb->last)->next = lb->first; lb->first = vlink; - lb->last = ((LinkData *)vlink)->prev; + lb->last = ((Link *)vlink)->prev; - ((LinkData *)lb->first)->prev = NULL; - ((LinkData *)lb->last)->next = NULL; + ((Link *)lb->first)->prev = NULL; + ((Link *)lb->last)->next = NULL; } +/** + * \param vlink Link to make last. + */ +void BLI_rotatelist_last(ListBase *lb, void *vlink) +{ + /* make circular */ + ((Link *)lb->first)->prev = lb->last; + ((Link *)lb->last)->next = lb->first; + + lb->first = ((Link *)vlink)->next; + lb->last = vlink; + + ((Link *)lb->first)->prev = NULL; + ((Link *)lb->last)->next = NULL; +} /* create a generic list node containing link to provided data */ LinkData *BLI_genericNodeN(void *data) diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index 3ffd96f62c7..e6509db1c5e 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -131,8 +131,9 @@ MINLINE int power_of_2_max_i(int n) if (is_power_of_2_i(n)) return n; - while (!is_power_of_2_i(n)) + do { n = n & (n - 1); + } while (!is_power_of_2_i(n)); return n * 2; } @@ -152,6 +153,14 @@ MINLINE int divide_round_i(int a, int b) return (2 * a + b) / (2 * b); } +/** + * modulo that handles negative numbers, works the same as Python's. + */ +MINLINE int mod_i(int i, int n) +{ + return (i % n + n) % n; +} + MINLINE unsigned int highest_order_bit_i(unsigned int n) { n |= (n >> 1); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 9b8fd0ad85b..0d15eede9ea 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -183,6 +183,28 @@ float area_poly_v2(int nr, float verts[][2]) return fabsf(0.5f * area); } +/********************************* Planes **********************************/ + +/** + * Calculate a plane from a point and a direction, + * \note \a point_no isn't required to be normalized. + */ +void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3]) +{ + copy_v3_v3(r_plane, plane_no); + r_plane[3] = -dot_v3v3(r_plane, plane_co); +} + +/** + * Get a point and a normal from a plane. + */ +void plane_to_point_normal_v3(const float plane[4], float r_plane_co[3], float r_plane_no[3]) +{ + const float length = normalize_v3_v3(r_plane_no, plane); + madd_v3_v3v3fl(r_plane_co, r_plane_no, r_plane_no, (-plane[3] / length) - 1.0f); +} + + /********************************* Volume **********************************/ /** @@ -283,45 +305,39 @@ void closest_to_line_segment_v3(float close_r[3], const float v1[3], const float copy_v3_v3(close_r, cp); } -/* find the closest point on a plane to another point and store it in close_r - * close_r: return coordinate - * plane_co: a point on the plane - * plane_no_unit: the plane's normal, and d is the last number in the plane equation 0 = ax + by + cz + d - * pt: the point that you want the nearest of +/** + * Find the closest point on a plane. + * + * \param close_r Return coordinate + * \param plane The plane to test against. + * \param pt The point to find the nearest of + * + * \note non-unit-length planes are supported. */ - -void closest_to_plane_v3(float close_r[3], const float plane_co[3], const float plane_no_unit[3], const float pt[3]) +void closest_to_plane_v3(float close_r[3], const float plane[4], const float pt[3]) { - float temp[3]; - float dotprod; - - sub_v3_v3v3(temp, pt, plane_co); - dotprod = dot_v3v3(temp, plane_no_unit); - - close_r[0] = pt[0] - (plane_no_unit[0] * dotprod); - close_r[1] = pt[1] - (plane_no_unit[1] * dotprod); - close_r[2] = pt[2] - (plane_no_unit[2] * dotprod); + const float length = len_squared_v3(plane); + const float side = plane_point_side_v3(plane, pt); + madd_v3_v3v3fl(close_r, pt, plane, -side / length); } -/* signed distance from the point to the plane in 3D */ -float dist_to_plane_normalized_v3(const float p[3], const float plane_co[3], const float plane_no_unit[3]) +float dist_squared_to_plane_v3(const float pt[3], const float plane[4]) { - float plane_co_other[3]; - - add_v3_v3v3(plane_co_other, plane_co, plane_no_unit); - - return line_point_factor_v3(p, plane_co, plane_co_other); + const float length = len_squared_v3(plane); + const float side = plane_point_side_v3(plane, pt); + const float fac = side / length; + return copysign(length * (fac * fac), side); } -float dist_to_plane_v3(const float p[3], const float plane_co[3], const float plane_no[3]) +/** + * Return the signed distance from the point to the plane. + */ +float dist_to_plane_v3(const float pt[3], const float plane[4]) { - float plane_no_unit[3]; - float plane_co_other[3]; - - normalize_v3_v3(plane_no_unit, plane_no); - add_v3_v3v3(plane_co_other, plane_co, plane_no_unit); - - return line_point_factor_v3(p, plane_co, plane_co_other); + const float length = len_squared_v3(plane); + const float side = plane_point_side_v3(plane, pt); + const float fac = side / length; + return sqrtf(length) * fac; } /* distance v1 to line-piece l1-l2 in 3D */ @@ -696,16 +712,16 @@ int isect_line_sphere_v2(const float l1[2], const float l2[2], } /* point in polygon (keep float and int versions in sync) */ -bool isect_point_poly_v2(const float pt[2], const float verts[][2], const int nr) +bool isect_point_poly_v2(const float pt[2], const float verts[][2], const unsigned int nr, + const bool use_holes) { /* we do the angle rule, define that all added angles should be about zero or (2 * PI) */ float angletot = 0.0; float fp1[2], fp2[2]; - int i; + unsigned int i; const float *p1, *p2; p1 = verts[nr - 1]; - p2 = verts[0]; /* first vector */ fp1[0] = (float)(p1[0] - pt[0]); @@ -714,6 +730,8 @@ bool isect_point_poly_v2(const float pt[2], const float verts[][2], const int nr for (i = 0; i < nr; i++) { float dot, ang, cross; + p2 = verts[i]; + /* second vector */ fp2[0] = (float)(p2[0] - pt[0]); fp2[1] = (float)(p2[1] - pt[1]); @@ -730,21 +748,28 @@ bool isect_point_poly_v2(const float pt[2], const float verts[][2], const int nr /* circulate */ copy_v2_v2(fp1, fp2); p1 = p2; - p2 = verts[i + 1]; } - return (fabsf(angletot) > 4.0f); + angletot = fabsf(angletot); + if (use_holes) { + const int nested = floorf((angletot / (float)(M_PI * 2.0)) + 0.00001f); + angletot -= nested * (float)(M_PI * 2.0); + return (angletot > 4.0f) != (nested % 2); + } + else { + return (angletot > 4.0f); + } } -bool isect_point_poly_v2_int(const int pt[2], const int verts[][2], const int nr) +bool isect_point_poly_v2_int(const int pt[2], const int verts[][2], const unsigned int nr, + const bool use_holes) { /* we do the angle rule, define that all added angles should be about zero or (2 * PI) */ float angletot = 0.0; float fp1[2], fp2[2]; - int i; + unsigned int i; const int *p1, *p2; p1 = verts[nr - 1]; - p2 = verts[0]; /* first vector */ fp1[0] = (float)(p1[0] - pt[0]); @@ -753,6 +778,8 @@ bool isect_point_poly_v2_int(const int pt[2], const int verts[][2], const int nr for (i = 0; i < nr; i++) { float dot, ang, cross; + p2 = verts[i]; + /* second vector */ fp2[0] = (float)(p2[0] - pt[0]); fp2[1] = (float)(p2[1] - pt[1]); @@ -769,10 +796,17 @@ bool isect_point_poly_v2_int(const int pt[2], const int verts[][2], const int nr /* circulate */ copy_v2_v2(fp1, fp2); p1 = p2; - p2 = verts[i + 1]; } - return (fabsf(angletot) > 4.0f); + angletot = fabsf(angletot); + if (use_holes) { + const int nested = floorf((angletot / (float)(M_PI * 2.0)) + 0.00001f); + angletot -= nested * (float)(M_PI * 2.0); + return (angletot > 4.0f) != (nested % 2); + } + else { + return (angletot > 4.0f); + } } /* point in tri */ @@ -878,6 +912,45 @@ bool isect_line_tri_v3(const float p1[3], const float p2[3], return 1; } +/* like isect_line_tri_v3, but allows epsilon tolerance around triangle */ +bool isect_line_tri_epsilon_v3(const float p1[3], const float p2[3], + const float v0[3], const float v1[3], const float v2[3], + float *r_lambda, float r_uv[2], const float epsilon) +{ + + float p[3], s[3], d[3], e1[3], e2[3], q[3]; + float a, f, u, v; + + sub_v3_v3v3(e1, v1, v0); + sub_v3_v3v3(e2, v2, v0); + sub_v3_v3v3(d, p2, p1); + + cross_v3_v3v3(p, d, e2); + a = dot_v3v3(e1, p); + if ((a > -0.000001f) && (a < 0.000001f)) return 0; + 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; + + cross_v3_v3v3(q, s, e1); + + v = f * dot_v3v3(d, q); + if ((v < -epsilon) || ((u + v) > 1.0f + epsilon)) return 0; + + *r_lambda = f * dot_v3v3(e2, q); + if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) return 0; + + if (r_uv) { + r_uv[0] = u; + r_uv[1] = v; + } + + return 1; +} + /* moved from effect.c * test if the ray starting at p1 going in d direction intersects the triangle v0..v2 * return non zero if it does @@ -1043,57 +1116,51 @@ bool isect_ray_tri_threshold_v3(const float p1[3], const float d[3], } /** - * Intersect line/plane, optionally treat line as directional (like a ray) with the no_flip argument. + * Check if a point is behind all planes. + */ +bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3]) +{ + int i; + + for (i = 0; i < totplane; i++) { + if (plane_point_side_v3(planes[i], p) > 0.0f) { + return false; + } + } + + return true; +} + +/** + * Intersect line/plane. * * \param out The intersection point. * \param l1 The first point of the line. * \param l2 The second point of the line. * \param plane_co A point on the plane to intersect with. * \param plane_no The direction of the plane (does not need to be normalized). - * \param no_flip When true, the intersection point will always be from l1 to l2, even if this is not on the plane. + * + * \note #line_plane_factor_v3() shares logic. */ bool isect_line_plane_v3(float out[3], const float l1[3], const float l2[3], - const float plane_co[3], const float plane_no[3], const bool no_flip) + const float plane_co[3], const float plane_no[3]) { - float l_vec[3]; /* l1 -> l2 normalized vector */ - float p_no[3]; /* 'plane_no' normalized */ + float u[3], h[3]; float dot; - sub_v3_v3v3(l_vec, l2, l1); - - normalize_v3(l_vec); - normalize_v3_v3(p_no, plane_no); + sub_v3_v3v3(u, l2, l1); + sub_v3_v3v3(h, l1, plane_co); + dot = dot_v3v3(plane_no, u); - dot = dot_v3v3(l_vec, p_no); - if (dot == 0.0f) { - return 0; + if (fabsf(dot) > FLT_EPSILON) { + float lambda = -dot_v3v3(plane_no, h) / dot; + madd_v3_v3v3fl(out, l1, u, lambda); + return true; } else { - float l1_plane[3]; /* line point aligned with the plane */ - float dist; /* 'plane_no' aligned distance to the 'plane_co' */ - - /* for predictable flipping since the plane is only used to - * define a direction, ignore its flipping and aligned with 'l_vec' */ - if (dot < 0.0f) { - dot = -dot; - negate_v3(p_no); - } - - add_v3_v3v3(l1_plane, l1, p_no); - - dist = line_point_factor_v3(plane_co, l1, l1_plane); - - /* treat line like a ray, when 'no_flip' is set */ - if (no_flip && dist < 0.0f) { - dist = -dist; - } - - mul_v3_fl(l_vec, dist / dot); - - add_v3_v3v3(out, l1, l_vec); - - return 1; + /* The segment is parallel to plane */ + return false; } } @@ -1119,7 +1186,7 @@ void isect_plane_plane_v3(float r_isect_co[3], float r_isect_no[3], cross_v3_v3v3(r_isect_no, plane_a_no, plane_b_no); /* direction is simply the cross product */ cross_v3_v3v3(plane_a_co_other, plane_a_no, r_isect_no); add_v3_v3(plane_a_co_other, plane_a_co); - isect_line_plane_v3(r_isect_co, plane_a_co, plane_a_co_other, plane_b_co, plane_b_no, FALSE); + isect_line_plane_v3(r_isect_co, plane_a_co, plane_a_co_other, plane_b_co, plane_b_no); } @@ -1561,7 +1628,7 @@ bool isect_ray_aabb(const IsectRayAABBData *data, const float bb_min[3], tymax = (bbox[1 - data->sign[1]][1] - data->ray_start[1]) * data->ray_inv_dir[1]; if ((tmin > tymax) || (tymin > tmax)) - return FALSE; + return false; if (tymin > tmin) tmin = tymin; @@ -1573,7 +1640,7 @@ bool isect_ray_aabb(const IsectRayAABBData *data, const float bb_min[3], tzmax = (bbox[1 - data->sign[2]][2] - data->ray_start[2]) * data->ray_inv_dir[2]; if ((tmin > tzmax) || (tzmin > tmax)) - return FALSE; + return false; if (tzmin > tmin) tmin = tzmin; @@ -1585,7 +1652,7 @@ bool isect_ray_aabb(const IsectRayAABBData *data, const float bb_min[3], if (tmin_out) (*tmin_out) = tmin; - return TRUE; + return true; } /* find closest point to p on line through (l1, l2) and return lambda, @@ -1645,6 +1712,20 @@ float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2 #endif } +/** + * \note #isect_line_plane_v3() shares logic + */ +float line_plane_factor_v3(const float plane_co[3], const float plane_no[3], + const float l1[3], const float l2[3]) +{ + float u[3], h[3]; + float dot; + sub_v3_v3v3(u, l2, l1); + sub_v3_v3v3(h, l1, plane_co); + dot = dot_v3v3(plane_no, u); + return (dot != 0.0f) ? -dot_v3v3(plane_no, h) / dot : 0.0f; +} + /* ensure the distance between these points is no greater then 'dist' * if it is, scale then both into the center */ void limit_dist_v3(float v1[3], float v2[3], const float dist) @@ -1757,7 +1838,7 @@ bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4]) if (div == 0.0f) /* parallel */ return 1; - t = -(dot_v3v3(p1, plane) + plane[3]) / div; + t = -plane_point_side_v3(plane, p1) / div; if (div > 0.0f) { /* behind plane, completely clipped */ @@ -1811,7 +1892,7 @@ bool clip_segment_v3_plane_n(float r_p1[3], float r_p2[3], float plane_array[][4 const float div = dot_v3v3(dp, plane); if (div != 0.0f) { - const float t = -(dot_v3v3(p1, plane) + plane[3]) / div; + const float t = -plane_point_side_v3(plane, p1) / div; if (div > 0.0f) { /* clip a */ if (t >= 1.0f) { @@ -1916,6 +1997,59 @@ void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int } } +void fill_poly_v2i_n( + const int xmin, const int ymin, const int xmax, const int ymax, + const int verts[][2], const int nr, + void (*callback)(int, int, void *), void *userData) +{ + /* originally by Darel Rex Finley, 2007 */ + + int nodes, pixel_y, i, j, swap; + int *node_x = MEM_mallocN(sizeof(*node_x) * (nr + 1), __func__); + + /* Loop through the rows of the image. */ + for (pixel_y = ymin; pixel_y < ymax; pixel_y++) { + + /* Build a list of nodes. */ + nodes = 0; j = nr - 1; + for (i = 0; i < nr; i++) { + if ((verts[i][1] < pixel_y && verts[j][1] >= pixel_y) || + (verts[j][1] < pixel_y && verts[i][1] >= pixel_y)) + { + node_x[nodes++] = (int)(verts[i][0] + + ((double)(pixel_y - verts[i][1]) / (verts[j][1] - verts[i][1])) * + (verts[j][0] - verts[i][0])); + } + j = i; + } + + /* Sort the nodes, via a simple "Bubble" sort. */ + i = 0; + while (i < nodes - 1) { + if (node_x[i] > node_x[i + 1]) { + SWAP_TVAL(swap, node_x[i], node_x[i + 1]); + if (i) i--; + } + else { + i++; + } + } + + /* Fill the pixels between node pairs. */ + for (i = 0; i < nodes; i += 2) { + if (node_x[i] >= xmax) break; + if (node_x[i + 1] > xmin) { + if (node_x[i ] < xmin) node_x[i ] = xmin; + if (node_x[i + 1] > xmax) node_x[i + 1] = xmax; + for (j = node_x[i]; j < node_x[i + 1]; j++) { + callback(j - xmin, pixel_y - ymin, userData); + } + } + } + } + MEM_freeN(node_x); +} + /****************************** Axis Utils ********************************/ /** @@ -2137,8 +2271,6 @@ void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const flo ((_area = cross_v2v2(dirs[i1], dirs[i2])) != 0.0f ? \ fabsf(((lens[i1] * lens[i2]) - dot_v2v2(dirs[i1], dirs[i2])) / _area) : 0.0f) - float wtot, area; - const float dirs[4][2] = { {v1[0] - co[0], v1[1] - co[1]}, {v2[0] - co[0], v2[1] - co[1]}, @@ -2153,20 +2285,29 @@ void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const flo len_v2(dirs[3]), }; - /* variable 'area' is just for storage, - * the order its initialized doesn't matter */ + /* avoid divide by zero */ + if (UNLIKELY(lens[0] < FLT_EPSILON)) { w[0] = 1.0f; w[1] = w[2] = w[3] = 0.0f; } + else if (UNLIKELY(lens[1] < FLT_EPSILON)) { w[1] = 1.0f; w[0] = w[2] = w[3] = 0.0f; } + else if (UNLIKELY(lens[2] < FLT_EPSILON)) { w[2] = 1.0f; w[0] = w[1] = w[3] = 0.0f; } + else if (UNLIKELY(lens[3] < FLT_EPSILON)) { w[3] = 1.0f; w[0] = w[1] = w[2] = 0.0f; + } + else { + float wtot, area; + + /* variable 'area' is just for storage, + * the order its initialized doesn't matter */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunsequenced" #endif - /* inline mean_value_half_tan four times here */ - float t[4] = { - MEAN_VALUE_HALF_TAN_V2(area, 0, 1), - MEAN_VALUE_HALF_TAN_V2(area, 1, 2), - MEAN_VALUE_HALF_TAN_V2(area, 2, 3), - MEAN_VALUE_HALF_TAN_V2(area, 3, 0), - }; + /* inline mean_value_half_tan four times here */ + float t[4] = { + MEAN_VALUE_HALF_TAN_V2(area, 0, 1), + MEAN_VALUE_HALF_TAN_V2(area, 1, 2), + MEAN_VALUE_HALF_TAN_V2(area, 2, 3), + MEAN_VALUE_HALF_TAN_V2(area, 3, 0), + }; #ifdef __clang__ # pragma clang diagnostic pop @@ -2174,18 +2315,19 @@ void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const flo #undef MEAN_VALUE_HALF_TAN_V2 - w[0] = (t[3] + t[0]) / lens[0]; - w[1] = (t[0] + t[1]) / lens[1]; - w[2] = (t[1] + t[2]) / lens[2]; - w[3] = (t[2] + t[3]) / lens[3]; + w[0] = (t[3] + t[0]) / lens[0]; + w[1] = (t[0] + t[1]) / lens[1]; + w[2] = (t[1] + t[2]) / lens[2]; + w[3] = (t[2] + t[3]) / lens[3]; - wtot = w[0] + w[1] + w[2] + w[3]; + wtot = w[0] + w[1] + w[2] + w[3]; - if (wtot != 0.0f) { - mul_v4_fl(w, 1.0f / wtot); - } - else { /* dummy values for zero area face */ - copy_v4_fl(w, 1.0f / 4.0f); + if (wtot != 0.0f) { + mul_v4_fl(w, 1.0f / wtot); + } + else { /* dummy values for zero area face */ + copy_v4_fl(w, 1.0f / 4.0f); + } } } @@ -2323,17 +2465,16 @@ int interp_sparse_array(float *array, int const list_size, const float skipval) * more than 3 vertices */ static float mean_value_half_tan_v3(const float v1[3], const float v2[3], const float v3[3]) { - float d2[3], d3[3], cross[3], area, dot, len; + 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); area = len_v3(cross); - dot = dot_v3v3(d2, d3); - len = len_v3(d2) * len_v3(d3); - if (LIKELY(area != 0.0f)) { + const float dot = dot_v3v3(d2, d3); + const float len = len_v3(d2) * len_v3(d3); return (len - dot) / area; } else { @@ -2342,18 +2483,16 @@ static float mean_value_half_tan_v3(const float v1[3], const float v2[3], const } 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, dot, len; + float d2[2], d3[2], area; sub_v2_v2v2(d2, v2, v1); sub_v2_v2v2(d3, v3, v1); /* different from the 3d version but still correct */ area = cross_v2v2(d2, d3); - - dot = dot_v2v2(d2, d3); - len = len_v2(d2) * len_v2(d3); - if (LIKELY(area != 0.0f)) { + const float dot = dot_v2v2(d2, d3); + const float len = len_v2(d2) * len_v2(d3); return (len - dot) / area; } else { @@ -3616,4 +3755,3 @@ int is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], c /* linetests, the 2 diagonals have to instersect to be convex */ return (isect_line_line_v2(v1, v3, v2, v4) > 0); } - diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c index f32b477787b..ac5c0033067 100644 --- a/source/blender/blenlib/intern/math_geom_inline.c +++ b/source/blender/blenlib/intern/math_geom_inline.c @@ -185,4 +185,9 @@ MINLINE int poly_to_tri_count(const int poly_count, const int corner_count) } } +MINLINE float plane_point_side_v3(const float plane[4], const float co[3]) +{ + return dot_v3v3(co, plane) + plane[3]; +} + #endif /* __MATH_GEOM_INLINE_C__ */ diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c index 81d931cfba6..d1acd45e40e 100644 --- a/source/blender/blenlib/intern/math_interp.c +++ b/source/blender/blenlib/intern/math_interp.c @@ -26,6 +26,10 @@ * */ +/** \file blender/blenlib/intern/math_interp.c + * \ingroup bli + */ + #include <math.h> #include "BLI_math.h" diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 611b3298c38..d24200fc0b7 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -322,6 +322,24 @@ void mul_serie_m4(float answ[4][4], float m1[4][4], } } +void mul_v2_m3v2(float r[2], float m[3][3], float v[2]) +{ + float temp[3], warped[3]; + + copy_v2_v2(temp, v); + temp[2] = 1.0f; + + mul_v3_m3v3(warped, m, temp); + + r[0] = warped[0] / warped[2]; + r[1] = warped[1] / warped[2]; +} + +void mul_m3_v2(float m[3][3], float r[2]) +{ + mul_v2_m3v2(r, m, r); +} + void mul_m4_v3(float mat[4][4], float vec[3]) { float x, y; diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index 9fd8c479d6e..6bac102e1b1 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -62,7 +62,7 @@ void copy_qt_qt(float q1[4], const float q2[4]) q1[3] = q2[3]; } -int is_zero_qt(float *q) +bool is_zero_qt(const float q[4]) { return (q[0] == 0 && q[1] == 0 && q[2] == 0 && q[3] == 0); } @@ -817,7 +817,8 @@ void mat4_to_axis_angle(float axis[3], float *angle, float mat[4][4]) quat_to_axis_angle(axis, angle, q); } -void single_axis_angle_to_mat3(float mat[3][3], const char axis, const float angle) +/* rotation matrix from a single axis */ +void axis_angle_to_mat3_single(float mat[3][3], const char axis, const float angle) { const float angle_cos = cosf(angle); const float angle_sin = sinf(angle); @@ -862,6 +863,18 @@ void single_axis_angle_to_mat3(float mat[3][3], const char axis, const float ang } } +void angle_to_mat2(float mat[2][2], const float angle) +{ + const float angle_cos = cosf(angle); + const float angle_sin = sinf(angle); + + /* 2D rotation matrix */ + mat[0][0] = angle_cos; + mat[0][1] = angle_sin; + mat[1][0] = -angle_sin; + mat[1][1] = angle_cos; +} + /******************************** XYZ Eulers *********************************/ /* XYZ order */ @@ -993,7 +1006,7 @@ void quat_to_eul(float *eul, const float quat[4]) } /* XYZ order */ -void eul_to_quat(float *quat, const float eul[3]) +void eul_to_quat(float quat[4], const float eul[3]) { float ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss; @@ -1018,7 +1031,7 @@ void eul_to_quat(float *quat, const float eul[3]) } /* XYZ order */ -void rotate_eul(float *beul, const char axis, const float ang) +void rotate_eul(float beul[3], const char axis, const float ang) { float eul[3], mat1[3][3], mat2[3][3], totmat[3][3]; @@ -1229,7 +1242,7 @@ void eulO_to_mat3(float M[3][3], const float e[3], const short order) } /* returns two euler calculation methods, so we can pick the best */ -static void mat3_to_eulo2(float M[3][3], float *e1, float *e2, const short order) +static void mat3_to_eulo2(float M[3][3], float e1[3], float e2[3], const short order) { const RotOrderInfo *R = GET_ROTATIONORDER_INFO(order); short i = R->axis[0], j = R->axis[1], k = R->axis[2]; @@ -1478,9 +1491,10 @@ void mat4_to_dquat(DualQuat *dq, float basemat[4][4], float mat[4][4]) dq->trans[3] = 0.5f * ( t[0] * q[2] - t[1] * q[1] + t[2] * q[0]); } -void dquat_to_mat4(float mat[4][4], DualQuat *dq) +void dquat_to_mat4(float mat[4][4], const DualQuat *dq) { - float len, *t, q0[4]; + float len, q0[4]; + const float *t; /* regular quaternion */ copy_qt_qt(q0, dq->quat); @@ -1502,7 +1516,7 @@ void dquat_to_mat4(float mat[4][4], DualQuat *dq) /* note: this does not handle scaling */ } -void add_weighted_dq_dq(DualQuat *dqsum, DualQuat *dq, float weight) +void add_weighted_dq_dq(DualQuat *dqsum, const DualQuat *dq, float weight) { int flipped = 0; @@ -1530,7 +1544,7 @@ void add_weighted_dq_dq(DualQuat *dqsum, DualQuat *dq, float weight) if (flipped) /* we don't want negative weights for scaling */ weight = -weight; - copy_m4_m4(wmat, dq->scale); + copy_m4_m4(wmat, (float(*)[4])dq->scale); mul_m4_fl(wmat, weight); add_m4_m4m4(dqsum->scale, dqsum->scale, wmat); dqsum->scale_weight += weight; @@ -1609,7 +1623,7 @@ void mul_v3m3_dq(float co[3], float mat[3][3], DualQuat *dq) } } -void copy_dq_dq(DualQuat *dq1, DualQuat *dq2) +void copy_dq_dq(DualQuat *dq1, const DualQuat *dq2) { memcpy(dq1, dq2, sizeof(DualQuat)); } diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index 8e5040d983b..ce5d9657c7f 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -771,61 +771,76 @@ MINLINE void normal_float_to_short_v3(short out[3], const float in[3]) /********************************* Comparison ********************************/ -MINLINE int is_zero_v2(const float v[2]) +MINLINE bool is_zero_v2(const float v[2]) { return (v[0] == 0 && v[1] == 0); } -MINLINE int is_zero_v3(const float v[3]) +MINLINE bool is_zero_v3(const float v[3]) { return (v[0] == 0 && v[1] == 0 && v[2] == 0); } -MINLINE int is_zero_v4(const float v[4]) +MINLINE bool is_zero_v4(const float v[4]) { return (v[0] == 0 && v[1] == 0 && v[2] == 0 && v[3] == 0); } -MINLINE int is_one_v3(const float v[3]) +MINLINE bool is_finite_v2(const float v[2]) +{ + return (finite(v[0]) && finite(v[1])); +} + +MINLINE bool is_finite_v3(const float v[3]) +{ + return (finite(v[0]) && finite(v[1]) && finite(v[2])); +} + +MINLINE bool is_finite_v4(const float v[4]) +{ + return (finite(v[0]) && finite(v[1]) && finite(v[2]) && finite(v[3])); +} + +MINLINE bool is_one_v3(const float v[3]) { return (v[0] == 1 && v[1] == 1 && v[2] == 1); } -MINLINE int equals_v2v2(const float v1[2], const float v2[2]) +MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) { return ((v1[0] == v2[0]) && (v1[1] == v2[1])); } -MINLINE int equals_v3v3(const float v1[3], const float v2[3]) +MINLINE bool equals_v3v3(const float v1[3], const float v2[3]) { return ((v1[0] == v2[0]) && (v1[1] == v2[1]) && (v1[2] == v2[2])); } -MINLINE int equals_v4v4(const float v1[4], const float v2[4]) +MINLINE bool equals_v4v4(const float v1[4], const float v2[4]) { return ((v1[0] == v2[0]) && (v1[1] == v2[1]) && (v1[2] == v2[2]) && (v1[3] == v2[3])); } -MINLINE int compare_v2v2(const float v1[2], const float v2[2], const float limit) +MINLINE bool compare_v2v2(const float v1[2], const float v2[2], const float limit) { if (fabsf(v1[0] - v2[0]) < limit) if (fabsf(v1[1] - v2[1]) < limit) - return 1; + return true; - return 0; + return false; } -MINLINE int compare_v3v3(const float v1[3], const float v2[3], const float limit) +MINLINE bool compare_v3v3(const float v1[3], const float v2[3], const float limit) { if (fabsf(v1[0] - v2[0]) < limit) if (fabsf(v1[1] - v2[1]) < limit) if (fabsf(v1[2] - v2[2]) < limit) - return 1; + return true; - return 0; + return false; } -MINLINE int compare_len_v3v3(const float v1[3], const float v2[3], const float limit) +MINLINE bool compare_len_v3v3(const float v1[3], const float v2[3], const float limit) { float x, y, z; @@ -836,15 +851,15 @@ MINLINE int compare_len_v3v3(const float v1[3], const float v2[3], const float l return ((x * x + y * y + z * z) < (limit * limit)); } -MINLINE int compare_v4v4(const float v1[4], const float v2[4], const float limit) +MINLINE bool compare_v4v4(const float v1[4], const float v2[4], const float limit) { if (fabsf(v1[0] - v2[0]) < limit) if (fabsf(v1[1] - v2[1]) < limit) if (fabsf(v1[2] - v2[2]) < limit) if (fabsf(v1[3] - v2[3]) < limit) - return 1; + return true; - return 0; + return false; } MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2]) diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 2c06a812c8a..d323098827b 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -46,20 +46,12 @@ #include "BLI_path_util.h" #include "BLI_string.h" #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" -#if defined WIN32 && !defined _LIBC || defined __sun -# include "BLI_fnmatch.h" /* use fnmatch included in blenlib */ -#else -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# endif -# include <fnmatch.h> -#endif - #ifdef WIN32 # include "utf_winfunc.h" # include "utfconv.h" @@ -1332,15 +1324,20 @@ const char *BLI_get_folder_version(const int id, const int ver, const bool do_ch #endif /** - * Sets the specified environment variable to the specified value. + * Sets the specified environment variable to the specified value, + * and clears it if val == NULL. */ void BLI_setenv(const char *env, const char *val) { /* free windows */ #if (defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS) - char *envstr = MEM_mallocN(sizeof(char) * (strlen(env) + strlen(val) + 2), "envstr"); /* one for = another for \0 */ + char *envstr; + + if (val) + envstr = BLI_sprintfN("%s=%s", env, val); + else + envstr = BLI_sprintfN("%s=", env); - sprintf(envstr, "%s=%s", env, val); putenv(envstr); MEM_freeN(envstr); @@ -1351,7 +1348,10 @@ void BLI_setenv(const char *env, const char *val) #else /* linux/osx/bsd */ - setenv(env, val, 1); + if (val) + setenv(env, val, 1); + else + unsetenv(env); #endif } @@ -1649,6 +1649,16 @@ bool BLI_ensure_extension(char *path, size_t maxlen, const char *ext) return true; } +bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename) +{ + char *c = (char *)BLI_last_slash(filepath); + if (!c || ((c - filepath) < maxlen - (strlen(filename) + 1))) { + strcpy(c ? &c[1] : filepath, filename); + return true; + } + return false; +} + /* Converts "/foo/bar.txt" to "/foo/" and "bar.txt" * - wont change 'string' * - wont create any directories @@ -1693,7 +1703,7 @@ void BLI_split_file_part(const char *string, char *file, const size_t filelen) /** * Append a filename to a dir, ensuring slash separates. */ -void BLI_path_append(char *dst, const size_t maxlen, const char *file) +void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file) { size_t dirlen = BLI_strnlen(dst, maxlen); @@ -1714,7 +1724,7 @@ void BLI_path_append(char *dst, const size_t maxlen, const char *file) * Simple appending of filename to dir, does not check for valid path! * Puts result into *dst, which may be same area as *dir. */ -void BLI_join_dirfile(char *dst, const size_t maxlen, const char *dir, const char *file) +void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__restrict dir, const char *__restrict file) { size_t dirlen = BLI_strnlen(dir, maxlen); diff --git a/source/blender/blenlib/intern/quadric.c b/source/blender/blenlib/intern/quadric.c index b06534d282a..8c831bdada0 100644 --- a/source/blender/blenlib/intern/quadric.c +++ b/source/blender/blenlib/intern/quadric.c @@ -35,6 +35,8 @@ //#include <string.h> #include "BLI_math.h" +#include "BLI_strict_flags.h" + #include "BLI_quadric.h" /* own include */ diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c index 743d910e418..c5b58e5a61b 100644 --- a/source/blender/blenlib/intern/rand.c +++ b/source/blender/blenlib/intern/rand.c @@ -175,20 +175,10 @@ float BLI_frand(void) float BLI_hash_frand(unsigned int seed) { - r_uint64 X; - - seed = seed + hash[seed & 255]; - X = (((r_uint64) seed) << 16) | LOWSEED; - seed = (int)(((MULTIPLIER * X + ADDEND) & MASK) >> 17); - - seed = seed + hash[seed & 255]; - X = (((r_uint64) seed) << 16) | LOWSEED; - X = (int)(((MULTIPLIER * X + ADDEND) & MASK) >> 17); - - seed = seed + hash[seed & 255]; - X = (((r_uint64) seed) << 16) | LOWSEED; + RNG rng; - return (int)(((MULTIPLIER * X + ADDEND) & MASK) >> 17); + BLI_rng_srandom(&rng, seed); + return BLI_rng_get_float(&rng); } void BLI_array_randomize(void *data, int elemSize, int numElems, unsigned int seed) diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c index c7163874dca..a292c2275c9 100644 --- a/source/blender/blenlib/intern/scanfill.c +++ b/source/blender/blenlib/intern/scanfill.c @@ -40,49 +40,17 @@ #include "BLI_callbacks.h" #include "BLI_listbase.h" #include "BLI_math.h" -#include "BLI_scanfill.h" +#include "BLI_memarena.h" #include "BLI_utildefines.h" +#include "BLI_strict_flags.h" -/* callbacks for errors and interrupts and some goo */ -static void (*BLI_localErrorCallBack)(const char *) = NULL; - -/** - * Set a function taking a (char *) as argument to flag errors. If the - * callback is not set, the error is discarded. - * \param f The function to use as callback - * \attention used in creator.c - */ -void BLI_setErrorCallBack(void (*f)(const char *)) -{ - BLI_localErrorCallBack = f; -} - -/* just flush the error to /dev/null if the error handler is missing */ -void callLocalErrorCallBack(const char *msg) -{ - if (BLI_localErrorCallBack) { - BLI_localErrorCallBack(msg); - } -} - -#if 0 -/* ignore if the interrupt wasn't set */ -static int callLocalInterruptCallBack(void) -{ - if (BLI_localInterruptCallBack) { - return BLI_localInterruptCallBack(); - } - else { - return 0; - } -} -#endif +#include "BLI_scanfill.h" /* own include */ /* local types */ typedef struct PolyFill { - int edges, verts; + unsigned int edges, verts; float min_xy[2], max_xy[2]; - short f, nr; + unsigned short f, nr; } PolyFill; typedef struct ScanFillVertLink { @@ -132,99 +100,45 @@ static int vergpoly(const void *a1, const void *a2) return 0; } -/* ************* MEMORY MANAGEMENT ************* */ - -/* memory management */ -struct mem_elements { - struct mem_elements *next, *prev; - char *data; -}; +/* **** FILL ROUTINES *************************** */ -static void *mem_element_new(ScanFillContext *sf_ctx, int size) +ScanFillVert *BLI_scanfill_vert_add(ScanFillContext *sf_ctx, const float vec[3]) { - BLI_assert(!(size > 10000 || size == 0)); /* this is invalid use! */ - - size = (size + 3) & ~3; /* allocate in units of 4 */ + ScanFillVert *sf_v; - if (sf_ctx->melem__cur && (size + sf_ctx->melem__offs < MEM_ELEM_BLOCKSIZE)) { - void *adr = (void *) (sf_ctx->melem__cur->data + sf_ctx->melem__offs); - sf_ctx->melem__offs += size; - return adr; - } - else { - sf_ctx->melem__cur = MEM_callocN(sizeof(struct mem_elements), "newmem"); - sf_ctx->melem__cur->data = MEM_callocN(MEM_ELEM_BLOCKSIZE, "newmem"); - BLI_addtail(&sf_ctx->melem__lb, sf_ctx->melem__cur); - - sf_ctx->melem__offs = size; - return sf_ctx->melem__cur->data; - } -} -static void mem_element_reset(ScanFillContext *sf_ctx, int keep_first) -{ - struct mem_elements *first; - - if ((first = sf_ctx->melem__lb.first)) { /* can be false if first fill fails */ - if (keep_first) { - BLI_remlink(&sf_ctx->melem__lb, first); - } - - sf_ctx->melem__cur = sf_ctx->melem__lb.first; - while (sf_ctx->melem__cur) { - MEM_freeN(sf_ctx->melem__cur->data); - sf_ctx->melem__cur = sf_ctx->melem__cur->next; - } - BLI_freelistN(&sf_ctx->melem__lb); + sf_v = BLI_memarena_alloc(sf_ctx->arena, sizeof(ScanFillVert)); - /*reset the block we're keeping*/ - if (keep_first) { - BLI_addtail(&sf_ctx->melem__lb, first); - memset(first->data, 0, MEM_ELEM_BLOCKSIZE); - } - else { - first = NULL; - - } - } - - sf_ctx->melem__cur = first; - sf_ctx->melem__offs = 0; -} - -void BLI_scanfill_end(ScanFillContext *sf_ctx) -{ - mem_element_reset(sf_ctx, FALSE); - - sf_ctx->fillvertbase.first = sf_ctx->fillvertbase.last = NULL; - sf_ctx->filledgebase.first = sf_ctx->filledgebase.last = NULL; - sf_ctx->fillfacebase.first = sf_ctx->fillfacebase.last = NULL; -} + BLI_addtail(&sf_ctx->fillvertbase, sf_v); -/* **** FILL ROUTINES *************************** */ + sf_v->tmp.p = NULL; + copy_v3_v3(sf_v->co, vec); -ScanFillVert *BLI_scanfill_vert_add(ScanFillContext *sf_ctx, const float vec[3]) -{ - ScanFillVert *eve; - - eve = mem_element_new(sf_ctx, sizeof(ScanFillVert)); - BLI_addtail(&sf_ctx->fillvertbase, eve); - - copy_v3_v3(eve->co, vec); + /* just zero out the rest */ + zero_v2(sf_v->xy); + sf_v->keyindex = 0; + sf_v->poly_nr = 0; + sf_v->edge_tot = 0; + sf_v->f = 0; - return eve; + return sf_v; } ScanFillEdge *BLI_scanfill_edge_add(ScanFillContext *sf_ctx, ScanFillVert *v1, ScanFillVert *v2) { - ScanFillEdge *newed; + ScanFillEdge *sf_ed; - newed = mem_element_new(sf_ctx, sizeof(ScanFillEdge)); - BLI_addtail(&sf_ctx->filledgebase, newed); + sf_ed = BLI_memarena_alloc(sf_ctx->arena, sizeof(ScanFillEdge)); + BLI_addtail(&sf_ctx->filledgebase, sf_ed); - newed->v1 = v1; - newed->v2 = v2; + sf_ed->v1 = v1; + sf_ed->v2 = v2; - return newed; + /* just zero out the rest */ + sf_ed->poly_nr = 0; + sf_ed->f = 0; + sf_ed->tmp.c = 0; + + return sf_ed; } static void addfillface(ScanFillContext *sf_ctx, ScanFillVert *v1, ScanFillVert *v2, ScanFillVert *v3) @@ -232,7 +146,7 @@ static void addfillface(ScanFillContext *sf_ctx, ScanFillVert *v1, ScanFillVert /* does not make edges */ ScanFillFace *sf_tri; - sf_tri = mem_element_new(sf_ctx, sizeof(ScanFillFace)); + sf_tri = BLI_memarena_alloc(sf_ctx->arena, sizeof(ScanFillFace)); BLI_addtail(&sf_ctx->fillfacebase, sf_tri); sf_tri->v1 = v1; @@ -240,7 +154,7 @@ static void addfillface(ScanFillContext *sf_ctx, ScanFillVert *v1, ScanFillVert sf_tri->v3 = v3; } -static int boundisect(PolyFill *pf2, PolyFill *pf1) +static bool boundisect(PolyFill *pf2, PolyFill *pf1) { /* has pf2 been touched (intersected) by pf1 ? with bounding box */ /* test first if polys exist */ @@ -287,7 +201,7 @@ static void mergepolysSimp(ScanFillContext *sf_ctx, PolyFill *pf1, PolyFill *pf2 pf1->f = (pf1->f | pf2->f); } -static short testedgeside(const float v1[2], const float v2[2], const float v3[2]) +static bool testedgeside(const float v1[2], const float v2[2], const float v3[2]) /* is v3 to the right of v1-v2 ? With exception: v3 == v1 || v3 == v2 */ { float inp; @@ -298,14 +212,14 @@ static short testedgeside(const float v1[2], const float v2[2], const float v3[2 if (inp < 0.0f) { return 0; } - else if (inp == 0) { + 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; } return 1; } -static short addedgetoscanvert(ScanFillVertLink *sc, ScanFillEdge *eed) +static bool addedgetoscanvert(ScanFillVertLink *sc, ScanFillEdge *eed) { /* find first edge to the right of eed, and insert eed before that */ ScanFillEdge *ed; @@ -354,7 +268,7 @@ static short addedgetoscanvert(ScanFillVertLink *sc, ScanFillEdge *eed) } -static ScanFillVertLink *addedgetoscanlist(ScanFillContext *sf_ctx, ScanFillEdge *eed, int len) +static ScanFillVertLink *addedgetoscanlist(ScanFillContext *sf_ctx, ScanFillEdge *eed, unsigned int len) { /* inserts edge at correct location in ScanFillVertLink list */ /* returns sc when edge already exists */ @@ -379,13 +293,17 @@ static ScanFillVertLink *addedgetoscanlist(ScanFillContext *sf_ctx, ScanFillEdge sc = (ScanFillVertLink *)bsearch(&scsearch, sf_ctx->_scdata, len, sizeof(ScanFillVertLink), vergscdata); - if (sc == NULL) printf("Error in search edge: %p\n", (void *)eed); - else if (addedgetoscanvert(sc, eed) == 0) return sc; + if (UNLIKELY(sc == NULL)) { + printf("Error in search edge: %p\n", (void *)eed); + } + else if (addedgetoscanvert(sc, eed) == false) { + return sc; + } return NULL; } -static short boundinsideEV(ScanFillEdge *eed, ScanFillVert *eve) +static bool boundinsideEV(ScanFillEdge *eed, ScanFillVert *eve) /* is eve inside boundbox eed */ { float minx, maxx, miny, maxy; @@ -476,7 +394,7 @@ static void testvertexnearedge(ScanFillContext *sf_ctx) } } -static void splitlist(ScanFillContext *sf_ctx, ListBase *tempve, ListBase *temped, short nr) +static void splitlist(ScanFillContext *sf_ctx, ListBase *tempve, ListBase *temped, unsigned short nr) { /* everything is in templist, write only poly nr to fillist */ ScanFillVert *eve, *nextve; @@ -505,15 +423,14 @@ static void splitlist(ScanFillContext *sf_ctx, ListBase *tempve, ListBase *tempe } } -static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) +static unsigned int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) { ScanFillVertLink *sc = NULL, *sc1; ScanFillVert *eve, *v1, *v2, *v3; ScanFillEdge *eed, *nexted, *ed1, *ed2, *ed3; - int a, b, verts, maxface, totface; - short nr, twoconnected = 0; - - nr = pf->nr; + unsigned int a, b, verts, maxface, totface; + const unsigned short nr = pf->nr; + bool twoconnected = false; /* PRINTS */ #if 0 @@ -629,7 +546,8 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) /* STEP 2: FILL LOOP */ - if (pf->f == 0) twoconnected = 1; + if (pf->f == 0) + twoconnected = true; /* (temporal) security: never much more faces than vertices */ totface = 0; @@ -826,14 +744,36 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) void BLI_scanfill_begin(ScanFillContext *sf_ctx) { memset(sf_ctx, 0, sizeof(*sf_ctx)); + sf_ctx->arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__); } -int BLI_scanfill_calc(ScanFillContext *sf_ctx, const int flag) +void BLI_scanfill_begin_arena(ScanFillContext *sf_ctx, MemArena *arena) { - return BLI_scanfill_calc_ex(sf_ctx, flag, NULL); + memset(sf_ctx, 0, sizeof(*sf_ctx)); + sf_ctx->arena = arena; } -int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float nor_proj[3]) +void BLI_scanfill_end(ScanFillContext *sf_ctx) +{ + BLI_memarena_free(sf_ctx->arena); + sf_ctx->arena = NULL; + + sf_ctx->fillvertbase.first = sf_ctx->fillvertbase.last = NULL; + sf_ctx->filledgebase.first = sf_ctx->filledgebase.last = NULL; + sf_ctx->fillfacebase.first = sf_ctx->fillfacebase.last = NULL; +} + +void BLI_scanfill_end_arena(ScanFillContext *sf_ctx, MemArena *arena) +{ + BLI_memarena_clear(arena); + BLI_assert(sf_ctx->arena == arena); + + sf_ctx->fillvertbase.first = sf_ctx->fillvertbase.last = NULL; + sf_ctx->filledgebase.first = sf_ctx->filledgebase.last = NULL; + sf_ctx->fillfacebase.first = sf_ctx->fillfacebase.last = NULL; +} + +unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float nor_proj[3]) { /* * - fill works with its own lists, so create that first (no faces!) @@ -845,34 +785,36 @@ int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float no */ ListBase tempve, temped; ScanFillVert *eve; - ScanFillEdge *eed, *nexted; + ScanFillEdge *eed, *eed_next; PolyFill *pflist, *pf; float *min_xy_p, *max_xy_p; - short a, c, poly = 0, ok = 0, toggle = 0; - int totfaces = 0; /* total faces added */ + unsigned int totverts = 0, toggle = 0; + unsigned int totfaces = 0; /* total faces added */ + unsigned short a, c, poly = 0; + bool ok; float mat_2d[3][3]; BLI_assert(!nor_proj || len_squared_v3(nor_proj) > FLT_EPSILON); - /* reset variables */ eve = sf_ctx->fillvertbase.first; - a = 0; while (eve) { - eve->f = 0; - eve->poly_nr = 0; - eve->edge_tot = 0; + /* these values used to be set, + * however they should always be zero'd so check instead */ + BLI_assert(eve->f == 0); + BLI_assert(eve->poly_nr == 0); + BLI_assert(eve->edge_tot == 0); + totverts++; eve = eve->next; - a += 1; } if (flag & BLI_SCANFILL_CALC_QUADTRI_FASTPATH) { - if (a == 3) { + if (totverts == 3) { eve = sf_ctx->fillvertbase.first; addfillface(sf_ctx, eve, eve->next, eve->next->next); return 1; } - else if (a == 4) { + else if (totverts == 4) { float vec1[3], vec2[3]; eve = sf_ctx->fillvertbase.first; @@ -897,23 +839,24 @@ int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float no /* including resetting of flags */ eed = sf_ctx->filledgebase.first; while (eed) { - eed->poly_nr = 0; + BLI_assert(eed->poly_nr == 0); eed->v1->f = SF_VERT_AVAILABLE; eed->v2->f = SF_VERT_AVAILABLE; eed = eed->next; } + ok = false; eve = sf_ctx->fillvertbase.first; while (eve) { if (eve->f & SF_VERT_AVAILABLE) { - ok = 1; + ok = true; break; } eve = eve->next; } - if (ok == 0) { + if (UNLIKELY(ok == false)) { return 0; } else { @@ -959,35 +902,33 @@ int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float no if (eve->poly_nr == 0) { poly++; /* now a sort of select connected */ - ok = 1; + ok = true; eve->poly_nr = poly; while (ok) { - ok = 0; - toggle++; - if (toggle & 1) eed = sf_ctx->filledgebase.first; - else eed = sf_ctx->filledgebase.last; + ok = false; + toggle++; + eed = (toggle & 1) ? sf_ctx->filledgebase.first : sf_ctx->filledgebase.last; while (eed) { if (eed->v1->poly_nr == 0 && eed->v2->poly_nr == poly) { eed->v1->poly_nr = poly; eed->poly_nr = poly; - ok = 1; + ok = true; } else if (eed->v2->poly_nr == 0 && eed->v1->poly_nr == poly) { eed->v2->poly_nr = poly; eed->poly_nr = poly; - ok = 1; + ok = true; } else if (eed->poly_nr == 0) { if (eed->v1->poly_nr == poly && eed->v2->poly_nr == poly) { eed->poly_nr = poly; - ok = 1; + ok = true; } } - if (toggle & 1) eed = eed->next; - else eed = eed->prev; + eed = (toggle & 1) ? eed->next : eed->prev; } } } @@ -1020,35 +961,36 @@ int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float no } if (eed) { /* otherwise it's impossible to be sure you can clear vertices */ - callLocalErrorCallBack("No vertices with 250 edges allowed!"); +#ifdef DEBUG + printf("No vertices with 250 edges allowed!\n"); +#endif return 0; } /* does it only for vertices with (->h == 1) */ testvertexnearedge(sf_ctx); - ok = 1; + ok = true; while (ok) { - ok = 0; + ok = false; + toggle++; - if (toggle & 1) eed = sf_ctx->filledgebase.first; - else eed = sf_ctx->filledgebase.last; + eed = (toggle & 1) ? sf_ctx->filledgebase.first : sf_ctx->filledgebase.last; while (eed) { - if (toggle & 1) nexted = eed->next; - else nexted = eed->prev; + eed_next = (toggle & 1) ? eed->next : eed->prev; if (eed->v1->edge_tot == 1) { eed->v2->edge_tot--; BLI_remlink(&sf_ctx->fillvertbase, eed->v1); BLI_remlink(&sf_ctx->filledgebase, eed); - ok = 1; + ok = true; } else if (eed->v2->edge_tot == 1) { eed->v1->edge_tot--; BLI_remlink(&sf_ctx->fillvertbase, eed->v2); BLI_remlink(&sf_ctx->filledgebase, eed); - ok = 1; + ok = true; } - eed = nexted; + eed = eed_next; } } if (sf_ctx->filledgebase.first == NULL) { @@ -1069,12 +1011,12 @@ int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float no /* STEP 3: MAKE POLYFILL STRUCT */ - pflist = (PolyFill *)MEM_callocN(poly * sizeof(PolyFill), "edgefill"); + pflist = (PolyFill *)MEM_callocN((size_t)poly * sizeof(PolyFill), "edgefill"); pf = pflist; for (a = 1; a <= poly; a++) { pf->nr = a; - pf->min_xy[0] = pf->min_xy[1] = 1.0e20; - pf->max_xy[0] = pf->max_xy[1] = -1.0e20; + pf->min_xy[0] = pf->min_xy[1] = 1.0e20f; + pf->max_xy[0] = pf->max_xy[1] = -1.0e20f; pf++; } eed = sf_ctx->filledgebase.first; @@ -1104,10 +1046,10 @@ int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float no * WATCH IT: ONLY WORKS WITH SORTED POLYS!!! */ if (poly > 1) { - short *polycache, *pc; + unsigned short *polycache, *pc; /* so, sort first */ - qsort(pflist, poly, sizeof(PolyFill), vergpoly); + qsort(pflist, (size_t)poly, sizeof(PolyFill), vergpoly); #if 0 pf = pflist; @@ -1118,10 +1060,10 @@ int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float no } #endif - polycache = pc = MEM_callocN(sizeof(short) * poly, "polycache"); + polycache = pc = MEM_callocN(sizeof(short) * (size_t)poly, "polycache"); pf = pflist; for (a = 0; a < poly; a++, pf++) { - for (c = a + 1; c < poly; c++) { + for (c = (unsigned short)(a + 1); c < poly; c++) { /* if 'a' inside 'c': join (bbox too) * Careful: 'a' can also be inside another poly. @@ -1177,3 +1119,8 @@ int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float no return totfaces; } + +unsigned int BLI_scanfill_calc(ScanFillContext *sf_ctx, const int flag) +{ + return BLI_scanfill_calc_ex(sf_ctx, flag, NULL); +} diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c index d255b4a9af6..19eb88f9e15 100644 --- a/source/blender/blenlib/intern/smallhash.c +++ b/source/blender/blenlib/intern/smallhash.c @@ -25,12 +25,17 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/blenlib/intern/smallhash.c + * \ingroup bli + */ + #include <string.h> #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" #include "BLI_smallhash.h" +#include "BLI_strict_flags.h" /* SMHASH_CELL_UNUSED means this cell is inside a key series, * while SMHASH_CELL_FREE means this cell terminates a key series. @@ -43,18 +48,10 @@ #define SMHASH_CELL_UNUSED ((void *)0x7FFFFFFF) #define SMHASH_CELL_FREE ((void *)0x7FFFFFFD) -#ifdef __GNUC__ -# pragma GCC diagnostic error "-Wsign-conversion" -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 /* gcc4.6+ only */ -# pragma GCC diagnostic error "-Wsign-compare" -# pragma GCC diagnostic error "-Wconversion" -# endif -#endif - /* typically this re-assigns 'h' */ #define SMHASH_NEXT(h, hoff) ( \ - CHECK_TYPE_INLINE(&(h), unsigned int), \ - CHECK_TYPE_INLINE(&(hoff), unsigned int), \ + CHECK_TYPE_INLINE(&(h), unsigned int *), \ + CHECK_TYPE_INLINE(&(hoff), unsigned int *), \ ((h) + (((hoff) = ((hoff) * 2) + 1), (hoff))) \ ) diff --git a/source/blender/blenlib/intern/sort.c b/source/blender/blenlib/intern/sort.c new file mode 100644 index 00000000000..44110564948 --- /dev/null +++ b/source/blender/blenlib/intern/sort.c @@ -0,0 +1,173 @@ +/* + * ***** 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) 2013 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Benoit Bolsee, + * Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenlib/intern/sort.c + * \ingroup bli + */ + +#include <stdlib.h> + +#include "BLI_utildefines.h" + +#include "BLI_sort.h" + +/* **** qsort based on FreeBSD source (libkern\qsort.c) **** */ +BLI_INLINE char *med3(char *, char *, char *, BLI_sort_cmp_t, void *); +BLI_INLINE void swapfunc(char *, char *, int, int); + +#define min(a, b) (a) < (b) ? a : b +#define swapcode(TYPE, parmi, parmj, n) \ +{ \ + long i = (n) / sizeof(TYPE); \ + TYPE *pi = (TYPE *) (parmi); \ + TYPE *pj = (TYPE *) (parmj); \ + do { \ + TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +BLI_INLINE void swapfunc(char *a, char *b, int n, int swaptype) +{ + if (swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b);\ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) +#define CMP(t, x, y) (cmp((t), (x), (y))) + +BLI_INLINE char *med3(char *a, char *b, char *c, BLI_sort_cmp_t cmp, void *thunk) +{ + return CMP(thunk, a, b) < 0 ? + (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a )) + :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c )); +} + +/** + * Quick sort reentrant. + * + * \note Follows BSD arg order (incompatible with glibc). + */ +void BLI_qsort_r(void *a, size_t n, size_t es, void *thunk, BLI_sort_cmp_t cmp) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + +loop: + SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) { + for (pl = pm; + pl > (char *)a && CMP(thunk, pl - es, pl) > 0; + pl -= es) + { + swap(pl, pl - es); + } + } + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = (char *)a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk); + pm = med3(pm - d, pm, pm + d, cmp, thunk); + pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk); + } + pm = med3(pl, pm, pn, cmp, thunk); + } + swap((char *)a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = CMP(thunk, pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = CMP(thunk, pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) { + for (pl = pm; + pl > (char *)a && CMP(thunk, pl - es, pl) > 0; + pl -= es) + { + swap(pl, pl - es); + } + } + return; + } + + pn = (char *)a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap((char *)a, pb - r, r); + r = min(pd - pc, pn - pd - es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > es) + BLI_qsort_r(a, r / es, es, thunk, cmp); + if ((r = pd - pc) > es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +} diff --git a/source/blender/blenlib/intern/sort_utils.c b/source/blender/blenlib/intern/sort_utils.c new file mode 100644 index 00000000000..c75e8e7455f --- /dev/null +++ b/source/blender/blenlib/intern/sort_utils.c @@ -0,0 +1,74 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenlib/intern/sort_utils.c + * \ingroup bli + * + * Utility functions for sorting common types. + */ + +#include "BLI_sort_utils.h" /* own include */ + +struct SortAnyByFloat { + float sort_value; +}; + +struct SortAnyByInt { + int sort_value; +}; + +int BLI_sortutil_cmp_float(const void *a_, const void *b_) +{ + const struct SortAnyByFloat *a = a_; + const struct SortAnyByFloat *b = b_; + if (a->sort_value > b->sort_value) return 1; + else if (a->sort_value < b->sort_value) return -1; + else return 0; +} + +int BLI_sortutil_cmp_float_reverse(const void *a_, const void *b_) +{ + const struct SortAnyByFloat *a = a_; + const struct SortAnyByFloat *b = b_; + if (a->sort_value < b->sort_value) return 1; + else if (a->sort_value > b->sort_value) return -1; + else return 0; +} + +int BLI_sortutil_cmp_int(const void *a_, const void *b_) +{ + const struct SortAnyByInt *a = a_; + const struct SortAnyByInt *b = b_; + if (a->sort_value > b->sort_value) return 1; + else if (a->sort_value < b->sort_value) return -1; + else return 0; +} + +int BLI_sortutil_cmp_int_reverse(const void *a_, const void *b_) +{ + const struct SortAnyByInt *a = a_; + const struct SortAnyByInt *b = b_; + if (a->sort_value < b->sort_value) return 1; + else if (a->sort_value > b->sort_value) return -1; + else return 0; +} diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index 34c6e632131..e40527b1bb6 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -70,7 +70,6 @@ #ifdef WIN32 # include <io.h> # include <direct.h> -# include <limits.h> /* PATH_MAX */ # include "BLI_winstuff.h" # include "utfconv.h" #else diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c index 2b6fb52c49c..c8b84d9310a 100644 --- a/source/blender/blenlib/intern/threads.c +++ b/source/blender/blenlib/intern/threads.c @@ -107,7 +107,7 @@ static void *thread_tls_data; * BLI_end_threads(&lb); * ************************************************ */ -static pthread_mutex_t _malloc_lock = PTHREAD_MUTEX_INITIALIZER; +static SpinLock _malloc_lock; static pthread_mutex_t _image_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t _image_draw_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t _viewer_lock = PTHREAD_MUTEX_INITIALIZER; @@ -134,17 +134,24 @@ typedef struct ThreadSlot { static void BLI_lock_malloc_thread(void) { - pthread_mutex_lock(&_malloc_lock); + BLI_spin_lock(&_malloc_lock); } static void BLI_unlock_malloc_thread(void) { - pthread_mutex_unlock(&_malloc_lock); + BLI_spin_unlock(&_malloc_lock); } void BLI_threadapi_init(void) { mainid = pthread_self(); + + BLI_spin_init(&_malloc_lock); +} + +void BLI_threadapi_exit(void) +{ + BLI_spin_end(&_malloc_lock); } /* tot = 0 only initializes malloc mutex in a safe way (see sequence.c) diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 00ff5863e59..58d0cf6d264 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -265,7 +265,10 @@ void BLO_main_expander(void (*expand_doit_func)(void *, struct Main *, void *)); * \param mainvar the Main database to expand */ void BLO_expand_main(void *fdhandle, struct Main *mainvar); - + +/* Update defaults in startup.blend, without having to save and embed it */ +void BLO_update_defaults_startup_blend(struct Main *mainvar); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 104c58b1c9e..f865962bac9 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -46,6 +46,7 @@ set(SRC intern/runtime.c intern/undofile.c intern/versioning_250.c + intern/versioning_defaults.c intern/versioning_legacy.c intern/writefile.c diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index aec91dedf8f..9ae2858f526 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -222,7 +222,7 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *to LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh) { FileData *fd = (FileData *) bh; - GHash *gathered = BLI_ghash_ptr_new("linkable_groups gh"); + GSet *gathered = BLI_gset_ptr_new("linkable_groups gh"); LinkNode *names = NULL; BHead *bhead; @@ -234,15 +234,15 @@ LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh) if (BKE_idcode_is_linkable(bhead->code)) { const char *str = BKE_idcode_to_name(bhead->code); - if (!BLI_ghash_haskey(gathered, (void *)str)) { + if (!BLI_gset_haskey(gathered, (void *)str)) { BLI_linklist_prepend(&names, strdup(str)); - BLI_ghash_insert(gathered, (void *)str, NULL); + BLI_gset_insert(gathered, (void *)str); } } } } - BLI_ghash_free(gathered, NULL, NULL); + BLI_gset_free(gathered, NULL); return names; } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 1f8bbfbec88..077b476c408 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -151,6 +151,7 @@ #include "BKE_text.h" // for txt_extended_ascii_as_utf8 #include "BKE_texture.h" #include "BKE_tracking.h" +#include "BKE_treehash.h" #include "BKE_sound.h" #include "IMB_imbuf.h" // for proxy / timecode versioning stuff @@ -249,11 +250,7 @@ static void convert_tface_mt(FileData *fd, Main *main); * we could alternatively have a versions of a report function which forces printing - campbell */ -static void BKE_reportf_wrap(ReportList *reports, ReportType type, const char *format, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 3, 4))) -#endif -; +static void BKE_reportf_wrap(ReportList *reports, ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4); static void BKE_reportf_wrap(ReportList *reports, ReportType type, const char *format, ...) { char fixed_buf[1024]; /* should be long enough */ @@ -1779,6 +1776,27 @@ static void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, FileData } } +#define IDP_DirectLinkGroup_OrFree(prop, switch_endian, fd) \ + _IDP_DirectLinkGroup_OrFree(prop, switch_endian, fd, __func__) + +static void _IDP_DirectLinkGroup_OrFree(IDProperty **prop, int switch_endian, FileData *fd, + const char *caller_func_id) +{ + if (*prop) { + if ((*prop)->type == IDP_GROUP) { + IDP_DirectLinkGroup(*prop, switch_endian, fd); + } + else { + /* corrupt file! */ + printf("%s: found non group data, freeing type %d!\n", + caller_func_id, (*prop)->type); + /* don't risk id, data's likely corrupt. */ + // IDP_FreeProperty(*prop); + *prop = NULL; + } + } +} + /* stub function */ static void IDP_LibLinkProperty(IDProperty *UNUSED(prop), int UNUSED(switch_endian), FileData *UNUSED(fd)) { @@ -1791,9 +1809,8 @@ static void direct_link_id(FileData *fd, ID *id) /*link direct data of ID properties*/ if (id->properties) { id->properties = newdataadr(fd, id->properties); - if (id->properties) { /* this case means the data was written incorrectly, it should not happen */ - IDP_DirectLinkProperty(id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); - } + /* this case means the data was written incorrectly, it should not happen */ + IDP_DirectLinkGroup_OrFree(&id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); } } @@ -2044,7 +2061,7 @@ static void direct_link_fmodifiers(FileData *fd, ListBase *list) FMod_Python *data = (FMod_Python *)fcm->data; data->prop = newdataadr(fd, data->prop); - IDP_DirectLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_DirectLinkGroup_OrFree(&data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); } break; } @@ -2599,8 +2616,7 @@ static void lib_verify_nodetree(Main *main, int UNUSED(open)) static void direct_link_node_socket(FileData *fd, bNodeSocket *sock) { sock->prop = newdataadr(fd, sock->prop); - if (sock->prop) - IDP_DirectLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_DirectLinkGroup_OrFree(&sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); sock->link = newdataadr(fd, sock->link); sock->typeinfo = NULL; @@ -2638,8 +2654,7 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree) link_list(fd, &node->outputs); node->prop = newdataadr(fd, node->prop); - if (node->prop) - IDP_DirectLinkProperty(node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_DirectLinkGroup_OrFree(&node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); link_list(fd, &node->internal_links); for (link = node->internal_links.first; link; link = link->next) { @@ -2797,8 +2812,7 @@ static void direct_link_constraints(FileData *fd, ListBase *lb) link_list(fd, &data->targets); data->prop = newdataadr(fd, data->prop); - if (data->prop) - IDP_DirectLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_DirectLinkGroup_OrFree(&data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); break; } case CONSTRAINT_TYPE_SPLINEIK: @@ -2897,8 +2911,7 @@ static void direct_link_bones(FileData *fd, Bone *bone) bone->parent = newdataadr(fd, bone->parent); bone->prop = newdataadr(fd, bone->prop); - if (bone->prop) - IDP_DirectLinkProperty(bone->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_DirectLinkGroup_OrFree(&bone->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); bone->flag &= ~BONE_DRAW_ACTIVE; @@ -3123,7 +3136,6 @@ static void direct_link_mball(FileData *fd, MetaBall *mb) mb->disp.first = mb->disp.last = NULL; mb->editelems = NULL; - mb->bb = NULL; /* mb->edit_elems.first= mb->edit_elems.last= NULL;*/ mb->lastelem = NULL; } @@ -3399,11 +3411,9 @@ static void direct_link_curve(FileData *fd, Curve *cu) if (cu->wordspace == 0.0f) cu->wordspace = 1.0f; } - cu->bev.first = cu->bev.last = NULL; cu->disp.first = cu->disp.last = NULL; cu->editnurb = NULL; cu->lastsel = NULL; - cu->path = NULL; cu->editfont = NULL; for (nu = cu->nurb.first; nu; nu = nu->next) { @@ -4106,6 +4116,8 @@ static void direct_link_customdata(FileData *fd, CustomData *data, int count) if (layer->flag & CD_FLAG_EXTERNAL) layer->flag &= ~CD_FLAG_IN_MEMORY; + + layer->flag &= ~CD_FLAG_NOFREE; if (CustomData_verify_versions(data, i)) { layer->data = newdataadr(fd, layer->data); @@ -4152,7 +4164,7 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh) direct_link_customdata(fd, &mesh->fdata, mesh->totface); direct_link_customdata(fd, &mesh->ldata, mesh->totloop); direct_link_customdata(fd, &mesh->pdata, mesh->totpoly); - + mesh->bb = NULL; mesh->edit_btmesh = NULL; @@ -4161,6 +4173,12 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh) mesh->totselect = 0; } + if (mesh->mloopuv || mesh->mtpoly) { + /* for now we have to ensure texpoly and mloopuv layers are aligned + * in the future we may allow non-aligned layers */ + BKE_mesh_cd_validate(mesh); + } + /* Multires data */ mesh->mr= newdataadr(fd, mesh->mr); if (mesh->mr) { @@ -4345,7 +4363,7 @@ static void lib_link_object(FileData *fd, Main *main) /* Only expand so as not to loose any object materials that might be set. */ if (totcol_data && (*totcol_data > ob->totcol)) { /* printf("'%s' %d -> %d\n", ob->id.name, ob->totcol, *totcol_data); */ - resize_object_material(ob, *totcol_data); + BKE_material_resize_object(ob, *totcol_data, false); } } @@ -4373,12 +4391,8 @@ static void lib_link_object(FileData *fd, Main *main) for (sens = ob->sensors.first; sens; sens = sens->next) { for (a = 0; a < sens->totlinks; a++) sens->links[a] = newglobadr(fd, sens->links[a]); - - if (sens->type == SENS_TOUCH) { - bTouchSensor *ts = sens->data; - ts->ma = newlibadr(fd, ob->id.lib, ts->ma); - } - else if (sens->type == SENS_MESSAGE) { + + if (sens->type == SENS_MESSAGE) { bMessageSensor *ms = sens->data; ms->fromObject = newlibadr(fd, ob->id.lib, ms->fromObject); @@ -4536,8 +4550,7 @@ static void direct_link_pose(FileData *fd, bPose *pose) direct_link_constraints(fd, &pchan->constraints); pchan->prop = newdataadr(fd, pchan->prop); - if (pchan->prop) - IDP_DirectLinkProperty(pchan->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_DirectLinkGroup_OrFree(&pchan->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); pchan->mpath = newdataadr(fd, pchan->mpath); if (pchan->mpath) @@ -4829,8 +4842,6 @@ static void direct_link_object(FileData *fd, Object *ob) ob->mode &= ~(OB_MODE_EDIT | OB_MODE_PARTICLE_EDIT); } - ob->disp.first = ob->disp.last = NULL; - ob->adt = newdataadr(fd, ob->adt); direct_link_animdata(fd, ob->adt); @@ -5025,6 +5036,9 @@ static void direct_link_object(FileData *fd, Object *ob) ob->gpulamp.first= ob->gpulamp.last = NULL; link_list(fd, &ob->pc_ids); + /* Runtime curve data */ + ob->curve_cache = NULL; + /* in case this value changes in future, clamp else we get undefined behavior */ CLAMP(ob->rotmode, ROT_MODE_MIN, ROT_MODE_MAX); @@ -5433,20 +5447,17 @@ static void direct_link_scene(FileData *fd, Scene *sce) } if (sce->r.ffcodecdata.properties) { sce->r.ffcodecdata.properties = newdataadr(fd, sce->r.ffcodecdata.properties); - if (sce->r.ffcodecdata.properties) { - IDP_DirectLinkProperty(sce->r.ffcodecdata.properties, - (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); - } + IDP_DirectLinkGroup_OrFree(&sce->r.ffcodecdata.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); } link_list(fd, &(sce->markers)); link_list(fd, &(sce->transform_spaces)); link_list(fd, &(sce->r.layers)); - for(srl = sce->r.layers.first; srl; srl = srl->next) { + for (srl = sce->r.layers.first; srl; srl = srl->next) { link_list(fd, &(srl->freestyleConfig.modules)); } - for(srl = sce->r.layers.first; srl; srl = srl->next) { + for (srl = sce->r.layers.first; srl; srl = srl->next) { link_list(fd, &(srl->freestyleConfig.linesets)); } @@ -5703,12 +5714,8 @@ static void lib_link_screen(FileData *fd, Main *main) tselem->id = newlibadr(fd, NULL, tselem->id); } if (so->treehash) { - /* update hash table, because it depends on ids too */ - BLI_ghash_clear(so->treehash, NULL, NULL); - BLI_mempool_iternew(so->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - BLI_ghash_insert(so->treehash, tselem, tselem); - } + /* rebuild hash table, because it depends on ids too */ + BKE_treehash_rebuild_from_treestore(so->treehash, so->treestore); } } } @@ -6044,12 +6051,8 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc tselem->id = restore_pointer_by_name(newmain, tselem->id, 0); } if (so->treehash) { - /* update hash table, because it depends on ids too */ - BLI_ghash_clear(so->treehash, NULL, NULL); - BLI_mempool_iternew(so->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - BLI_ghash_insert(so->treehash, tselem, tselem); - } + /* rebuild hash table, because it depends on ids too */ + BKE_treehash_rebuild_from_treestore(so->treehash, so->treestore); } } } @@ -6136,6 +6139,9 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) { ui_list->type = NULL; + ui_list->dyn_data = NULL; + ui_list->properties = newdataadr(fd, ui_list->properties); + IDP_DirectLinkGroup_OrFree(&ui_list->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); } if (spacetype == SPACE_EMPTY) { @@ -6324,7 +6330,7 @@ static bool direct_link_screen(FileData *fd, bScreen *sc) else if (sl->spacetype == SPACE_OUTLINER) { SpaceOops *soops = (SpaceOops *) sl; - /* use newdataadr_no_us and do not free old memory avoidign double + /* use newdataadr_no_us and do not free old memory avoiding double * frees and use of freed memory. this could happen because of a * bug fixed in revision 58959 where the treestore memory address * was not unique */ @@ -6687,6 +6693,28 @@ static void direct_link_movieTracks(FileData *fd, ListBase *tracksbase) } } +static void direct_link_moviePlaneTracks(FileData *fd, ListBase *plane_tracks_base) +{ + MovieTrackingPlaneTrack *plane_track; + + link_list(fd, plane_tracks_base); + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + int i; + + plane_track->point_tracks = newdataadr(fd, plane_track->point_tracks); + + for (i = 0; i < plane_track->point_tracksnr; i++) { + plane_track->point_tracks[i] = newdataadr(fd, plane_track->point_tracks[i]); + } + + plane_track->markers = newdataadr(fd, plane_track->markers); + } +} + static void direct_link_movieclip(FileData *fd, MovieClip *clip) { MovieTracking *tracking = &clip->tracking; @@ -6701,9 +6729,11 @@ static void direct_link_movieclip(FileData *fd, MovieClip *clip) else clip->tracking.camera.intrinsics = NULL; direct_link_movieTracks(fd, &tracking->tracks); + direct_link_moviePlaneTracks(fd, &tracking->plane_tracks); direct_link_movieReconstruction(fd, &tracking->reconstruction); clip->tracking.act_track = newdataadr(fd, clip->tracking.act_track); + clip->tracking.act_plane_track = newdataadr(fd, clip->tracking.act_plane_track); clip->anim = NULL; clip->tracking_context = NULL; @@ -6720,6 +6750,7 @@ static void direct_link_movieclip(FileData *fd, MovieClip *clip) for (object = tracking->objects.first; object; object = object->next) { direct_link_movieTracks(fd, &object->tracks); + direct_link_moviePlaneTracks(fd, &object->plane_tracks); direct_link_movieReconstruction(fd, &object->reconstruction); } } @@ -7008,16 +7039,16 @@ static void direct_link_linestyle(FileData *fd, FreestyleLineStyle *linestyle) linestyle->adt= newdataadr(fd, linestyle->adt); direct_link_animdata(fd, linestyle->adt); link_list(fd, &linestyle->color_modifiers); - for(modifier = linestyle->color_modifiers.first; modifier; modifier = modifier->next) + for (modifier = linestyle->color_modifiers.first; modifier; modifier = modifier->next) direct_link_linestyle_color_modifier(fd, modifier); link_list(fd, &linestyle->alpha_modifiers); - for(modifier = linestyle->alpha_modifiers.first; modifier; modifier = modifier->next) + for (modifier = linestyle->alpha_modifiers.first; modifier; modifier = modifier->next) direct_link_linestyle_alpha_modifier(fd, modifier); link_list(fd, &linestyle->thickness_modifiers); - for(modifier = linestyle->thickness_modifiers.first; modifier; modifier = modifier->next) + for (modifier = linestyle->thickness_modifiers.first; modifier; modifier = modifier->next) direct_link_linestyle_thickness_modifier(fd, modifier); link_list(fd, &linestyle->geometry_modifiers); - for(modifier = linestyle->geometry_modifiers.first; modifier; modifier = modifier->next) + for (modifier = linestyle->geometry_modifiers.first; modifier; modifier = modifier->next) direct_link_linestyle_geometry_modifier(fd, modifier); } @@ -7054,7 +7085,9 @@ static const char *dataname(short id_code) case ID_BR: return "Data from BR"; case ID_PA: return "Data from PA"; case ID_GD: return "Data from GD"; + case ID_WM: return "Data from WM"; case ID_MC: return "Data from MC"; + case ID_MSK: return "Data from MSK"; case ID_LS: return "Data from LS"; } return "Data from Lib Block"; @@ -7123,7 +7156,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID if (id->flag & LIB_FAKEUSER) id->us= 1; else id->us = 0; id->icon_id = 0; - id->flag &= ~(LIB_ID_RECALC|LIB_ID_RECALC_DATA); + id->flag &= ~(LIB_ID_RECALC|LIB_ID_RECALC_DATA|LIB_DOIT); /* this case cannot be direct_linked: it's just the ID part */ if (bhead->code == ID_ID) { @@ -9430,12 +9463,12 @@ static void do_versions(FileData *fd, Library *lib, Main *main) SceneRenderLayer *srl; FreestyleLineStyle *linestyle; - for(sce = main->scene.first; sce; sce = sce->id.next) { + for (sce = main->scene.first; sce; sce = sce->id.next) { if (sce->r.line_thickness_mode == 0) { sce->r.line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE; sce->r.unit_line_thickness = 1.0f; } - for(srl = sce->r.layers.first; srl; srl = srl->next) { + for (srl = sce->r.layers.first; srl; srl = srl->next) { if (srl->freestyleConfig.mode == 0) srl->freestyleConfig.mode = FREESTYLE_CONTROL_EDITOR_MODE; if (srl->freestyleConfig.raycasting_algorithm == FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE || @@ -9465,7 +9498,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } - for(linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) { + for (linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) { #if 1 /* disable the Misc panel for now */ if (linestyle->panel == LS_PANEL_MISC) { @@ -9518,8 +9551,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } - if (MAIN_VERSION_OLDER(main, 267, 1)) - { + if (MAIN_VERSION_OLDER(main, 267, 1)) { Object *ob; for (ob = main->object.first; ob; ob = ob->id.next) { @@ -9553,21 +9585,35 @@ static void do_versions(FileData *fd, Library *lib, Main *main) for (brush = main->brush.first; brush; brush = brush->id.next) { brush->flag &= ~BRUSH_FIXED; - if(brush->cursor_overlay_alpha < 2) + if (brush->cursor_overlay_alpha < 2) brush->cursor_overlay_alpha = 33; - if(brush->texture_overlay_alpha < 2) + if (brush->texture_overlay_alpha < 2) brush->texture_overlay_alpha = 33; - if(brush->mask_overlay_alpha <2) + if (brush->mask_overlay_alpha <2) brush->mask_overlay_alpha = 33; } #undef BRUSH_FIXED } - { + + if (!MAIN_VERSION_ATLEAST(main, 268, 4)) { bScreen *sc; Object *ob; for (ob = main->object.first; ob; ob = ob->id.next) { + bConstraint *con; + for (con = ob->constraints.first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) { + bShrinkwrapConstraint *data = (bShrinkwrapConstraint *)con->data; + if (data->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) data->projAxis = OB_POSX; + else if (data->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) data->projAxis = OB_POSY; + else data->projAxis = OB_POSZ; + data->projAxisSpace = CONSTRAINT_SPACE_LOCAL; + } + } + } + + for (ob = main->object.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_Smoke) { @@ -9600,12 +9646,88 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } } + + for (ob = main->object.first; ob; ob = ob->id.next) { + bSensor *sens; + bTouchSensor *ts; + bCollisionSensor *cs; + Material *ma; + + for (sens = ob->sensors.first; sens; sens = sens->next) { + if (sens->type == SENS_TOUCH) { + ts = sens->data; + cs = MEM_callocN(sizeof(bCollisionSensor), "touch -> collision sensor do_version"); + + if (ts->ma) { + ma = blo_do_versions_newlibadr(fd, ob->id.lib, ts->ma); + BLI_strncpy(cs->materialName, ma->id.name+2, sizeof(cs->materialName)); + } + + cs->mode = SENS_COLLISION_MATERIAL; + + MEM_freeN(ts); + + sens->data = cs; + sens->type = sens->otype = SENS_COLLISION; + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(main, 268, 5)) { + bScreen *sc; + ScrArea *sa; + + /* add missing (+) expander in node editor */ + for (sc = main->screen.first; sc; sc = sc->id.next) { + for (sa = sc->areabase.first; sa; sa = sa->next) { + ARegion *ar, *arnew; + + if (sa->spacetype == SPACE_NODE) { + ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS); + + if (ar) + continue; + + /* add subdiv level; after header */ + ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); + + /* is error! */ + if (ar == NULL) + continue; + + arnew = MEM_callocN(sizeof(ARegion), "node tools"); + + BLI_insertlinkafter(&sa->regionbase, ar, arnew); + arnew->regiontype = RGN_TYPE_TOOLS; + arnew->alignment = RGN_ALIGN_LEFT; + + arnew->flag = RGN_FLAG_HIDDEN; + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(main, 269, 1)) { + /* Removal of Cycles SSS Compatible falloff */ + FOREACH_NODETREE(main, ntree, id) { + if (ntree->type == NTREE_SHADER) { + bNode *node; + for (node = ntree->nodes.first; node; node = node->next) { + if (node->type == SH_NODE_SUBSURFACE_SCATTERING) { + if (node->custom1 == SHD_SUBSURFACE_COMPATIBLE) { + node->custom1 = SHD_SUBSURFACE_CUBIC; + } + } + } + } + } FOREACH_NODETREE_END } /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */ - /* don't forget to set version number in blender.c! */ + /* don't forget to set version number in BKE_blender.h! */ } #if 0 // XXX: disabled for now... we still don't have this in the right place in the loading code for it to work @@ -9661,8 +9783,7 @@ static void lib_link_all(FileData *fd, Main *main) static void direct_link_keymapitem(FileData *fd, wmKeyMapItem *kmi) { kmi->properties = newdataadr(fd, kmi->properties); - if (kmi->properties) - IDP_DirectLinkProperty(kmi->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + IDP_DirectLinkGroup_OrFree(&kmi->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); kmi->ptr = NULL; kmi->flag &= ~KMI_UPDATE; } @@ -9719,9 +9840,7 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead) for (addon = user->addons.first; addon; addon = addon->next) { addon->prop = newdataadr(fd, addon->prop); - if (addon->prop) { - IDP_DirectLinkProperty(addon->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); - } + IDP_DirectLinkGroup_OrFree(&addon->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); } // XXX @@ -10501,11 +10620,7 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob) expand_doit(fd, mainvar, psys->part); for (sens = ob->sensors.first; sens; sens = sens->next) { - if (sens->type == SENS_TOUCH) { - bTouchSensor *ts = sens->data; - expand_doit(fd, mainvar, ts->ma); - } - else if (sens->type == SENS_MESSAGE) { + if (sens->type == SENS_MESSAGE) { bMessageSensor *ms = sens->data; expand_doit(fd, mainvar, ms->fromObject); } @@ -10929,13 +11044,17 @@ static void give_base_to_groups(Main *mainvar, Scene *scene) { Group *group; - /* give all objects which are LIB_INDIRECT a base, or for a group when *lib has been set */ + /* give all objects which are tagged a base */ for (group = mainvar->group.first; group; group = group->id.next) { - if (((group->id.flag & LIB_INDIRECT)==0 && (group->id.flag & LIB_PRE_EXISTING)==0)) { + if (group->id.flag & LIB_DOIT) { Base *base; + Object *ob; + + /* any indirect group should not have been tagged */ + BLI_assert((group->id.flag & LIB_INDIRECT)==0); /* BKE_object_add(...) messes with the selection */ - Object *ob = BKE_object_add_only_object(mainvar, OB_EMPTY, group->id.name + 2); + ob = BKE_object_add_only_object(mainvar, OB_EMPTY, group->id.name + 2); ob->type = OB_EMPTY; ob->lay = scene->lay; @@ -11060,6 +11179,11 @@ static ID *append_named_part_ex(const bContext *C, Main *mainl, FileData *fd, co } } } + else if (id && (GS(id->name) == ID_GR)) { + /* tag as needing to be instanced */ + if (flag & FILE_GROUP_INSTANCE) + id->flag |= LIB_DOIT; + } return id; } @@ -11105,6 +11229,9 @@ static Main *library_append_begin(Main *mainvar, FileData **fd, const char *file (*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist"); + /* clear for group instancing tag */ + tag_main_lb(&(mainvar->group), 0); + /* make mains */ blo_split_main((*fd)->mainlist, mainvar); @@ -11181,6 +11308,10 @@ static void library_append_end(const bContext *C, Main *mainl, FileData **fd, in printf("library_append_end, scene is NULL (objects wont get bases)\n"); } } + + /* clear group instancing tag */ + tag_main_lb(&(mainvar->group), 0); + /* has been removed... erm, why? s..ton) */ /* 20040907: looks like they are give base already in append_named_part(); -Nathan L */ /* 20041208: put back. It only linked direct, not indirect objects (ton) */ diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c index 2b63d13a9dd..12f4a295a34 100644 --- a/source/blender/blenloader/intern/undofile.c +++ b/source/blender/blenloader/intern/undofile.c @@ -51,9 +51,9 @@ void BLO_free_memfile(MemFile *memfile) { MemFileChunk *chunk; - while ( (chunk = (memfile->chunks.first) ) ) { - if (chunk->ident == 0) MEM_freeN(chunk->buf); - BLI_remlink(&memfile->chunks, chunk); + while ((chunk = BLI_pophead(&memfile->chunks))) { + if (chunk->ident == 0) + MEM_freeN(chunk->buf); MEM_freeN(chunk); } memfile->size = 0; diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c new file mode 100644 index 00000000000..6a0f1747d2f --- /dev/null +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -0,0 +1,57 @@ +/* + * ***** 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. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/blenloader/intern/versioning_defaults.c + * \ingroup blenloader + */ + +#include "BLI_utildefines.h" + +#include "DNA_freestyle_types.h" +#include "DNA_linestyle_types.h" +#include "DNA_scene_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_main.h" + +#include "BLO_readfile.h" + +/* Update defaults in startup.blend, without having to save and embed the file. + * This function can be emptied each time the startup.blend is updated. */ +void BLO_update_defaults_startup_blend(Main *main) +{ + Scene *scene; + SceneRenderLayer *srl; + FreestyleLineStyle *linestyle; + + for (scene = main->scene.first; scene; scene = scene->id.next) { + scene->r.im_format.planes = R_IMF_PLANES_RGBA; + + for (srl = scene->r.layers.first; srl; srl = srl->next) + srl->freestyleConfig.sphere_radius = 0.1f; + } + + for (linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) + linestyle->flag = LS_SAME_OBJECT; +} + diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 82040020ce4..067a8629906 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -518,11 +518,8 @@ static void do_version_free_effects_245(ListBase *lb) { Effect *eff; - eff = lb->first; - while (eff) { - BLI_remlink(lb, eff); + while ((eff = BLI_pophead(lb))) { do_version_free_effect_245(eff); - eff = lb->first; } } @@ -1997,15 +1994,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) while (sce) { if (sce->toolsettings == NULL) { sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct"); - sce->toolsettings->cornertype =0; - sce->toolsettings->degr = 90; - sce->toolsettings->step = 9; - sce->toolsettings->turn = 1; - sce->toolsettings->extr_offs = 1; sce->toolsettings->doublimit = 0.001f; - sce->toolsettings->segments = 32; - sce->toolsettings->rings = 32; - sce->toolsettings->vertices = 32; } sce = sce->id.next; } @@ -2092,7 +2081,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) for (me = main->mesh.first; me; me = me->id.next) { if (!me->medge) { - BKE_mesh_make_edges(me, 1); /* 1 = use mface->edcode */ + BKE_mesh_calc_edges_legacy(me, true); /* true = use mface->edcode */ } else { BKE_mesh_strip_loose_faces(me); @@ -2152,9 +2141,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } for (; sce; sce = sce->id.next) { - /* make 'innervert' the default subdivide type, for backwards compat */ - sce->toolsettings->cornertype = 1; - if (sce->r.scemode & R_PASSEPARTOUT) { set_passepartout = 1; sce->r.scemode &= ~R_PASSEPARTOUT; @@ -2241,11 +2227,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) ntree_version_241(sce->nodetree); /* uv calculation options moved to toolsettings */ - if (sce->toolsettings->uvcalc_radius == 0.0f) { - sce->toolsettings->uvcalc_radius = 1.0f; - sce->toolsettings->uvcalc_cubesize = 1.0f; - sce->toolsettings->uvcalc_mapdir = 1; - sce->toolsettings->uvcalc_mapalign = 1; + if (sce->toolsettings->unwrapper == 0) { sce->toolsettings->uvcalc_flag = UVCALC_FILLHOLES; sce->toolsettings->unwrapper = 1; } @@ -2346,8 +2328,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) for (sce = main->scene.first; sce; sce = sce->id.next) { if (sce->toolsettings->select_thresh == 0.0f) sce->toolsettings->select_thresh = 0.01f; - if (sce->toolsettings->clean_thresh == 0.0f) - sce->toolsettings->clean_thresh = 0.1f; if (sce->r.threads == 0) { if (sce->r.mode & R_THREADS) @@ -2557,14 +2537,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) sce->r.bake_flag = R_BAKE_CLEAR; } } - - if (main->subversionfile < 5) { - for (sce = main->scene.first; sce; sce = sce->id.next) { - /* improved triangle to quad conversion settings */ - if (sce->toolsettings->jointrilimit == 0.0f) - sce->toolsettings->jointrilimit = 0.8f; - } - } } if (main->versionfile <= 243) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 4f0ccd3c626..a2c91969cf8 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1108,9 +1108,6 @@ static void write_sensors(WriteData *wd, ListBase *lb) case SENS_MOUSE: writestruct(wd, DATA, "bMouseSensor", 1, sens->data); break; - case SENS_TOUCH: - writestruct(wd, DATA, "bTouchSensor", 1, sens->data); - break; case SENS_KEYBOARD: writestruct(wd, DATA, "bKeyboardSensor", 1, sens->data); break; @@ -1739,7 +1736,7 @@ static void write_grid_paint_mask(WriteData *wd, int count, GridPaintMask *grid_ for (i = 0; i < count; ++i) { GridPaintMask *gpm = &grid_paint_mask[i]; if (gpm->data) { - const int gridsize = ccg_gridsize(gpm->level); + const int gridsize = BKE_ccg_gridsize(gpm->level); writedata(wd, DATA, sizeof(*gpm->data) * gridsize * gridsize, gpm->data); @@ -1750,16 +1747,26 @@ static void write_grid_paint_mask(WriteData *wd, int count, GridPaintMask *grid_ static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data, int partial_type, int partial_count) { + CustomData data_tmp; int i; + /* This copy will automatically ignore/remove layers set as NO_COPY (and TEMPORARY). */ + CustomData_copy(data, &data_tmp, CD_MASK_EVERYTHING, CD_REFERENCE, count); + /* write external customdata (not for undo) */ - if (data->external && !wd->current) - CustomData_external_write(data, id, CD_MASK_MESH, count, 0); + if (data_tmp.external && !wd->current) + CustomData_external_write(&data_tmp, id, CD_MASK_MESH, count, 0); - writestruct(wd, DATA, "CustomDataLayer", data->maxlayer, data->layers); + for (i = 0; i < data_tmp.totlayer; i++) + data_tmp.layers[i].flag &= ~CD_FLAG_NOFREE; - for (i=0; i<data->totlayer; i++) { - CustomDataLayer *layer= &data->layers[i]; + writestruct_at_address(wd, DATA, "CustomDataLayer", data_tmp.maxlayer, data->layers, data_tmp.layers); + + for (i = 0; i < data_tmp.totlayer; i++) + data_tmp.layers[i].flag |= CD_FLAG_NOFREE; + + for (i = 0; i < data_tmp.totlayer; i++) { + CustomDataLayer *layer= &data_tmp.layers[i]; const char *structname; int structnum, datasize; @@ -1795,11 +1802,13 @@ static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data, } } - if (data->external) - writestruct(wd, DATA, "CustomDataExternal", 1, data->external); + if (data_tmp.external) + writestruct_at_address(wd, DATA, "CustomDataExternal", 1, data->external, data_tmp.external); + + CustomData_free(&data_tmp, count); } -static void write_meshs(WriteData *wd, ListBase *idbase) +static void write_meshes(WriteData *wd, ListBase *idbase) { Mesh *mesh; int save_for_old_blender= 0; @@ -2394,6 +2403,15 @@ static void write_region(WriteData *wd, ARegion *ar, int spacetype) } } +static void write_uilist(WriteData *wd, uiList *ui_list) +{ + writestruct(wd, DATA, "uiList", 1, ui_list); + + if (ui_list->properties) { + IDP_WriteProperty(ui_list->properties, wd); + } +} + static void write_soops(WriteData *wd, SpaceOops *so, LinkNode **tmp_mem_list) { BLI_mempool *ts = so->treestore; @@ -2421,8 +2439,8 @@ static void write_soops(WriteData *wd, SpaceOops *so, LinkNode **tmp_mem_list) * outliners in a screen we might get the same address on the next * malloc, which makes the address no longer unique and so invalid for * lookups on file read, causing crashes or double frees */ - BLI_linklist_append(tmp_mem_list, ts_flat); - BLI_linklist_append(tmp_mem_list, data); + BLI_linklist_prepend(tmp_mem_list, ts_flat); + BLI_linklist_prepend(tmp_mem_list, data); } else { so->treestore = NULL; @@ -2431,7 +2449,8 @@ static void write_soops(WriteData *wd, SpaceOops *so, LinkNode **tmp_mem_list) /* restore old treestore */ so->treestore = ts; - } else { + } + else { writestruct(wd, DATA, "SpaceOops", 1, so); } } @@ -2475,7 +2494,7 @@ static void write_screens(WriteData *wd, ListBase *scrbase) writestruct(wd, DATA, "Panel", 1, pa); for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) - writestruct(wd, DATA, "uiList", 1, ui_list); + write_uilist(wd, ui_list); } sl= sa->spacedata.first; @@ -2920,6 +2939,21 @@ static void write_movieTracks(WriteData *wd, ListBase *tracks) } } +static void write_moviePlaneTracks(WriteData *wd, ListBase *plane_tracks_base) +{ + MovieTrackingPlaneTrack *plane_track; + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + writestruct(wd, DATA, "MovieTrackingPlaneTrack", 1, plane_track); + + writedata(wd, DATA, sizeof(MovieTrackingTrack *) * plane_track->point_tracksnr, plane_track->point_tracks); + writestruct(wd, DATA, "MovieTrackingPlaneMarker", plane_track->markersnr, plane_track->markers); + } +} + static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction *reconstruction) { if (reconstruction->camnr) @@ -2944,6 +2978,7 @@ static void write_movieclips(WriteData *wd, ListBase *idbase) write_animdata(wd, clip->adt); write_movieTracks(wd, &tracking->tracks); + write_moviePlaneTracks(wd, &tracking->plane_tracks); write_movieReconstruction(wd, &tracking->reconstruction); object= tracking->objects.first; @@ -2951,6 +2986,7 @@ static void write_movieclips(WriteData *wd, ListBase *idbase) writestruct(wd, DATA, "MovieTrackingObject", 1, object); write_movieTracks(wd, &object->tracks); + write_moviePlaneTracks(wd, &object->plane_tracks); write_movieReconstruction(wd, &object->reconstruction); object= object->next; @@ -3330,7 +3366,7 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil write_objects (wd, &mainvar->object); write_materials(wd, &mainvar->mat); write_textures (wd, &mainvar->tex); - write_meshs (wd, &mainvar->mesh); + write_meshes (wd, &mainvar->mesh); write_particlesettings(wd, &mainvar->particle); write_nodetrees(wd, &mainvar->nodetree); write_brushes (wd, &mainvar->brush); diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index 228ebcb96c4..67f95cca6aa 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -41,6 +41,7 @@ set(INC_SYS set(SRC operators/bmo_beautify.c operators/bmo_bevel.c + operators/bmo_bisect_plane.c operators/bmo_bridge.c operators/bmo_connect.c operators/bmo_connect_nonplanar.c @@ -50,6 +51,7 @@ set(SRC operators/bmo_dupe.c operators/bmo_edgenet.c operators/bmo_extrude.c + operators/bmo_fill_attribute.c operators/bmo_fill_edgeloop.c operators/bmo_fill_grid.c operators/bmo_fill_holes.c @@ -119,10 +121,14 @@ set(SRC tools/bmesh_bevel.c tools/bmesh_bevel.h + tools/bmesh_bisect_plane.c + tools/bmesh_bisect_plane.h tools/bmesh_decimate_collapse.c tools/bmesh_decimate_dissolve.c tools/bmesh_decimate_unsubdivide.c tools/bmesh_decimate.h + tools/bmesh_edgenet.c + tools/bmesh_edgenet.h tools/bmesh_edgesplit.c tools/bmesh_edgesplit.h tools/bmesh_path.c @@ -130,8 +136,11 @@ set(SRC tools/bmesh_triangulate.c tools/bmesh_triangulate.h - bmesh.h bmesh_class.h + + # public includes + bmesh.h + bmesh_tools.h ) if(MSVC) diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h index d1d93bbfd1d..52aeff77fca 100644 --- a/source/blender/bmesh/bmesh.h +++ b/source/blender/bmesh/bmesh.h @@ -45,9 +45,9 @@ * \subsection bm_header_flags Header Flags * Each element (vertex/edge/face/loop) in a mesh has an associated bit-field called "header flags". * - * BMHeader flags should <b>never</b> be read or written to by bmesh operators (see Operators below). + * BMHeader flags should **never** be read or written to by bmesh operators (see Operators below). * - * Access to header flags is done with BM_elem_flag_*() functions. + * Access to header flags is done with ``BM_elem_flag_*()`` functions. * * * \subsection bm_faces Faces @@ -64,7 +64,8 @@ * Loops store several handy pointers: * * - BMLoop#v - pointer to the vertex associated with this loop. - * - BMLoop#e - pointer to the edge associated with this loop. + * - BMLoop#e - pointer to the edge associated with this loop, + * between verts ``(loop->v, loop->next->v)`` * - BMLoop#f - pointer to the face associated with this loop. * * @@ -124,14 +125,14 @@ * \subsection bm_ops Operators * * Operators are an integral part of BMesh. Unlike regular blender operators, - * BMesh operators <b>bmo's</b> are designed to be nested (e.g. call other operators). + * BMesh operators **bmo's** are designed to be nested (e.g. call other operators). * * Each operator has a number of input/output "slots" which are used to pass settings & data into/out of the operator * (and allows for chaining operators together). * * These slots are identified by name, using strings. * - * Access to slots is done with BMO_slot_*() functions. + * Access to slots is done with ``BMO_slot_***()`` functions. * * * \subsection bm_tool_flags Tool Flags @@ -145,9 +146,9 @@ * These flags should not be confused with header flags, which are used to store persistent flags * (e.g. selection, hide status, etc). * - * Access to tool flags is done with BMO_elem_flag_*() functions. + * Access to tool flags is done with ``BMO_elem_flag_***()`` functions. * - * \warning Operators are never allowed to read or write to header flags. + * \warning Operators are **never** allowed to read or write to header flags. * They act entirely on the data inside their input slots. * For example an operator should not check the selected state of an element, * there are some exceptions to this - some operators check of a face is smooth. @@ -161,8 +162,10 @@ * - boolean - #BMO_OP_SLOT_BOOL * - float - #BMO_OP_SLOT_FLT * - pointer - #BMO_OP_SLOT_PNT - * - element buffer - #BMO_OP_SLOT_ELEMENT_BUF - a list of verts/edges/faces - * - map - BMO_OP_SLOT_MAPPING - simple hash map + * - matrix - #BMO_OP_SLOT_MAT + * - vector - #BMO_OP_SLOT_VEC + * - buffer - #BMO_OP_SLOT_ELEMENT_BUF - a list of verts/edges/faces. + * - map - BMO_OP_SLOT_MAPPING - simple hash map. * * * \subsection bm_slot_iter Slot Iterators @@ -185,33 +188,25 @@ * * These conventions should be used throughout the bmesh module. * - * - BM_xxx() - High level BMesh API function for use anywhere. - * - bmesh_xxx() - Low level API function. - * - bm_xxx() - 'static' functions, not apart of the API at all, but use prefix since they operate on BMesh data. - * - BMO_xxx() - High level operator API function for use anywhere. - * - bmo_xxx() - Low level / internal operator API functions. - * - _bm_xxx() - Functions which are called via macros only. + * - ``BM_***()`` - High level BMesh API function for use anywhere. + * - ``bmesh_***()`` - Low level API function. + * - ``bm_***()`` - 'static' functions, not apart of the API at all, but use prefix since they operate on BMesh data. + * - ``BMO_***()`` - High level operator API function for use anywhere. + * - ``bmo_***()`` - Low level / internal operator API functions. + * - ``_bm_***()`` - Functions which are called via macros only. * * \section bm_todo BMesh TODO's * * There may be a better place for this section, but adding here for now. * - * \subsection bm_todo_api API - * - * - make crease and bevel weight optional, they come for free in meshes but are allocated layers - * in the bmesh data structure. - * - * * \subsection bm_todo_tools Tools * * Probably most of these will be bmesh operators. * * - make ngons flat. - * - make ngons into tris/quads (ngon poke?), many methods could be used here (triangulate/fan/quad-fan). * - solidify (precise mode), keeps even wall thickness, re-creates outlines of offset faces with plane-plane * intersections. - * - split vert (we already have in our API, just no tool) - * - bridge (add option to bridge between different edge loop counts, option to remove selected face regions) + * - split vert (we already have in our API, just no tool). * - flip selected region (invert all faces about the plane defined by the selected region outline) * - interactive dissolve (like the knife tool but draw over edges to dissolve) * @@ -222,16 +217,12 @@ * - skip BMO flag allocation, its not needed in many cases, this is fairly redundant to calc by default. * - ability to call BMO's with option not to create return data (will save some time) * - binary diff UNDO, currently this uses huge amount of ram when all shapes are stored for each undo step for eg. - * - use two differnt iterator types for BMO map/buffer types. - * - avoid string lookups for BMO slot lookups _especially_ when used in loops, this is very crappy. + * - use two different iterator types for BMO map/buffer types. * * * \subsection bm_todo_tools_enhance Tool Enhancements * - * - face inset interpolate loop data from face (currently copies - but this stretches UV's in an ugly way) * - vert slide UV correction (like we have for edge slide) - * - fill-face edge net - produce consistent normals, currently it won't, fix should be to fill in edge-net node - * connected with previous one - since they already check for normals of adjacent edge-faces before creating. */ #ifdef __cplusplus @@ -251,8 +242,8 @@ extern "C" { #include "intern/bmesh_operator_api.h" #include "intern/bmesh_error.h" -#include "intern/bmesh_construct.h" #include "intern/bmesh_core.h" +#include "intern/bmesh_construct.h" #include "intern/bmesh_edgeloop.h" #include "intern/bmesh_interp.h" #include "intern/bmesh_iterators.h" @@ -269,12 +260,6 @@ extern "C" { #include "intern/bmesh_inline.h" -#include "tools/bmesh_bevel.h" -#include "tools/bmesh_decimate.h" -#include "tools/bmesh_edgesplit.h" -#include "tools/bmesh_path.h" -#include "tools/bmesh_triangulate.h" - #ifdef __cplusplus } #endif diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index 0e4c014a06a..90105b0dd81 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -65,7 +65,7 @@ typedef struct BMHeader { void *data; /* customdata layers */ int index; /* notes: * - Use BM_elem_index_get/set macros for index - * - Unitialized to -1 so we can easily tell its not set. + * - Uninitialized to -1 so we can easily tell its not set. * - Used for edge/vert/face, check BMesh.elem_index_dirty for valid index values, * this is abused by various tools which set it dirty. * - For loops this is used for sorting during tessellation. */ @@ -254,6 +254,8 @@ enum { struct BPy_BMGeneric; extern void bpy_bm_generic_invalidate(struct BPy_BMGeneric *self); +typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data); + /* defines */ #define BM_ELEM_CD_GET_VOID_P(ele, offset) \ (assert(offset != -1), (void *)((char *)(ele)->head.data + (offset))) @@ -290,6 +292,12 @@ extern void bpy_bm_generic_invalidate(struct BPy_BMGeneric *self); * but should not error on valid cases */ #define BM_LOOP_RADIAL_MAX 10000 #define BM_NGON_MAX 100000 -#define BM_OMP_LIMIT 10000 /* 10000 */ /* setting zero so we can catch bugs in OpenMP/BMesh */ + +/* setting zero so we can catch bugs in OpenMP/BMesh */ +#ifdef DEBUG +# define BM_OMP_LIMIT 0 +#else +# define BM_OMP_LIMIT 10000 +#endif #endif /* __BMESH_CLASS_H__ */ diff --git a/source/blender/compositor/operations/COM_MixBurnOperation.h b/source/blender/bmesh/bmesh_tools.h index 131ccfa2130..b2dac810bce 100644 --- a/source/blender/compositor/operations/COM_MixBurnOperation.h +++ b/source/blender/bmesh/bmesh_tools.h @@ -1,5 +1,5 @@ /* - * Copyright 2011, Blender Foundation. + * ***** 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 @@ -15,31 +15,35 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** */ -#ifndef _COM_MixBurnOperation_h -#define _COM_MixBurnOperation_h -#include "COM_MixBaseOperation.h" - +#ifndef __BMESH_TOOLS_H__ +#define __BMESH_TOOLS_H__ -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. +/** \file blender/bmesh/bmesh_tools.h + * \ingroup bmesh + * + * Utility functions that operate directly on the BMesh, + * These can be used by both Modifiers and BMesh-Operators. */ -class MixBurnOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixBurnOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); -}; +#ifdef __cplusplus +extern "C" { #endif + +#include "tools/bmesh_bevel.h" +#include "tools/bmesh_bisect_plane.h" +#include "tools/bmesh_decimate.h" +#include "tools/bmesh_edgenet.h" +#include "tools/bmesh_edgesplit.h" +#include "tools/bmesh_path.h" +#include "tools/bmesh_triangulate.h" + +#ifdef __cplusplus +} +#endif + +#endif /* __BMESH_TOOLS_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index f5856ee94b3..1a7464ce340 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -35,6 +35,7 @@ #include "BLI_alloca.h" #include "BLI_math.h" +#include "BLI_sort_utils.h" #include "BKE_customdata.h" @@ -65,95 +66,69 @@ static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh, BMFace *BM_face_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, - const BMFace *example, const bool no_double) + const BMFace *f_example, const eBMCreateFlag create_flag) { BMVert *vtar[4] = {v1, v2, v3, v4}; - return BM_face_create_quad_tri_v(bm, vtar, v4 ? 4 : 3, example, no_double); -} - -BMFace *BM_face_create_quad_tri_v(BMesh *bm, BMVert **verts, int len, const BMFace *example, const bool no_double) -{ - BMFace *f = NULL; - bool is_overlap = false; - - /* sanity check - debug mode only */ - if (len == 3) { - BLI_assert(verts[0] != verts[1]); - BLI_assert(verts[0] != verts[2]); - BLI_assert(verts[1] != verts[2]); - } - else if (len == 4) { - BLI_assert(verts[0] != verts[1]); - BLI_assert(verts[0] != verts[2]); - BLI_assert(verts[0] != verts[3]); - - BLI_assert(verts[1] != verts[2]); - BLI_assert(verts[1] != verts[3]); - - BLI_assert(verts[2] != verts[3]); - } - else { - BLI_assert(0); - } - - - if (no_double) { - /* check if face exists or overlaps */ - is_overlap = BM_face_exists(verts, len, &f); - } - - /* make new face */ - if ((f == NULL) && (!is_overlap)) { - BMEdge *edar[4] = {NULL}; - edar[0] = BM_edge_create(bm, verts[0], verts[1], NULL, BM_CREATE_NO_DOUBLE); - edar[1] = BM_edge_create(bm, verts[1], verts[2], NULL, BM_CREATE_NO_DOUBLE); - if (len == 4) { - edar[2] = BM_edge_create(bm, verts[2], verts[3], NULL, BM_CREATE_NO_DOUBLE); - edar[3] = BM_edge_create(bm, verts[3], verts[0], NULL, BM_CREATE_NO_DOUBLE); - } - else { - edar[2] = BM_edge_create(bm, verts[2], verts[0], NULL, BM_CREATE_NO_DOUBLE); - } - - f = BM_face_create(bm, verts, edar, len, 0); - - if (example && f) { - BM_elem_attrs_copy(bm, bm, example, f); - } - } - - return f; + return BM_face_create_verts(bm, vtar, v4 ? 4 : 3, f_example, create_flag, true); } /** * \brief copies face loop data from shared adjacent faces. + * + * \param filter_fn A function that filters the source loops before copying (don't always want to copy all) + * * \note when a matching edge is found, both loops of that edge are copied * this is done since the face may not be completely surrounded by faces, - * this way: a quad with 2 connected quads on either side will still get all 4 loops updated */ -void BM_face_copy_shared(BMesh *bm, BMFace *f) + * this way: a quad with 2 connected quads on either side will still get all 4 loops updated + */ +void BM_face_copy_shared(BMesh *bm, BMFace *f, + BMElemFilterFunc filter_fn, void *user_data) { BMLoop *l_first; BMLoop *l_iter; +#ifdef DEBUG + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BLI_assert(BM_ELEM_API_FLAG_TEST(l_iter, _FLAG_OVERLAP) == 0); + } while ((l_iter = l_iter->next) != l_first); +#endif + l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { BMLoop *l_other = l_iter->radial_next; if (l_other && l_other != l_iter) { + BMLoop *l_src[2]; + BMLoop *l_dst[2] = {l_iter, l_iter->next}; + unsigned int j; + if (l_other->v == l_iter->v) { - bm_loop_attrs_copy(bm, bm, l_other, l_iter); - bm_loop_attrs_copy(bm, bm, l_other->next, l_iter->next); + l_src[0] = l_other; + l_src[1] = l_other->next; } else { - bm_loop_attrs_copy(bm, bm, l_other->next, l_iter); - bm_loop_attrs_copy(bm, bm, l_other, l_iter->next); + l_src[0] = l_other->next; + l_src[1] = l_other; } - /* since we copy both loops of the shared edge, step over the next loop here */ - if ((l_iter = l_iter->next) == l_first) { - break; + + for (j = 0; j < 2; j++) { + BLI_assert(l_dst[j]->v == l_src[j]->v); + if (BM_ELEM_API_FLAG_TEST(l_dst[j], _FLAG_OVERLAP) == 0) { + if ((filter_fn == NULL) || filter_fn((BMElem *)l_src[j], user_data)) { + bm_loop_attrs_copy(bm, bm, l_src[j], l_dst[j]); + BM_ELEM_API_FLAG_ENABLE(l_dst[j], _FLAG_OVERLAP); + } + } } } } while ((l_iter = l_iter->next) != l_first); + + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BM_ELEM_API_FLAG_DISABLE(l_iter, _FLAG_OVERLAP); + } while ((l_iter = l_iter->next) != l_first); } /** @@ -171,7 +146,8 @@ void BM_face_copy_shared(BMesh *bm, BMFace *f) * #BM_face_create should be considered over this function as it * avoids some unnecessary work. */ -BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len, const int create_flag) +BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len, + const BMFace *f_example, const eBMCreateFlag create_flag) { BMEdge **edges_sort = BLI_array_alloca(edges_sort, len); BMVert **verts_sort = BLI_array_alloca(verts_sort, len + 1); @@ -290,7 +266,7 @@ BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, c BM_ELEM_API_FLAG_DISABLE(verts_sort[i], _FLAG_MV); } - f = BM_face_create(bm, verts_sort, edges_sort, len, create_flag); + f = BM_face_create(bm, verts_sort, edges_sort, len, f_example, create_flag); /* clean up flags */ for (i = 0; i < len; i++) { @@ -318,7 +294,8 @@ err: * - Optionally create edges between vertices. * - Uses verts so no need to find edges (handy when you only have verts) */ -BMFace *BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len, const int create_flag, +BMFace *BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len, + const BMFace *f_example, const eBMCreateFlag create_flag, const bool calc_winding, const bool create_edges) { BMEdge **edge_arr = BLI_array_alloca(edge_arr, len); @@ -378,21 +355,8 @@ BMFace *BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len, c bm, v_winding[winding[0]], v_winding[winding[1]], - edge_arr, len, create_flag); -} - - -typedef struct AngleIndexPair { - float angle; - int index; -} AngleIndexPair; - -static int angle_index_pair_cmp(const void *e1, const void *e2) -{ - const AngleIndexPair *p1 = e1, *p2 = e2; - if (p1->angle > p2->angle) return 1; - else if (p1->angle < p2->angle) return -1; - else return 0; + edge_arr, len, + f_example, create_flag); } /** @@ -411,8 +375,12 @@ static int angle_index_pair_cmp(const void *e1, const void *e2) * * \note Since this is a vcloud there is no direction. */ -BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len, const int create_flag) +BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len, + const BMFace *f_example, const eBMCreateFlag create_flag) { + struct SortIntByFloat *vang = BLI_array_alloca(vang, len); + BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len); + BMFace *f; float totv_inv = 1.0f / (float)len; @@ -429,10 +397,6 @@ BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len, const float far_dist, far_best; float far_cross_dist, far_cross_best = 0.0f; - AngleIndexPair *vang; - - BMVert **vert_arr_map; - /* get the center point and collect vector array since we loop over these a lot */ zero_v3(cent); for (i = 0; i < len; i++) { @@ -492,8 +456,6 @@ BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len, const /* --- */ /* now calculate every points angle around the normal (signed) */ - vang = MEM_mallocN(sizeof(AngleIndexPair) * len, __func__); - for (i = 0; i < len; i++) { float co[3]; float proj_vec[3]; @@ -513,26 +475,21 @@ BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len, const angle = -angle; } - vang[i].angle = angle; - vang[i].index = i; + vang[i].sort_value = angle; + vang[i].data = i; } /* sort by angle and magic! - we have our ngon */ - qsort(vang, len, sizeof(AngleIndexPair), angle_index_pair_cmp); + qsort(vang, len, sizeof(*vang), BLI_sortutil_cmp_float); /* --- */ /* create edges and find the winding (if faces are attached to any existing edges) */ - vert_arr_map = MEM_mallocN(sizeof(BMVert *) * len, __func__); - for (i = 0; i < len; i++) { - vert_arr_map[i] = vert_arr[vang[i].index]; + vert_arr_map[i] = vert_arr[vang[i].data]; } - MEM_freeN(vang); - - f = BM_face_create_ngon_verts(bm, vert_arr_map, len, create_flag, true, true); - MEM_freeN(vert_arr_map); + f = BM_face_create_ngon_verts(bm, vert_arr_map, len, f_example, create_flag, true, true); return f; } @@ -543,10 +500,10 @@ BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len, const */ void BMO_remove_tagged_faces(BMesh *bm, const short oflag) { - BMFace *f; + BMFace *f, *f_next; BMIter iter; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + BM_ITER_MESH_MUTABLE (f, f_next, &iter, bm, BM_FACES_OF_MESH) { if (BMO_elem_flag_test(bm, f, oflag)) { BM_face_kill(bm, f); } @@ -555,10 +512,10 @@ void BMO_remove_tagged_faces(BMesh *bm, const short oflag) void BMO_remove_tagged_edges(BMesh *bm, const short oflag) { - BMEdge *e; + BMEdge *e, *e_next; BMIter iter; - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { if (BMO_elem_flag_test(bm, e, oflag)) { BM_edge_kill(bm, e); } @@ -567,10 +524,10 @@ void BMO_remove_tagged_edges(BMesh *bm, const short oflag) void BMO_remove_tagged_verts(BMesh *bm, const short oflag) { - BMVert *v; + BMVert *v, *v_next; BMIter iter; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { if (BMO_elem_flag_test(bm, v, oflag)) { BM_vert_kill(bm, v); } @@ -824,6 +781,7 @@ void BM_elem_attrs_copy_ex(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, BMHeader *ele_dst = ele_dst_v; BLI_assert(ele_src->htype == ele_dst->htype); + BLI_assert(ele_src != ele_dst); if ((hflag_mask & BM_ELEM_SELECT) == 0) { /* First we copy select */ @@ -903,7 +861,7 @@ static BMFace *bm_mesh_copy_new_face(BMesh *bm_new, BMesh *bm_old, j++; } while ((l_iter = l_iter->next) != l_first); - f_new = BM_face_create(bm_new, verts, edges, f->len, BM_CREATE_SKIP_CD); + f_new = BM_face_create(bm_new, verts, edges, f->len, NULL, BM_CREATE_SKIP_CD); if (UNLIKELY(f_new == NULL)) { return NULL; @@ -953,10 +911,7 @@ BMesh *BM_mesh_copy(BMesh *bm_old) BMEditSelection *ese; BMIter iter; int i; - const BMAllocTemplate allocsize = {bm_old->totvert, - bm_old->totedge, - bm_old->totloop, - bm_old->totface}; + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_BM(bm_old); /* allocate a bmesh */ bm_new = BM_mesh_create(&allocsize); diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h index f0bd7b316e9..e85c97dffd9 100644 --- a/source/blender/bmesh/intern/bmesh_construct.h +++ b/source/blender/bmesh/intern/bmesh_construct.h @@ -29,20 +29,20 @@ struct BMAllocTemplate; -BMFace *BM_face_create_quad_tri_v(BMesh *bm, - BMVert **verts, int len, - const BMFace *example, const bool no_double); - BMFace *BM_face_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, - const BMFace *example, const bool no_double); + const BMFace *f_example, const eBMCreateFlag create_flag); -void BM_face_copy_shared(BMesh *bm, BMFace *f); +void BM_face_copy_shared(BMesh *bm, BMFace *f, + BMElemFilterFunc filter_fn, void *user_data); -BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len, const int create_flag); -BMFace *BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len, const int create_flag, +BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len, + const BMFace *f_example, const eBMCreateFlag create_flag); +BMFace *BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len, + const BMFace *f_example, const eBMCreateFlag create_flag, const bool calc_winding, const bool create_edges); -BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len, const int create_flag); +BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int len, + const BMFace *f_example, const eBMCreateFlag create_flag); void BMO_remove_tagged_faces(BMesh *bm, const short oflag); void BMO_remove_tagged_edges(BMesh *bm, const short oflag); diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index b296c367575..164a92125cd 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -56,7 +56,8 @@ /** * \brief Main function for creating a new vertex. */ -BMVert *BM_vert_create(BMesh *bm, const float co[3], const BMVert *example, const eBMCreateFlag create_flag) +BMVert *BM_vert_create(BMesh *bm, const float co[3], + const BMVert *v_example, const eBMCreateFlag create_flag) { BMVert *v = BLI_mempool_calloc(bm->vpool); @@ -86,10 +87,10 @@ BMVert *BM_vert_create(BMesh *bm, const float co[3], const BMVert *example, cons } if (!(create_flag & BM_CREATE_SKIP_CD)) { - if (example) { + if (v_example) { int *keyi; - BM_elem_attrs_copy(bm, bm, example, v); + BM_elem_attrs_copy(bm, bm, v_example, v); /* exception: don't copy the original shapekey index */ keyi = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_SHAPE_KEYINDEX); @@ -113,7 +114,8 @@ BMVert *BM_vert_create(BMesh *bm, const float co[3], const BMVert *example, cons * \note Duplicate edges are supported by the API however users should _never_ see them. * so unless you need a unique edge or know the edge won't exist, you should call with \a no_double = true */ -BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *example, const eBMCreateFlag create_flag) +BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, + const BMEdge *e_example, const eBMCreateFlag create_flag) { BMEdge *e; @@ -148,8 +150,8 @@ BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *example, bmesh_disk_edge_append(e, e->v2); if (!(create_flag & BM_CREATE_SKIP_CD)) { - if (example) { - BM_elem_attrs_copy(bm, bm, example, e); + if (e_example) { + BM_elem_attrs_copy(bm, bm, e_example, e); } else { CustomData_bmesh_set_default(&bm->edata, &e->head.data); @@ -190,7 +192,8 @@ static BMLoop *bm_loop_create(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f, return l; } -static BMLoop *bm_face_boundary_add(BMesh *bm, BMFace *f, BMVert *startv, BMEdge *starte, const int create_flag) +static BMLoop *bm_face_boundary_add(BMesh *bm, BMFace *f, BMVert *startv, BMEdge *starte, + const eBMCreateFlag create_flag) { #ifdef USE_BMESH_HOLES BMLoopList *lst = BLI_mempool_calloc(bm->looplistpool); @@ -228,7 +231,7 @@ BMFace *BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f, i = 0; do { if (copy_verts) { - verts[i] = BM_vert_create(bm_dst, l_iter->v->co, l_iter->v, 0); + verts[i] = BM_vert_create(bm_dst, l_iter->v->co, l_iter->v, BM_CREATE_NOP); } else { verts[i] = l_iter->v; @@ -251,7 +254,7 @@ BMFace *BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f, v1 = verts[(i + 1) % f->len]; } - edges[i] = BM_edge_create(bm_dst, v1, v2, l_iter->e, 0); + edges[i] = BM_edge_create(bm_dst, v1, v2, l_iter->e, BM_CREATE_NOP); } else { edges[i] = l_iter->e; @@ -259,7 +262,7 @@ BMFace *BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f, i++; } while ((l_iter = l_iter->next) != l_first); - f_copy = BM_face_create(bm_dst, verts, edges, f->len, BM_CREATE_SKIP_CD); + f_copy = BM_face_create(bm_dst, verts, edges, f->len, NULL, BM_CREATE_SKIP_CD); BM_elem_attrs_copy(bm_src, bm_dst, f, f_copy); @@ -320,11 +323,12 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm, const eBMCreateFlag creat * \param len Length of the face * \param create_flag Options for creating the face */ -BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len, const eBMCreateFlag create_flag) +BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len, + const BMFace *f_example, const eBMCreateFlag create_flag) { BMFace *f = NULL; BMLoop *l, *startl, *lastl; - int i, overlap; + int i; if (len == 0) { /* just return NULL for now */ @@ -333,8 +337,8 @@ BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len, if (create_flag & BM_CREATE_NO_DOUBLE) { /* Check if face already exists */ - overlap = BM_face_exists(verts, len, &f); - if (overlap) { + const bool is_overlap = BM_face_exists(verts, len, &f); + if (is_overlap) { return f; } else { @@ -364,11 +368,48 @@ BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len, f->len = len; + if (!(create_flag & BM_CREATE_SKIP_CD)) { + if (f_example) { + BM_elem_attrs_copy(bm, bm, f_example, f); + } + else { + CustomData_bmesh_set_default(&bm->pdata, &f->head.data); + } + } + BM_CHECK_ELEMENT(f); return f; } +/** + * Wrapper for #BM_face_create when you don't have an edge array + */ +BMFace *BM_face_create_verts(BMesh *bm, BMVert **vert_arr, const int len, + const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges) +{ + BMEdge **edge_arr = BLI_array_alloca(edge_arr, len); + int i, i_prev = len - 1; + + if (create_edges) { + for (i = 0; i < len; i++) { + edge_arr[i_prev] = BM_edge_create(bm, vert_arr[i_prev], vert_arr[i], NULL, BM_CREATE_NO_DOUBLE); + i_prev = i; + } + } + else { + for (i = 0; i < len; i++) { + edge_arr[i_prev] = BM_edge_exists(vert_arr[i_prev], vert_arr[i]); + if (edge_arr[i_prev] == NULL) { + return NULL; + } + i_prev = i; + } + } + + return BM_face_create(bm, vert_arr, edge_arr, len, f_example, create_flag); +} + #ifndef NDEBUG /** @@ -1053,7 +1094,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) } /* create region face */ - f_new = tote ? BM_face_create_ngon(bm, v1, v2, edges, tote, 0) : NULL; + f_new = tote ? BM_face_create_ngon(bm, v1, v2, edges, tote, faces[0], BM_CREATE_NOP) : NULL; if (UNLIKELY(!f_new || BMO_error_occurred(bm))) { if (!BMO_error_occurred(bm)) err = N_("Invalid boundary region to join faces"); @@ -1080,8 +1121,6 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) BM_elem_attrs_copy(bm, bm, l2, l_iter); } } while ((l_iter = l_iter->next) != l_first); - - BM_elem_attrs_copy(bm, bm, faces[0], f_new); #ifdef USE_BMESH_HOLES /* add holes */ @@ -1239,11 +1278,12 @@ BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, } if (!l_v1 || !l_v2) { + BLI_assert(0); return NULL; } /* allocate new edge between v1 and v2 */ - e = BM_edge_create(bm, v1, v2, example, no_double ? BM_CREATE_NO_DOUBLE : 0); + e = BM_edge_create(bm, v1, v2, example, no_double ? BM_CREATE_NO_DOUBLE : BM_CREATE_NOP); f2 = bm_face_create__sfme(bm, f); l_f1 = bm_loop_create(bm, v2, e, f, l_v2, 0); @@ -1384,8 +1424,8 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) valence2 = bmesh_disk_count(tv); #endif - v_new = BM_vert_create(bm, tv->co, tv, 0); - e_new = BM_edge_create(bm, v_new, tv, e, 0); + v_new = BM_vert_create(bm, tv->co, tv, BM_CREATE_NOP); + e_new = BM_edge_create(bm, v_new, tv, e, BM_CREATE_NOP); bmesh_disk_edge_remove(e_new, tv); bmesh_disk_edge_remove(e_new, v_new); @@ -1970,7 +2010,7 @@ void bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len verts[0] = v; for (i = 1; i < maxindex; i++) { - verts[i] = BM_vert_create(bm, v->co, v, 0); + verts[i] = BM_vert_create(bm, v->co, v, BM_CREATE_NOP); if (copy_select) { BM_elem_select_copy(bm, bm, verts[i], v); } @@ -2136,7 +2176,7 @@ void bmesh_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, e->l = l_sep->radial_next; } - e_new = BM_edge_create(bm, e->v1, e->v2, e, 0); + e_new = BM_edge_create(bm, e->v1, e->v2, e, BM_CREATE_NOP); bmesh_radial_loop_remove(l_sep, e); bmesh_radial_append(e_new, l_sep); l_sep->e = e_new; diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h index c9e806335dd..a18c2ebd32c 100644 --- a/source/blender/bmesh/intern/bmesh_core.h +++ b/source/blender/bmesh/intern/bmesh_core.h @@ -31,6 +31,7 @@ BMFace *BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f, const bool copy_verts, const bool copy_edges); typedef enum eBMCreateFlag { + BM_CREATE_NOP = 0, /* faces and edges only */ BM_CREATE_NO_DOUBLE = (1 << 1), /* Skip CustomData - for all element types data, @@ -39,9 +40,15 @@ typedef enum eBMCreateFlag { BM_CREATE_SKIP_CD = (1 << 2), } eBMCreateFlag; -BMVert *BM_vert_create(BMesh *bm, const float co[3], const BMVert *example, const eBMCreateFlag create_flag); -BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *example, const eBMCreateFlag create_flag); -BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len, const eBMCreateFlag create_flag); +BMVert *BM_vert_create(BMesh *bm, const float co[3], + const BMVert *v_example, const eBMCreateFlag create_flag); +BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, + const BMEdge *e_example, const eBMCreateFlag create_flag); +BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len, + const BMFace *f_example, const eBMCreateFlag create_flag); +BMFace *BM_face_create_verts(BMesh *bm, BMVert **verts, const int len, + const BMFace *f_example, const eBMCreateFlag create_flag, + const bool create_edges); void BM_face_edges_kill(BMesh *bm, BMFace *f); void BM_face_verts_kill(BMesh *bm, BMFace *f); diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c index 1f052bd206a..fe3f6551b70 100644 --- a/source/blender/bmesh/intern/bmesh_edgeloop.c +++ b/source/blender/bmesh/intern/bmesh_edgeloop.c @@ -230,7 +230,7 @@ static bool bm_loop_path_build_step(BLI_mempool *vs_pool, ListBase *lb, const in /* on the same side - do nothing */ } else { - /* we have met out match! (vertices from differnt sides meet) */ + /* we have met out match! (vertices from different sides meet) */ if (dir == 1) { v_match[0] = vs->v; v_match[1] = v_next; @@ -361,8 +361,7 @@ bool BM_mesh_edgeloops_find_path(BMesh *bm, ListBase *r_eloops, void BM_mesh_edgeloops_free(ListBase *eloops) { BMEdgeLoopStore *el_store; - while ((el_store = eloops->first)) { - BLI_remlink(eloops, el_store); + while ((el_store = BLI_pophead(eloops))) { BM_edgeloop_free(el_store); } } diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.h b/source/blender/bmesh/intern/bmesh_edgeloop.h index b46509d4030..527dba120e1 100644 --- a/source/blender/bmesh/intern/bmesh_edgeloop.h +++ b/source/blender/bmesh/intern/bmesh_edgeloop.h @@ -70,7 +70,7 @@ bool BM_edgeloop_overlap_check(struct BMEdgeLoopStore *el_store_a (elink)->next ? elink->next : (BM_edgeloop_is_closed(el_store) ? BM_edgeloop_verts_get(el_store)->first : NULL) #define BM_EDGELOOP_NEXT(el_store) \ - (CHECK_TYPE_INLINE(el_store, struct BMEdgeLoopStore), \ + (CHECK_TYPE_INLINE(el_store, struct BMEdgeLoopStore *), \ (struct BMEdgeLoopStore *)((LinkData *)el_store)->next) #endif /* __BMESH_EDGELOOP_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_inline.h b/source/blender/bmesh/intern/bmesh_inline.h index 102e9d47ffd..5ac6d7da61b 100644 --- a/source/blender/bmesh/intern/bmesh_inline.h +++ b/source/blender/bmesh/intern/bmesh_inline.h @@ -56,7 +56,7 @@ BLI_INLINE void _bm_elem_flag_enable(BMHeader *head, const char hflag) BLI_INLINE void _bm_elem_flag_disable(BMHeader *head, const char hflag) { - head->hflag &= ~hflag; + head->hflag &= (char)~hflag; } BLI_INLINE void _bm_elem_flag_set(BMHeader *head, const char hflag, const int val) diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c index 4555de7b13d..91b9774634d 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.c +++ b/source/blender/bmesh/intern/bmesh_iterators.c @@ -54,6 +54,32 @@ const char bm_iter_itype_htype_map[BM_ITYPE_MAX] = { }; /** + * Utility function. + */ +int BM_iter_mesh_count(BMesh *bm, const char itype) +{ + int count; + + switch (itype) { + case BM_VERTS_OF_MESH: + count = bm->totvert; + break; + case BM_EDGES_OF_MESH: + count = bm->totedge; + break; + case BM_FACES_OF_MESH: + count = bm->totface; + break; + default: + count = 0; + BLI_assert(0); + break; + } + + return count; +} + +/** * \note Use #BM_vert_at_index / #BM_edge_at_index / #BM_face_at_index for mesh arrays. */ void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index) @@ -304,36 +330,66 @@ int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const * VERT OF MESH CALLBACKS */ +/* see bug [#36923] for why we need this, + * allow adding but not removing, this isnt _totally_ safe since + * you could add/remove within the same loop, but catches common cases + */ +#ifdef DEBUG +# define USE_IMMUTABLE_ASSERT +#endif + void bmiter__vert_of_mesh_begin(struct BMIter__vert_of_mesh *iter) { +#ifdef USE_IMMUTABLE_ASSERT + ((BMIter *)iter)->count = iter->bm->totvert; +#endif BLI_mempool_iternew(iter->bm->vpool, &iter->pooliter); } void *bmiter__vert_of_mesh_step(struct BMIter__vert_of_mesh *iter) { +#ifdef USE_IMMUTABLE_ASSERT + BLI_assert(((BMIter *)iter)->count <= iter->bm->totvert); +#endif return BLI_mempool_iterstep(&iter->pooliter); } void bmiter__edge_of_mesh_begin(struct BMIter__edge_of_mesh *iter) { +#ifdef USE_IMMUTABLE_ASSERT + ((BMIter *)iter)->count = iter->bm->totedge; +#endif BLI_mempool_iternew(iter->bm->epool, &iter->pooliter); } void *bmiter__edge_of_mesh_step(struct BMIter__edge_of_mesh *iter) { +#ifdef USE_IMMUTABLE_ASSERT + BLI_assert(((BMIter *)iter)->count <= iter->bm->totedge); +#endif return BLI_mempool_iterstep(&iter->pooliter); } void bmiter__face_of_mesh_begin(struct BMIter__face_of_mesh *iter) { +#ifdef USE_IMMUTABLE_ASSERT + ((BMIter *)iter)->count = iter->bm->totface; +#endif BLI_mempool_iternew(iter->bm->fpool, &iter->pooliter); } void *bmiter__face_of_mesh_step(struct BMIter__face_of_mesh *iter) { +#ifdef USE_IMMUTABLE_ASSERT + BLI_assert(((BMIter *)iter)->count <= iter->bm->totface); +#endif return BLI_mempool_iterstep(&iter->pooliter); } +#ifdef USE_IMMUTABLE_ASSERT +# undef USE_IMMUTABLE_ASSERT +#endif + /* * EDGE OF VERT CALLBACKS */ diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h index b5535b59321..fdf0f27f05f 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.h +++ b/source/blender/bmesh/intern/bmesh_iterators.h @@ -39,6 +39,7 @@ * */ +#include "BLI_compiler_attrs.h" #include "BLI_mempool.h" /* Defines for passing to BM_iter_new. @@ -88,6 +89,20 @@ extern const char bm_iter_itype_htype_map[BM_ITYPE_MAX]; #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)++) +/* 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(bm, itype)), \ + (void)(ele_next = BM_iter_step(iter)), 1) : 0; \ + 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) +#endif + + #define BM_ITER_ELEM(ele, iter, data, itype) \ for (ele = BM_iter_new(iter, NULL, itype, data); ele; ele = BM_iter_step(iter)) @@ -181,18 +196,11 @@ typedef struct BMIter { char itype; } BMIter; -void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -#endif -; +int BM_iter_mesh_count(BMesh *bm, const char itype); +void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index) ATTR_WARN_UNUSED_RESULT; int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len); void *BM_iter_as_arrayN(BMesh *bm, const char itype, void *data, int *r_len, - void **stack_array, int stack_array_size) -#ifdef __GNUC__ -__attribute__((warn_unused_result)) -#endif -; + void **stack_array, int stack_array_size) ATTR_WARN_UNUSED_RESULT; int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask, void **array, const int len); void *BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask, diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c index c7be4424a21..b302ca7b8b2 100644 --- a/source/blender/bmesh/intern/bmesh_log.c +++ b/source/blender/bmesh/intern/bmesh_log.c @@ -18,6 +18,21 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/bmesh/intern/bmesh_log.c + * \ingroup bmesh + * + * The BMLog is an interface for storing undo/redo steps as a BMesh is + * modified. It only stores changes to the BMesh, not full copies. + * + * Currently it supports the following types of changes: + * + * - Adding and removing vertices + * - Adding and removing faces + * - Moving vertices + * - Setting vertex paint-mask values + * - Setting vertex hflags + */ + #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -95,6 +110,7 @@ struct BMLog { typedef struct { float co[3]; + short no[3]; float mask; char hflag; } BMLogVert; @@ -117,10 +133,8 @@ static void bm_log_vert_id_set(BMLog *log, BMVert *v, unsigned int id) { void *vid = SET_INT_IN_POINTER(id); - BLI_ghash_remove(log->id_to_elem, vid, NULL, NULL); - BLI_ghash_insert(log->id_to_elem, vid, v); - BLI_ghash_remove(log->elem_to_id, v, NULL, NULL); - BLI_ghash_insert(log->elem_to_id, v, vid); + BLI_ghash_reinsert(log->id_to_elem, vid, v, NULL, NULL); + BLI_ghash_reinsert(log->elem_to_id, v, vid, NULL, NULL); } /* Get a vertex from its unique ID */ @@ -142,11 +156,9 @@ static unsigned int bm_log_face_id_get(BMLog *log, BMFace *f) static void bm_log_face_id_set(BMLog *log, BMFace *f, unsigned int id) { void *fid = SET_INT_IN_POINTER(id); - - BLI_ghash_remove(log->id_to_elem, fid, NULL, NULL); - BLI_ghash_insert(log->id_to_elem, fid, f); - BLI_ghash_remove(log->elem_to_id, f, NULL, NULL); - BLI_ghash_insert(log->elem_to_id, f, fid); + + BLI_ghash_reinsert(log->id_to_elem, fid, f, NULL, NULL); + BLI_ghash_reinsert(log->elem_to_id, f, fid, NULL, NULL); } /* Get a face from its unique ID */ @@ -191,6 +203,7 @@ static void vert_mask_set(BMesh *bm, BMVert *v, float new_mask) static void bm_log_vert_bmvert_copy(BMesh *bm, BMLogVert *lv, BMVert *v) { copy_v3_v3(lv->co, v->co); + normal_float_to_short_v3(lv->no, v->no); lv->mask = vert_mask_get(bm, v); lv->hflag = v->head.hflag; } @@ -277,9 +290,10 @@ static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts) GHASH_ITER (gh_iter, verts) { void *key = BLI_ghashIterator_getKey(&gh_iter); BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter); - BMVert *v = BM_vert_create(bm, lv->co, NULL, 0); + BMVert *v = BM_vert_create(bm, lv->co, NULL, BM_CREATE_NOP); v->head.hflag = lv->hflag; vert_mask_set(bm, v, lv->mask); + normal_short_to_float_v3(v->no, lv->no); bm_log_vert_id_set(log, v, GET_INT_FROM_POINTER(key)); } } @@ -295,7 +309,7 @@ static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces) bm_log_vert_from_id(log, lf->v_ids[2])}; BMFace *f; - f = BM_face_create_quad_tri_v(bm, v, 3, NULL, false); + f = BM_face_create_verts(bm, v, 3, NULL, BM_CREATE_NOP, true); bm_log_face_id_set(log, f, GET_INT_FROM_POINTER(key)); } } @@ -309,8 +323,12 @@ static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts) unsigned int id = GET_INT_FROM_POINTER(key); BMVert *v = bm_log_vert_from_id(log, id); float mask; + short normal[3]; swap_v3_v3(v->co, lv->co); + copy_v3_v3_short(normal, lv->no); + normal_float_to_short_v3(lv->no, v->no); + normal_short_to_float_v3(v->no, normal); SWAP(char, v->head.hflag, lv->hflag); mask = lv->mask; lv->mask = vert_mask_get(bm, v); @@ -404,7 +422,7 @@ static int uint_compare(const void *a_v, const void *b_v) */ static GHash *bm_log_compress_ids_to_indices(unsigned int *ids, int totid) { - GHash *map = BLI_ghash_int_new(AT); + GHash *map = BLI_ghash_int_new_ex(AT, totid); int i; qsort(ids, totid, sizeof(*ids), uint_compare); @@ -438,8 +456,8 @@ BMLog *BM_log_create(BMesh *bm) BMLog *log = MEM_callocN(sizeof(*log), AT); log->unused_ids = range_tree_uint_alloc(0, (unsigned)-1); - log->id_to_elem = BLI_ghash_ptr_new(AT); - log->elem_to_id = BLI_ghash_ptr_new(AT); + log->id_to_elem = BLI_ghash_ptr_new_ex(AT, bm->totvert + bm->totface); + log->elem_to_id = BLI_ghash_ptr_new_ex(AT, bm->totvert + bm->totface); /* Assign IDs to all existing vertices and faces */ bm_log_assign_ids(bm, log); @@ -931,6 +949,24 @@ const float *BM_log_original_vert_co(BMLog *log, BMVert *v) return lv->co; } +/* Get the logged normal of a vertex + * + * Does not modify the log or the vertex */ +const short *BM_log_original_vert_no(BMLog *log, BMVert *v) +{ + BMLogEntry *entry = log->current_entry; + const BMLogVert *lv; + unsigned v_id = bm_log_vert_id_get(log, v); + void *key = SET_INT_IN_POINTER(v_id); + + BLI_assert(entry); + + BLI_assert(BLI_ghash_haskey(entry->modified_verts, key)); + + lv = BLI_ghash_lookup(entry->modified_verts, key); + return lv->no; +} + /* Get the logged mask of a vertex * * Does not modify the log or the vertex */ diff --git a/source/blender/bmesh/intern/bmesh_log.h b/source/blender/bmesh/intern/bmesh_log.h index 958ff340b43..3cd2fd70081 100644 --- a/source/blender/bmesh/intern/bmesh_log.h +++ b/source/blender/bmesh/intern/bmesh_log.h @@ -21,16 +21,8 @@ #ifndef __BMESH_LOG_H__ #define __BMESH_LOG_H__ -/* The BMLog is an interface for storing undo/redo steps as a BMesh is - * modified. It only stores changes to the BMesh, not full copies. - * - * Currently it supports the following types of changes: - * - * - Adding and removing vertices - * - Adding and removing faces - * - Moving vertices - * - Setting vertex paint-mask values - * - Setting vertex hflags +/** \file blender/bmesh/intern/bmesh_log.h + * \ingroup bmesh */ struct BMFace; @@ -92,6 +84,9 @@ void BM_log_before_all_removed(BMesh *bm, BMLog *log); /* Get the logged coordinates of a vertex */ const float *BM_log_original_vert_co(BMLog *log, BMVert *v); +/* Get the logged normal of a vertex */ +const short *BM_log_original_vert_no(BMLog *log, BMVert *v); + /* Get the logged mask of a vertex */ float BM_log_original_mask(BMLog *log, BMVert *v); diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index 64368390444..cc2324ba34a 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -667,14 +667,14 @@ void BM_mesh_remap(BMesh *bm, int *vert_idx, int *edge_idx, int *face_idx) if (!(vert_idx || edge_idx || face_idx)) return; - /* Remap vertices */ + /* Remap Verts */ if (vert_idx) { BMVert **verts_pool, *verts_copy, **vep; int i, totvert = bm->totvert; int *new_idx = NULL; /* Init the old-to-new vert pointers mapping */ - vptr_map = BLI_ghash_ptr_new("BM_mesh_remap vert pointers mapping"); + vptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap vert pointers mapping", bm->totvert); /* Make a copy of all vertices. */ verts_pool = MEM_callocN(sizeof(BMVert *) * totvert, "BM_mesh_remap verts pool"); @@ -701,14 +701,14 @@ void BM_mesh_remap(BMesh *bm, int *vert_idx, int *edge_idx, int *face_idx) MEM_freeN(verts_copy); } - /* XXX Code not tested yet (though I don't why it would fail)! */ + /* Remap Edges */ if (edge_idx) { BMEdge **edges_pool, *edges_copy, **edp; int i, totedge = bm->totedge; int *new_idx = NULL; /* Init the old-to-new vert pointers mapping */ - eptr_map = BLI_ghash_ptr_new("BM_mesh_remap edge pointers mapping"); + eptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap edge pointers mapping", bm->totedge); /* Make a copy of all vertices. */ edges_pool = MEM_callocN(sizeof(BMEdge *) * totedge, "BM_mesh_remap edges pool"); @@ -734,14 +734,14 @@ void BM_mesh_remap(BMesh *bm, int *vert_idx, int *edge_idx, int *face_idx) MEM_freeN(edges_copy); } - /* XXX Code not tested yet (though I don't why it would fail)! */ + /* Remap Faces */ if (face_idx) { BMFace **faces_pool, *faces_copy, **fap; int i, totface = bm->totface; int *new_idx = NULL; /* Init the old-to-new vert pointers mapping */ - fptr_map = BLI_ghash_ptr_new("BM_mesh_remap face pointers mapping"); + fptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap face pointers mapping", bm->totface); /* Make a copy of all vertices. */ faces_pool = MEM_callocN(sizeof(BMFace *) * totface, "BM_mesh_remap faces pool"); diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h index efcd80b374b..583b1589290 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.h +++ b/source/blender/bmesh/intern/bmesh_mesh.h @@ -60,6 +60,13 @@ typedef struct BMAllocTemplate { extern const BMAllocTemplate bm_mesh_allocsize_default; extern const BMAllocTemplate bm_mesh_chunksize_default; +#define BMALLOC_TEMPLATE_FROM_BM(bm) { (CHECK_TYPE_INLINE(bm, BMesh *), \ + (bm)->totvert), (bm)->totedge, (bm)->totloop, (bm)->totface} +#define BMALLOC_TEMPLATE_FROM_ME(me) { (CHECK_TYPE_INLINE(me, Mesh *), \ + (me)->totvert), (me)->totedge, (me)->totloop, (me)->totpoly} +#define BMALLOC_TEMPLATE_FROM_DM(dm) { (CHECK_TYPE_INLINE(dm, DerivedMesh *), \ + (dm)->getNumVerts(dm)), (dm)->getNumEdges(dm), (dm)->getNumLoops(dm), (dm)->getNumPolys(dm)} + enum { BM_MESH_CREATE_USE_TOOLFLAGS = (1 << 0) }; diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c index 81d4aad0fdf..d92fe45afcd 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_conv.c +++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c @@ -212,7 +212,7 @@ static BMFace *bm_face_create_from_mpoly(MPoly *mp, MLoop *ml, edges[j] = etable[ml->e]; } - return BM_face_create(bm, verts, edges, mp->totloop, BM_CREATE_SKIP_CD); + return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD); } diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index 418fc16ea55..3ffdd0f86a6 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -356,10 +356,9 @@ BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **r_l if (f_new) { BM_elem_attrs_copy(bm, bm, f, f_new); - copy_v3_v3(f_new->no, f->no); /* handle multires update */ - if (has_mdisp && (f_new != f)) { + if (has_mdisp) { BMLoop *l_iter; BMLoop *l_first; @@ -373,8 +372,6 @@ BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **r_l BM_loop_interp_multires(bm, l_iter, f_tmp); } while ((l_iter = l_iter->next) != l_first); - BM_face_kill(bm, f_tmp); - #if 0 /* BM_face_multires_bounds_smooth doesn't flip displacement correct */ BM_face_multires_bounds_smooth(bm, f); @@ -383,6 +380,10 @@ BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **r_l } } + if (has_mdisp) { + BM_face_kill(bm, f_tmp); + } + return f_new; } @@ -1067,7 +1068,7 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f /* first create the new edge, this is so we can copy the customdata from the old one * if splice if disabled, always add in a new edge even if theres one there. */ - e_new = BM_edge_create(bm, v1, v2, e, (check_flag & BM_EDGEROT_CHECK_SPLICE) != 0); + e_new = BM_edge_create(bm, v1, v2, e, (check_flag & BM_EDGEROT_CHECK_SPLICE) ? BM_CREATE_NO_DOUBLE : BM_CREATE_NOP); f_hflag_prev_1 = l1->f->head.hflag; f_hflag_prev_2 = l2->f->head.hflag; diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 4f8a851c780..775cb24b8c9 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -542,6 +542,7 @@ static BMOpDefine bmo_grid_fill_def = { /* restricts edges to groups. maps edges to integer */ {"mat_nr", BMO_OP_SLOT_INT}, /* material to use */ {"use_smooth", BMO_OP_SLOT_BOOL}, /* smooth state to use */ + {"use_interp_simple", BMO_OP_SLOT_BOOL}, /* use simple interpolation */ {{'\0'}}, }, /* slots_out */ @@ -577,6 +578,28 @@ static BMOpDefine bmo_holes_fill_def = { /* + * Face Attribute Fill. + * + * Fill in faces with data from adjacent faces. + */ +static BMOpDefine bmo_face_attribute_fill_def = { + "face_attribute_fill", + /* slots_in */ + {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ + {"use_normals", BMO_OP_SLOT_BOOL}, /* copy face winding */ + {"use_data", BMO_OP_SLOT_BOOL}, /* copy face data */ + {{'\0'}}, + }, + /* slots_out */ + /* maps new faces to the group numbers they came from */ + {{"faces_fail.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* faces that could not be handled */ + {{'\0'}}, + }, + bmo_face_attribute_fill_exec, + BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, +}; + +/* * Edge Loop Fill. * * Create faces defined by one or more non overlapping edge loops. @@ -609,19 +632,14 @@ static BMOpDefine bmo_edgenet_fill_def = { "edgenet_fill", /* slots_in */ {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */ - /* restricts edges to groups. maps edges to integer */ - {"restrict", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_BOOL}}, - {"use_restrict", BMO_OP_SLOT_BOOL}, - {"use_fill_check", BMO_OP_SLOT_BOOL}, - {"exclude_faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* list of faces to ignore for manifold check */ - {"mat_nr", BMO_OP_SLOT_INT}, /* material to use */ - {"use_smooth", BMO_OP_SLOT_BOOL}, /* smooth state to use */ + {"mat_nr", BMO_OP_SLOT_INT}, /* material to use */ + {"use_smooth", BMO_OP_SLOT_BOOL}, /* smooth state to use */ + {"sides", BMO_OP_SLOT_INT}, /* number of sides */ {{'\0'}}, }, /* slots_out */ /* maps new faces to the group numbers they came from */ - {{"face_groupmap.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, - {"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* new faces */ + {{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* new faces */ {{'\0'}}, }, bmo_edgenet_fill_exec, @@ -1101,6 +1119,30 @@ static BMOpDefine bmo_subdivide_edgering_def = { }; /* + * Bisect Plane. + * + * Bisects the mesh by a plane (cut the mesh in half). + */ +static BMOpDefine bmo_bisect_plane_def = { + "bisect_plane", + /* slots_in */ + {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, + {"dist", BMO_OP_SLOT_FLT}, /* minimum distance when testing if a vert is exactly on the plane */ + {"plane_co", BMO_OP_SLOT_VEC}, /* point on the plane */ + {"plane_no", BMO_OP_SLOT_VEC}, /* direction of the plane */ + {"use_snap_center", BMO_OP_SLOT_BOOL}, /* snap axis aligned verts to the center */ + {"clear_outer", BMO_OP_SLOT_BOOL}, /* when enabled. remove all geometry on the positive side of the plane */ + {"clear_inner", BMO_OP_SLOT_BOOL}, /* when enabled. remove all geometry on the negative side of the plane */ + {{'\0'}}, + }, + {{"geom_cut.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE}}, /* output new geometry from the cut */ + {"geom.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input and output geometry (result of cut) */ + {{'\0'}}}, + bmo_bisect_plane_exec, + BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, +}; + +/* * Delete Geometry. * * Utility operator to delete geometry. @@ -1136,6 +1178,8 @@ static BMOpDefine bmo_duplicate_def = { {"geom.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* facemap maps from source faces to dupe * faces, and from dupe faces to source faces */ + {"vert_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, + {"edge_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, {"face_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, {"boundary_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, {"isovert_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, @@ -1536,6 +1580,7 @@ static BMOpDefine bmo_beautify_fill_def = { {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ {"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* edges that can be flipped */ {"use_restrict_tag", BMO_OP_SLOT_BOOL}, /* restrict edge rotation to mixed tagged vertices */ + {"method", BMO_OP_SLOT_INT}, /* method to define what is beautiful */ {{'\0'}}, }, /* slots_out */ @@ -1555,7 +1600,9 @@ static BMOpDefine bmo_triangle_fill_def = { "triangle_fill", /* slots_in */ {{"use_beauty", BMO_OP_SLOT_BOOL}, + {"use_dissolve", BMO_OP_SLOT_BOOL}, /* dissolve resulting faces */ {"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */ + {"normal", BMO_OP_SLOT_VEC}, /* optionally pass the fill normal to use */ {{'\0'}}, }, /* slots_out */ @@ -1607,7 +1654,7 @@ static BMOpDefine bmo_inset_individual_def = { {{'\0'}}, }, bmo_inset_individual_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + BMO_OPTYPE_FLAG_NORMALS_CALC, /* caller needs to handle BMO_OPTYPE_FLAG_SELECT_FLUSH */ }; /* @@ -1734,6 +1781,7 @@ static BMOpDefine bmo_symmetrize_def = { /* slots_in */ {{"input", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, {"direction", BMO_OP_SLOT_INT}, + {"dist", BMO_OP_SLOT_FLT}, /* minimum distance */ {{'\0'}}, }, /* slots_out */ @@ -1776,6 +1824,7 @@ const BMOpDefine *bmo_opdefines[] = { &bmo_dissolve_verts_def, &bmo_duplicate_def, &bmo_holes_fill_def, + &bmo_face_attribute_fill_def, &bmo_edgeloop_fill_def, &bmo_edgenet_fill_def, &bmo_edgenet_prepare_def, @@ -1816,6 +1865,7 @@ const BMOpDefine *bmo_opdefines[] = { &bmo_split_edges_def, &bmo_subdivide_edges_def, &bmo_subdivide_edgering_def, + &bmo_bisect_plane_def, &bmo_symmetrize_def, &bmo_transform_def, &bmo_translate_def, diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h index 24bfcd70d75..7de158f3c29 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api.h +++ b/source/blender/bmesh/intern/bmesh_operator_api.h @@ -335,6 +335,11 @@ void BMO_slot_mat3_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, const char htype, const short oflag); +void BMO_mesh_selected_remap(BMesh *bm, + BMOpSlot *slot_vert_map, + BMOpSlot *slot_edge_map, + BMOpSlot *slot_face_map); + /* copies the values from another slot to the end of the output slot */ #define BMO_slot_buffer_append(op_src, slots_src, slot_name_src, \ op_dst, slots_dst, slot_name_dst) \ @@ -398,7 +403,7 @@ int BMO_slot_buffer_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot int BMO_slot_map_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name); void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot, - const void *element, const void *data, const int len); + const void *element, const void *data); /* flags all elements in a mapping. note that the mapping must only have * bmesh elements in it.*/ @@ -452,7 +457,7 @@ typedef struct BMOIter { BMOpSlot *slot; int cur; //for arrays GHashIterator giter; - void *val; + void **val; char restrictmask; /* bitwise '&' with BMHeader.htype */ } BMOIter; @@ -463,15 +468,12 @@ void *BMO_iter_new(BMOIter *iter, const char restrictmask); void *BMO_iter_step(BMOIter *iter); -/* returns a pointer to the key value when iterating over mappings. - * remember for pointer maps this will be a pointer to a pointer.*/ -void *BMO_iter_map_value(BMOIter *iter); - -/* use this for pointer mappings */ -void *BMO_iter_map_value_p(BMOIter *iter); +void **BMO_iter_map_value_p(BMOIter *iter); +void *BMO_iter_map_value_ptr(BMOIter *iter); -/* use this for float mappings */ -float BMO_iter_map_value_f(BMOIter *iter); +float BMO_iter_map_value_float(BMOIter *iter); +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)) @@ -479,16 +481,6 @@ float BMO_iter_map_value_f(BMOIter *iter); /******************* Inlined Functions********************/ typedef void (*opexec)(BMesh *bm, BMOperator *op); -/* mappings map elements to data, which - * follows the mapping struct in memory. */ -typedef struct BMOElemMapping { - BMHeader *element; - int len; -} BMOElemMapping; - -/* pointer after BMOElemMapping */ -#define BMO_OP_SLOT_MAPPING_DATA(var) (void *)(((BMOElemMapping *)var) + 1) - extern const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES]; int BMO_opcode_from_opname(const char *opname); diff --git a/source/blender/bmesh/intern/bmesh_operator_api_inline.h b/source/blender/bmesh/intern/bmesh_operator_api_inline.h index 724ddcf3b04..77310d958e6 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api_inline.h +++ b/source/blender/bmesh/intern/bmesh_operator_api_inline.h @@ -55,13 +55,13 @@ BLI_INLINE void _bmo_elem_flag_enable(BMesh *bm, BMFlagLayer *oflags, const shor BLI_INLINE void _bmo_elem_flag_disable(BMesh *bm, BMFlagLayer *oflags, const short oflag) { - oflags[bm->stackdepth - 1].f &= ~oflag; + oflags[bm->stackdepth - 1].f &= (short)~oflag; } BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short oflag, int val) { if (val) oflags[bm->stackdepth - 1].f |= oflag; - else oflags[bm->stackdepth - 1].f &= ~oflag; + else oflags[bm->stackdepth - 1].f &= (short)~oflag; } BLI_INLINE void _bmo_elem_flag_toggle(BMesh *bm, BMFlagLayer *oflags, const short oflag) @@ -72,23 +72,26 @@ BLI_INLINE void _bmo_elem_flag_toggle(BMesh *bm, BMFlagLayer *oflags, const shor BLI_INLINE void BMO_slot_map_int_insert(BMOperator *op, BMOpSlot *slot, void *element, const int val) { + union { void *ptr; int val; } t = {NULL}; BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_INT); - BMO_slot_map_insert(op, slot, element, &val, sizeof(int)); + BMO_slot_map_insert(op, slot, element, ((t.val = val), t.ptr)); } BLI_INLINE void BMO_slot_map_bool_insert(BMOperator *op, BMOpSlot *slot, void *element, const int val) { + union { void *ptr; int val; } t = {NULL}; BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_BOOL); BLI_assert(val == false || val == true); - BMO_slot_map_insert(op, slot, element, &val, sizeof(int)); + BMO_slot_map_insert(op, slot, element, ((t.val = val), t.ptr)); } BLI_INLINE void BMO_slot_map_float_insert(BMOperator *op, BMOpSlot *slot, void *element, const float val) { + union { void *ptr; float val; } t = {NULL}; BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_FLT); - BMO_slot_map_insert(op, slot, element, &val, sizeof(float)); + BMO_slot_map_insert(op, slot, element, ((t.val = val), t.ptr)); } @@ -101,14 +104,14 @@ BLI_INLINE void BMO_slot_map_ptr_insert(BMOperator *op, BMOpSlot *slot, const void *element, void *val) { BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL); - BMO_slot_map_insert(op, slot, element, &val, sizeof(void *)); + BMO_slot_map_insert(op, slot, element, val); } BLI_INLINE void BMO_slot_map_elem_insert(BMOperator *op, BMOpSlot *slot, const void *element, void *val) { BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_ELEM); - BMO_slot_map_insert(op, slot, element, &val, sizeof(void *)); + BMO_slot_map_insert(op, slot, element, val); } @@ -117,77 +120,66 @@ BLI_INLINE void BMO_slot_map_empty_insert(BMOperator *op, BMOpSlot *slot, const void *element) { BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_EMPTY); - BMO_slot_map_insert(op, slot, element, NULL, 0); + BMO_slot_map_insert(op, slot, element, NULL); } BLI_INLINE bool BMO_slot_map_contains(BMOpSlot *slot, const void *element) { BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING); - - /* sanity check */ - if (UNLIKELY(slot->data.ghash == NULL)) { - return false; - } - return BLI_ghash_haskey(slot->data.ghash, element); } -BLI_INLINE void *BMO_slot_map_data_get(BMOpSlot *slot, const void *element) +BLI_INLINE void **BMO_slot_map_data_get(BMOpSlot *slot, const void *element) { - BMOElemMapping *mapping; - BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING); - - /* sanity check */ - if (UNLIKELY(slot->data.ghash == NULL)) { - return NULL; - } - - mapping = (BMOElemMapping *)BLI_ghash_lookup(slot->data.ghash, element); - - if (!mapping) { - return NULL; - } - return mapping + 1; + return BLI_ghash_lookup_p(slot->data.ghash, element); } BLI_INLINE float BMO_slot_map_float_get(BMOpSlot *slot, const void *element) { - float *val; + void **data; BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_FLT); - val = (float *) BMO_slot_map_data_get(slot, element); - if (val) return *val; - - return 0.0f; + data = BMO_slot_map_data_get(slot, element); + if (data) { + return **(float **)data; + } + else { + return 0.0f; + } } BLI_INLINE int BMO_slot_map_int_get(BMOpSlot *slot, const void *element) { - int *val; + void **data; BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_INT); - val = (int *) BMO_slot_map_data_get(slot, element); - if (val) return *val; - - return 0; + data = BMO_slot_map_data_get(slot, element); + if (data) { + return **(int **)data; + } + else { + return 0; + } } BLI_INLINE bool BMO_slot_map_bool_get(BMOpSlot *slot, const void *element) { - int *val; + void **data; BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_BOOL); - val = (int *) BMO_slot_map_data_get(slot, element); - BLI_assert(val == NULL || *val == false || *val == true); - if (val) return (bool)*val; - - return false; + data = BMO_slot_map_data_get(slot, element); + if (data) { + return **(int **)data; + } + else { + return false; + } } BLI_INLINE void *BMO_slot_map_ptr_get(BMOpSlot *slot, const void *element) { - void **val = (void **) BMO_slot_map_data_get(slot, element); + void **val = BMO_slot_map_data_get(slot, element); BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL); if (val) return *val; diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c index b71d5a7e7d4..611ee4d03b8 100644 --- a/source/blender/bmesh/intern/bmesh_operators.c +++ b/source/blender/bmesh/intern/bmesh_operators.c @@ -74,7 +74,7 @@ const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES] = { 0, /* 7: unused */ sizeof(float) * 3, /* 8: BMO_OP_SLOT_VEC */ sizeof(void *), /* 9: BMO_OP_SLOT_ELEMENT_BUF */ - sizeof(BMOElemMapping) /* 10: BMO_OP_SLOT_MAPPING */ + sizeof(void *) /* 10: BMO_OP_SLOT_MAPPING */ }; /* Dummy slot so there is something to return when slot name lookup fails */ @@ -127,12 +127,38 @@ void BMO_pop(BMesh *bm) /* use for both slot_types_in and slot_types_out */ static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args) { + BMOpSlot *slot; + unsigned int i; + for (i = 0; slot_types[i].type; i++) { + slot = &slot_args[i]; + slot->slot_name = slot_types[i].name; + slot->slot_type = slot_types[i].type; + slot->slot_subtype = slot_types[i].subtype; + // slot->index = i; // UNUSED + + switch (slot->slot_type) { + case BMO_OP_SLOT_MAPPING: + slot->data.ghash = BLI_ghash_ptr_new("bmesh slot map hash"); + break; + default: + break; + } + } +} + +static void bmo_op_slots_free(const BMOSlotType *slot_types, BMOpSlot *slot_args) +{ + BMOpSlot *slot; unsigned int i; for (i = 0; slot_types[i].type; i++) { - slot_args[i].slot_name = slot_types[i].name; - slot_args[i].slot_type = slot_types[i].type; - slot_args[i].slot_subtype = slot_types[i].subtype; - // slot_args[i].index = i; // UNUSED + slot = &slot_args[i]; + switch (slot->slot_type) { + case BMO_OP_SLOT_MAPPING: + BLI_ghash_free(slot->data.ghash, NULL, NULL); + break; + default: + break; + } } } @@ -198,20 +224,6 @@ void BMO_op_exec(BMesh *bm, BMOperator *op) BMO_pop(bm); } -static void bmo_op_slots_free(const BMOSlotType *slot_types, BMOpSlot *slot_args) -{ - BMOpSlot *slot; - unsigned int i; - for (i = 0; slot_types[i].type; i++) { - slot = &slot_args[i]; - if (slot->slot_type == BMO_OP_SLOT_MAPPING) { - if (slot->data.ghash) { - BLI_ghash_free(slot->data.ghash, NULL, NULL); - } - } - } -} - /** * \brief BMESH OPSTACK FINISH OP * @@ -333,28 +345,13 @@ void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS], const char *slot_n } else if (slot_dst->slot_type == BMO_OP_SLOT_MAPPING) { GHashIterator it; - BMOElemMapping *srcmap, *dstmap; - - /* sanity check */ - if (!slot_src->data.ghash) { - return; - } - - if (!slot_dst->data.ghash) { - slot_dst->data.ghash = BLI_ghash_ptr_new("bmesh operator 2"); - } - for (BLI_ghashIterator_init(&it, slot_src->data.ghash); - (srcmap = BLI_ghashIterator_getValue(&it)); + BLI_ghashIterator_done(&it) == false; BLI_ghashIterator_step(&it)) { - dstmap = BLI_memarena_alloc(arena_dst, sizeof(*dstmap) + srcmap->len); - - dstmap->element = srcmap->element; - dstmap->len = srcmap->len; - memcpy(BMO_OP_SLOT_MAPPING_DATA(dstmap), BMO_OP_SLOT_MAPPING_DATA(srcmap), srcmap->len); - - BLI_ghash_insert(slot_dst->data.ghash, dstmap->element, dstmap); + void *key = BLI_ghashIterator_getKey(&it); + void *val = BLI_ghashIterator_getValue(&it); + BLI_ghash_insert(slot_dst->data.ghash, key, val); } } else { @@ -605,6 +602,44 @@ void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char hty } } +void BMO_mesh_selected_remap(BMesh *bm, + BMOpSlot *slot_vert_map, + BMOpSlot *slot_edge_map, + BMOpSlot *slot_face_map) +{ + if (bm->selected.first) { + BMEditSelection *ese, *ese_next; + BMOpSlot *slot_elem_map; + + for (ese = bm->selected.first; ese; ese = ese_next) { + ese_next = ese->next; + + switch (ese->htype) { + case BM_VERT: slot_elem_map = slot_vert_map; break; + case BM_EDGE: slot_elem_map = slot_edge_map; break; + default: slot_elem_map = slot_face_map; break; + } + + ese->ele = BMO_slot_map_elem_get(slot_elem_map, ese->ele); + + if (UNLIKELY((ese->ele == NULL) || + (BM_elem_flag_test(ese->ele, BM_ELEM_SELECT) == false))) + { + BLI_remlink(&bm->selected, ese); + MEM_freeN(ese); + } + } + } + + if (bm->act_face) { + BMFace *f = BMO_slot_map_elem_get(slot_face_map, bm->act_face); + if (f) { + bm->act_face = f; + } + } +} + + int BMO_slot_buffer_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name) { BMOpSlot *slot = BMO_slot_get(slot_args, slot_name); @@ -621,38 +656,21 @@ int BMO_slot_map_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_na { BMOpSlot *slot = BMO_slot_get(slot_args, slot_name); BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING); - - /* check if its actually a buffer */ - if (!(slot->slot_type == BMO_OP_SLOT_MAPPING)) - return 0; - - return slot->data.ghash ? BLI_ghash_size(slot->data.ghash) : 0; + return BLI_ghash_size(slot->data.ghash); } /* inserts a key/value mapping into a mapping slot. note that it copies the * value, it doesn't store a reference to it. */ void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot, - const void *element, const void *data, const int len) + const void *element, const void *data) { - BMOElemMapping *mapping; + (void) op; /* Ignored in release builds. */ + BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING); BMO_ASSERT_SLOT_IN_OP(slot, op); - mapping = (BMOElemMapping *) BLI_memarena_alloc(op->arena, sizeof(*mapping) + len); - - mapping->element = (BMHeader *) element; - mapping->len = len; - memcpy(BMO_OP_SLOT_MAPPING_DATA(mapping), data, len); - - if (!slot->data.ghash) { - slot->data.ghash = BLI_ghash_ptr_new("bmesh slot map hash"); - } - else { - BLI_assert(slot->data.ghash); - } - - BLI_ghash_insert(slot->data.ghash, (void *)element, mapping); + BLI_ghash_insert(slot->data.ghash, (void *)element, (void *)data); } #if 0 @@ -707,11 +725,11 @@ void BMO_slot_map_to_flag(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING); - /* sanity check */ - if (!slot->data.ghash) return; - BLI_ghashIterator_init(&it, slot->data.ghash); - for ( ; (ele_f = BLI_ghashIterator_getKey(&it)); BLI_ghashIterator_step(&it)) { + for (BLI_ghashIterator_init(&it, slot->data.ghash); + (ele_f = BLI_ghashIterator_getKey(&it)); + BLI_ghashIterator_step(&it)) + { if (ele_f->head.htype & htype) { BMO_elem_flag_enable(bm, ele_f, oflag); } @@ -1360,12 +1378,7 @@ void *BMO_iter_new(BMOIter *iter, iter->restrictmask = restrictmask; if (iter->slot->slot_type == BMO_OP_SLOT_MAPPING) { - if (iter->slot->data.ghash) { - BLI_ghashIterator_init(&iter->giter, slot->data.ghash); - } - else { - return NULL; - } + BLI_ghashIterator_init(&iter->giter, slot->data.ghash); } else if (iter->slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF) { BLI_assert(restrictmask & slot->slot_subtype.elem); @@ -1402,11 +1415,8 @@ void *BMO_iter_step(BMOIter *iter) return ele; } else if (slot->slot_type == BMO_OP_SLOT_MAPPING) { - BMOElemMapping *map; void *ret = BLI_ghashIterator_getKey(&iter->giter); - map = BLI_ghashIterator_getValue(&iter->giter); - - iter->val = BMO_OP_SLOT_MAPPING_DATA(map); + iter->val = BLI_ghashIterator_getValue_p(&iter->giter); BLI_ghashIterator_step(&iter->giter); @@ -1420,19 +1430,40 @@ void *BMO_iter_step(BMOIter *iter) } /* used for iterating over mappings */ -void *BMO_iter_map_value(BMOIter *iter) + +/** + * Returns a pointer to the key-value when iterating over mappings. + * remember for pointer maps this will be a pointer to a pointer. + */ +void **BMO_iter_map_value_p(BMOIter *iter) { return iter->val; } -void *BMO_iter_map_value_p(BMOIter *iter) +void *BMO_iter_map_value_ptr(BMOIter *iter) +{ + BLI_assert(ELEM(iter->slot->slot_subtype.map, + BMO_OP_SLOT_SUBTYPE_MAP_ELEM, BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL)); + return iter->val ? *iter->val : NULL; +} + + +float BMO_iter_map_value_float(BMOIter *iter) { - return *((void **)iter->val); + BLI_assert(iter->slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_FLT); + return **((float **)iter->val); } -float BMO_iter_map_value_f(BMOIter *iter) +int BMO_iter_map_value_int(BMOIter *iter) { - return *((float *)iter->val); + BLI_assert(iter->slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_INT); + return **((int **)iter->val); +} + +bool BMO_iter_map_value_bool(BMOIter *iter) +{ + BLI_assert(iter->slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_BOOL); + return **((int **)iter->val); } /* error system */ @@ -1608,9 +1639,9 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, // BMOpDefine *def; char *opname, *ofmt, *fmt; char slot_name[64] = {0}; - int i /*, n = strlen(fmt) */, stop /*, slot_code = -1 */, type, state; + int i, type; + bool noslot, state; char htype; - int noslot = 0; /* basic useful info to help find where bmop formatting strings fail */ @@ -1631,7 +1662,7 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, i = strcspn(fmt, " "); opname = fmt; - if (!opname[i]) noslot = 1; + noslot = (opname[i] == '\0'); opname[i] = '\0'; fmt += i + (noslot ? 0 : 1); @@ -1648,7 +1679,7 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, // def = bmo_opdefines[i]; i = 0; - state = 1; /* 0: not inside slot_code name, 1: inside slot_code name */ + state = true; /* false: not inside slot_code name, true: inside slot_code name */ while (*fmt) { if (state) { @@ -1674,7 +1705,7 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, BLI_strncpy(slot_name, fmt, sizeof(slot_name)); - state = 0; + state = false; fmt += i; } else { @@ -1695,13 +1726,13 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, else GOTO_ERROR("matrix size was not 3 or 4"); BMO_slot_mat_set(op, op->slots_in, slot_name, va_arg(vlist, void *), size); - state = 1; + state = true; break; } case 'v': { BMO_slot_vec_set(op->slots_in, slot_name, va_arg(vlist, float *)); - state = 1; + state = true; break; } case 'e': /* single vert/edge/face */ @@ -1711,7 +1742,7 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, BMO_slot_buffer_from_single(op, slot, ele); - state = 1; + state = true; break; } case 's': @@ -1730,20 +1761,20 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, BMO_slot_copy(op_other, slots_out, slot_name_other, op, slots_in, slot_name); } - state = 1; + state = true; break; } case 'i': BMO_slot_int_set(op->slots_in, slot_name, va_arg(vlist, int)); - state = 1; + state = true; break; case 'b': BMO_slot_bool_set(op->slots_in, slot_name, va_arg(vlist, int)); - state = 1; + state = true; break; case 'p': BMO_slot_ptr_set(op->slots_in, slot_name, va_arg(vlist, void *)); - state = 1; + state = true; break; case 'f': case 'F': @@ -1756,15 +1787,16 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, BMO_slot_float_set(op->slots_in, slot_name, va_arg(vlist, double)); } else { + bool stop = false; + htype = 0; - stop = 0; while (1) { switch (NEXT_CHAR(fmt)) { case 'f': htype |= BM_FACE; break; case 'e': htype |= BM_EDGE; break; case 'v': htype |= BM_VERT; break; default: - stop = 1; + stop = true; break; } if (stop) { @@ -1791,11 +1823,11 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, } } - state = 1; + state = true; break; default: fprintf(stderr, - "%s: unrecognized bmop format char: %c, %d in '%s'\n", + "%s: unrecognized bmop format char: '%c', %d in '%s'\n", __func__, *fmt, (int)(fmt - ofmt), ofmt); break; } diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h index 33c10411c0f..07d0ceb3aa3 100644 --- a/source/blender/bmesh/intern/bmesh_operators_private.h +++ b/source/blender/bmesh/intern/bmesh_operators_private.h @@ -35,6 +35,7 @@ void bmo_average_vert_facedata_exec(BMesh *bm, BMOperator *op); void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op); void bmo_bevel_exec(BMesh *bm, BMOperator *op); void bmo_bisect_edges_exec(BMesh *bm, BMOperator *op); +void bmo_bisect_plane_exec(BMesh *bm, BMOperator *op); void bmo_bmesh_to_mesh_exec(BMesh *bm, BMOperator *op); void bmo_bridge_loops_exec(BMesh *bm, BMOperator *op); void bmo_collapse_exec(BMesh *bm, BMOperator *op); @@ -59,6 +60,7 @@ void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op); void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op); void bmo_duplicate_exec(BMesh *bm, BMOperator *op); void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op); +void bmo_face_attribute_fill_exec(BMesh *bm, BMOperator *op); void bmo_holes_fill_exec(BMesh *bm, BMOperator *op); void bmo_edgenet_fill_exec(BMesh *bm, BMOperator *op); void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op); diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index 43b261c118d..0978faee9e4 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -829,7 +829,9 @@ static bool bm_face_goodline(float const (*projectverts)[2], BMFace *f, int v1i, continue; } - if (isect_point_tri_v2(pv1, v1, v2, v3) || isect_point_tri_v2(pv1, v3, v2, v1)) { + if (isect_point_tri_v2(pv1, v1, v2, v3) || + isect_point_tri_v2(pv1, v3, v2, v1)) + { #if 0 if (isect_point_tri_v2(pv1, v1, v2, v3)) printf("%d in (%d, %d, %d)\n", v3i, i, v1i, v2i); @@ -863,7 +865,10 @@ static BMLoop *poly_find_ear(BMFace *f, float (*projectverts)[2], const bool use const float cos_threshold = 0.9f; const float bias = 1.0f + 1e-6f; - BLI_assert(len_squared_v3(f->no) > FLT_EPSILON); + /* just triangulate degenerate faces */ + if (UNLIKELY(is_zero_v3(f->no))) { + return BM_FACE_FIRST_LOOP(f); + } if (f->len == 4) { BMLoop *larr[4]; @@ -875,10 +880,10 @@ static BMLoop *poly_find_ear(BMFace *f, float (*projectverts)[2], const bool use i++; } while ((l_iter = l_iter->next) != l_first); - /* pick 0/1 based on best lenth */ + /* pick 0/1 based on best length */ /* XXX Can't only rely on such test, also must check we do not get (too much) degenerated triangles!!! */ i = (((len_squared_v3v3(larr[0]->v->co, larr[2]->v->co) > - len_squared_v3v3(larr[1]->v->co, larr[3]->v->co) * bias)) != use_beauty); + len_squared_v3v3(larr[1]->v->co, larr[3]->v->co) * bias)) != use_beauty); i4 = (i + 3) % 4; /* Check produced tris aren't too flat/narrow... * Probably not the best test, but is quite efficient and should at least avoid null-area faces! */ @@ -891,6 +896,7 @@ static BMLoop *poly_find_ear(BMFace *f, float (*projectverts)[2], const bool use #endif if (cos1 < cos2) cos1 = cos2; + if (cos1 > cos_threshold) { if (cos1 > fabsf(cos_v3v3v3(larr[i]->v->co, larr[i4]->v->co, larr[i + 2]->v->co)) && cos1 > fabsf(cos_v3v3v3(larr[i]->v->co, larr[i + 1]->v->co, larr[i + 2]->v->co))) @@ -901,8 +907,10 @@ static BMLoop *poly_find_ear(BMFace *f, float (*projectverts)[2], const bool use /* Last check we do not get overlapping triangles * (as much as possible, there are some cases with no good solution!) */ i4 = (i + 3) % 4; - if (!bm_face_goodline((float const (*)[2])projectverts, f, BM_elem_index_get(larr[i4]->v), - BM_elem_index_get(larr[i]->v), BM_elem_index_get(larr[i + 1]->v))) + if (!bm_face_goodline((float const (*)[2])projectverts, f, + BM_elem_index_get(larr[i4]->v), + BM_elem_index_get(larr[i]->v), + BM_elem_index_get(larr[i + 1]->v))) { i = !i; } @@ -912,13 +920,13 @@ static BMLoop *poly_find_ear(BMFace *f, float (*projectverts)[2], const bool use } else { /* float angle, bestangle = 180.0f; */ - float cos, bestcos = 1.0f; - int i, j, len; + const int len = f->len; + float cos, cos_best = 1.0f; + int i, j; /* Compute cos of all corners! */ i = 0; l_iter = l_first = BM_FACE_FIRST_LOOP(f); - len = l_iter->f->len; do { const BMVert *v1 = l_iter->prev->v; const BMVert *v2 = l_iter->v; @@ -936,39 +944,41 @@ static BMLoop *poly_find_ear(BMFace *f, float (*projectverts)[2], const bool use const BMVert *v2 = l_iter->v; const BMVert *v3 = l_iter->next->v; - if (bm_face_goodline((float const (*)[2])projectverts, f, - BM_elem_index_get(v1), BM_elem_index_get(v2), BM_elem_index_get(v3))) - { - /* Compute highest cos (i.e. narrowest angle) of this tri. */ - cos = max_fff(abscoss[i], - fabsf(cos_v3v3v3(v2->co, v3->co, v1->co)), - fabsf(cos_v3v3v3(v3->co, v1->co, v2->co))); - - /* Compare to prev best (i.e. lowest) cos. */ - if (cos < bestcos) { + /* Compute highest cos (i.e. narrowest angle) of this tri. */ + cos = max_fff(abscoss[i], + fabsf(cos_v3v3v3(v2->co, v3->co, v1->co)), + fabsf(cos_v3v3v3(v3->co, v1->co, v2->co))); + + /* Compare to prev best (i.e. lowest) cos. */ + if (cos < cos_best) { + if (bm_face_goodline((float const (*)[2])projectverts, f, + BM_elem_index_get(v1), + BM_elem_index_get(v2), + BM_elem_index_get(v3))) + { /* We must check this tri would not leave a (too much) degenerated remaining face! */ /* For now just assume if the average of cos of all * "remaining face"'s corners is below a given threshold, it's OK. */ - float avgcos = fabsf(cos_v3v3v3(v1->co, v3->co, l_iter->next->next->v->co)); + float cos_mean = fabsf(cos_v3v3v3(v1->co, v3->co, l_iter->next->next->v->co)); const int i_limit = (i - 1 + len) % len; - avgcos += fabsf(cos_v3v3v3(l_iter->prev->prev->v->co, v1->co, v3->co)); + cos_mean += fabsf(cos_v3v3v3(l_iter->prev->prev->v->co, v1->co, v3->co)); j = (i + 2) % len; do { - avgcos += abscoss[j]; + cos_mean += abscoss[j]; } while ((j = (j + 1) % len) != i_limit); - avgcos /= len - 1; + cos_mean /= len - 1; /* We need a best ear in any case... */ - if (avgcos < cos_threshold || (!bestear && avgcos < 1.0f)) { + if (cos_mean < cos_threshold || (!bestear && cos_mean < 1.0f)) { /* OKI, keep this ear (corner...) as a potential best one! */ bestear = l_iter; - bestcos = cos; + cos_best = cos; } #if 0 else - printf("Had a nice tri (higest cos of %f, current bestcos is %f), " + printf("Had a nice tri (higest cos of %f, current cos_best is %f), " "but average cos of all \"remaining face\"'s corners is too high (%f)!\n", - cos, bestcos, avgcos); + cos, cos_best, cos_mean); #endif } } @@ -1203,3 +1213,37 @@ void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]) r_verts[2] = l->v; l = l->next; r_verts[3] = l->v; } + + +/** + * Small utility functions for fast access + * + * faster alternative to: + * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 3); + */ +void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3]) +{ + BMLoop *l = BM_FACE_FIRST_LOOP(f); + + BLI_assert(f->len == 3); + + r_loops[0] = l; l = l->next; + r_loops[1] = l; l = l->next; + r_loops[2] = l; +} + +/** + * faster alternative to: + * BM_iter_as_array(bm, BM_LOOPS_OF_FACE, f, (void **)l, 4); + */ +void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4]) +{ + BMLoop *l = BM_FACE_FIRST_LOOP(f); + + BLI_assert(f->len == 4); + + r_loops[0] = l; l = l->next; + r_loops[1] = l; l = l->next; + r_loops[2] = l; l = l->next; + r_loops[3] = l; +} diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h index e5dc5c081c3..14fe1e76360 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.h +++ b/source/blender/bmesh/intern/bmesh_polygon.h @@ -27,40 +27,40 @@ * \ingroup bmesh */ -int BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, int (*r_index)[3]) -#ifdef __GNUC__ - __attribute__((warn_unused_result)) - __attribute__((nonnull)) -#endif -; -void BM_face_calc_normal(const BMFace *f, float r_no[3]); +#include "BLI_compiler_attrs.h" + +int BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, int (*r_index)[3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL(); void BM_face_calc_normal_vcos(BMesh *bm, BMFace *f, float r_no[3], - float const (*vertexCos)[3]); -float BM_face_calc_area(BMFace *f); -float BM_face_calc_perimeter(BMFace *f); -void BM_face_calc_plane(BMFace *f, float r_plane[3]); -void BM_face_calc_center_bounds(BMFace *f, float center[3]); -void BM_face_calc_center_mean(BMFace *f, float center[3]); + float const (*vertexCos)[3]) ATTR_NONNULL(); +float BM_face_calc_area(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_face_calc_perimeter(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void BM_face_calc_plane(BMFace *f, float r_plane[3]) ATTR_NONNULL(); +void BM_face_calc_center_bounds(BMFace *f, float center[3]) ATTR_NONNULL(); +void BM_face_calc_center_mean(BMFace *f, float center[3]) ATTR_NONNULL(); void BM_face_calc_center_mean_vcos(BMesh *bm, BMFace *f, float r_cent[3], - float const (*vertexCos)[3]); -void BM_face_calc_center_mean_weighted(BMFace *f, float center[3]); + float const (*vertexCos)[3]) ATTR_NONNULL(); +void BM_face_calc_center_mean_weighted(BMFace *f, float center[3]) ATTR_NONNULL(); -void BM_face_normal_update(BMFace *f); +void BM_face_normal_update(BMFace *f) ATTR_NONNULL(); -void BM_edge_normals_update(BMEdge *e); +void BM_edge_normals_update(BMEdge *e) ATTR_NONNULL(); -void BM_vert_normal_update(BMVert *v); -void BM_vert_normal_update_all(BMVert *v); +void BM_vert_normal_update(BMVert *v) ATTR_NONNULL(); +void BM_vert_normal_update_all(BMVert *v) ATTR_NONNULL(); -void BM_face_normal_flip(BMesh *bm, BMFace *f); -bool BM_face_point_inside_test(BMFace *f, const float co[3]); +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 **newfaces, - const bool use_beauty, const bool use_tag); + const bool use_beauty, const bool use_tag) ATTR_NONNULL(1, 2); + +void BM_face_legal_splits(BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL(); -void BM_face_legal_splits(BMFace *f, BMLoop *(*loops)[2], int len); +void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3]) ATTR_NONNULL(); +void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]) ATTR_NONNULL(); -void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3]); -void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]); +void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3]) ATTR_NONNULL(); +void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4]) ATTR_NONNULL(); #endif /* __BMESH_POLYGON_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 6eab3c625fa..9b4f34d18f2 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -35,6 +35,7 @@ #include "BLI_math.h" #include "BLI_alloca.h" +#include "BLI_linklist.h" #include "bmesh.h" #include "intern/bmesh_private.h" @@ -991,6 +992,25 @@ BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2) } /** + * \brief Return the Loop Shared by Edge and Vert + * + * Finds the loop used which uses \a in face loop \a l + * + * \note this function takes a loop rather then an edge + * so we can select the face that the loop should be from. + */ +BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v) +{ + BLI_assert(BM_vert_in_edge(l->e, v)); + if (l->v == v) { + return l; + } + else { + return l->next; + } +} + +/** * \brief Return the Loop Shared by Face and Vertex * * Finds the loop used which uses \a v in face loop \a l @@ -1453,8 +1473,7 @@ BMEdge *BM_edge_find_double(BMEdge *e) * there is a face with exactly those vertices * (and only those vertices). * - * \note there used to be a BM_face_exists_overlap function that checked for partial overlap, - * however this is no longer used, simple to add back. + * \note there used to be a BM_face_exists_overlap function that checks for partial overlap. */ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) { @@ -1684,6 +1703,140 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len) return ok; } + +/** + * Given a set of vertices (varr), find out if + * all those vertices overlap an existing face. + * + * \note The face may contain other verts \b not in \a varr. + * + * \note Its possible there are more then one overlapping faces, + * in this case the first one found will be assigned to \a r_f_overlap. + * + * \param varr Array of unordered verts. + * \param len \a varr array length. + * \param r_f_overlap The overlapping face to return. + * \return Success + */ + +bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) +{ + BMIter viter; + BMFace *f; + int i; + bool is_overlap = false; + LinkNode *f_lnk = NULL; + + if (r_f_overlap) { + *r_f_overlap = NULL; + } + +#ifdef DEBUG + /* check flag isn't already set */ + for (i = 0; i < len; i++) { + BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) { + BLI_assert(BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0); + } + } +#endif + + 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 (r_f_overlap) + *r_f_overlap = f; + + is_overlap = true; + break; + } + + BM_ELEM_API_FLAG_ENABLE(f, _FLAG_OVERLAP); + BLI_linklist_prepend_alloca(&f_lnk, f); + } + } + } + + for (; f_lnk; f_lnk = f_lnk->next) { + BM_ELEM_API_FLAG_DISABLE((BMFace *)f_lnk->link, _FLAG_OVERLAP); + } + + return is_overlap; +} + +/** + * Given a set of vertices (varr), find out if + * there is a face that uses vertices only from this list + * (that the face is a subset or made from the vertices given). + * + * \param varr Array of unordered verts. + * \param len varr array length. + */ +bool BM_face_exists_overlap_subset(BMVert **varr, const int len) +{ + BMIter viter; + BMFace *f; + int i; + bool is_init = false; + bool is_overlap = false; + LinkNode *f_lnk = NULL; + +#ifdef DEBUG + /* check flag isn't already set */ + for (i = 0; i < len; i++) { + BLI_assert(BM_ELEM_API_FLAG_TEST(varr[i], _FLAG_OVERLAP) == 0); + BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) { + BLI_assert(BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0); + } + } +#endif + + for (i = 0; i < len; i++) { + BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) { + if ((f->len <= len) && (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0)) { + /* check if all vers in this face are flagged*/ + BMLoop *l_iter, *l_first; + + if (is_init == false) { + is_init = true; + for (i = 0; i < len; i++) { + BM_ELEM_API_FLAG_ENABLE(varr[i], _FLAG_OVERLAP); + } + } + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + is_overlap = true; + do { + if (BM_ELEM_API_FLAG_TEST(l_iter->v, _FLAG_OVERLAP) == 0) { + is_overlap = false; + break; + } + } while ((l_iter = l_iter->next) != l_first); + + if (is_overlap) { + break; + } + + BM_ELEM_API_FLAG_ENABLE(f, _FLAG_OVERLAP); + BLI_linklist_prepend_alloca(&f_lnk, f); + } + } + } + + if (is_init == true) { + for (i = 0; i < len; i++) { + BM_ELEM_API_FLAG_DISABLE(varr[i], _FLAG_OVERLAP); + } + } + + for (; f_lnk; f_lnk = f_lnk->next) { + BM_ELEM_API_FLAG_DISABLE((BMFace *)f_lnk->link, _FLAG_OVERLAP); + } + + return is_overlap; +} + + /* convenience functions for checking flags */ bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag) { diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 2c931de995e..a057d120be1 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -27,8 +27,6 @@ * \ingroup bmesh */ -typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data); - bool BM_vert_in_face(BMFace *f, BMVert *v); int BM_verts_in_face_count(BMFace *f, BMVert **varr, int len); bool BM_verts_in_face(BMFace *f, BMVert **varr, int len); @@ -95,6 +93,9 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface); bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len); bool BM_face_exists_multi_edge(BMEdge **earr, int len); +bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap); +bool BM_face_exists_overlap_subset(BMVert **varr, const int len); + int BM_face_share_face_count(BMFace *f_a, BMFace *f_b); int BM_face_share_edge_count(BMFace *f1, BMFace *f2); @@ -105,6 +106,7 @@ bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2); bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2); BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2); +BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v); BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v); BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e); diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c index 80b85ab6edd..af901b3359c 100644 --- a/source/blender/bmesh/intern/bmesh_walkers.c +++ b/source/blender/bmesh/intern/bmesh_walkers.c @@ -87,8 +87,8 @@ void BMW_init(BMWalker *walker, BMesh *bm, int type, walker->mask_edge = mask_edge; walker->mask_face = mask_face; - walker->visithash = BLI_ghash_ptr_new("bmesh walkers 1"); - walker->secvisithash = BLI_ghash_ptr_new("bmesh walkers sec 1"); + walker->visit_set = BLI_gset_ptr_new("bmesh walkers"); + walker->visit_set_alt = BLI_gset_ptr_new("bmesh walkers sec"); if (UNLIKELY(type >= BMW_MAXWALKERS || type < 0)) { fprintf(stderr, @@ -127,8 +127,8 @@ void BMW_init(BMWalker *walker, BMesh *bm, int type, void BMW_end(BMWalker *walker) { BLI_mempool_destroy(walker->worklist); - BLI_ghash_free(walker->visithash, NULL, NULL); - BLI_ghash_free(walker->secvisithash, NULL, NULL); + BLI_gset_free(walker->visit_set, NULL); + BLI_gset_free(walker->visit_set_alt, NULL); } @@ -253,8 +253,6 @@ void BMW_reset(BMWalker *walker) BMW_state_remove(walker); } walker->depth = 0; - BLI_ghash_free(walker->visithash, NULL, NULL); - BLI_ghash_free(walker->secvisithash, NULL, NULL); - walker->visithash = BLI_ghash_ptr_new("bmesh walkers 1"); - walker->secvisithash = BLI_ghash_ptr_new("bmesh walkers sec 1"); + BLI_gset_clear(walker->visit_set, NULL); + BLI_gset_clear(walker->visit_set_alt, NULL); } diff --git a/source/blender/bmesh/intern/bmesh_walkers.h b/source/blender/bmesh/intern/bmesh_walkers.h index 8be362b5afa..ea1dbc61cc6 100644 --- a/source/blender/bmesh/intern/bmesh_walkers.h +++ b/source/blender/bmesh/intern/bmesh_walkers.h @@ -67,8 +67,8 @@ typedef struct BMWalker { BMWFlag flag; - GHash *visithash; - GHash *secvisithash; + GSet *visit_set; + GSet *visit_set_alt; int depth; } BMWalker; diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c index 6a8ce32991e..238b7b4aaaa 100644 --- a/source/blender/bmesh/intern/bmesh_walkers_impl.c +++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c @@ -26,6 +26,8 @@ * BMesh Walker Code. */ +#include <string.h> + #include "BLI_utildefines.h" #include "BKE_customdata.h" @@ -34,6 +36,12 @@ #include "intern/bmesh_private.h" #include "intern/bmesh_walkers_private.h" +/* pop into stack memory (common operation) */ +#define BMW_state_remove_r(walker, owalk) { \ + memcpy(owalk, BMW_current_state(walker), sizeof(*(owalk))); \ + BMW_state_remove(walker); \ +} (void)0 + static bool bmw_mask_check_vert(BMWalker *walker, BMVert *v) { if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { @@ -85,7 +93,7 @@ static void bmw_ShellWalker_visitEdge(BMWalker *walker, BMEdge *e) { BMwShellWalker *shellWalk = NULL; - if (BLI_ghash_haskey(walker->visithash, e)) { + if (BLI_gset_haskey(walker->visit_set, e)) { return; } @@ -95,7 +103,7 @@ static void bmw_ShellWalker_visitEdge(BMWalker *walker, BMEdge *e) shellWalk = BMW_state_add(walker); shellWalk->curedge = e; - BLI_ghash_insert(walker->visithash, e, NULL); + BLI_gset_insert(walker->visit_set, e); } static void bmw_ShellWalker_begin(BMWalker *walker, void *data) @@ -140,14 +148,16 @@ static void *bmw_ShellWalker_yield(BMWalker *walker) static void *bmw_ShellWalker_step(BMWalker *walker) { - BMwShellWalker *swalk = BMW_current_state(walker); + BMwShellWalker *swalk, owalk; BMEdge *e, *e2; BMVert *v; BMIter iter; int i; + BMW_state_remove_r(walker, &owalk); + swalk = &owalk; + e = swalk->curedge; - BMW_state_remove(walker); for (i = 0; i < 2; i++) { v = i ? e->v2 : e->v1; @@ -167,8 +177,8 @@ static void *bmw_ShellWalker_step(BMWalker *walker) bool restrictpass = true; BMwShellWalker shellWalk = *((BMwShellWalker *)BMW_current_state(walker)); - if (!BLI_ghash_haskey(walker->visithash, shellWalk.base)) { - BLI_ghash_insert(walker->visithash, shellWalk.base, NULL); + if (!BLI_gset_haskey(walker->visit_set, shellWalk.base)) { + BLI_gset_insert(walker->visit_set, shellWalk.base); } BMW_state_remove(walker); @@ -177,7 +187,7 @@ static void *bmw_ShellWalker_step(BMWalker *walker) /* find the next edge whose other vertex has not been visite */ curedge = shellWalk.curedge; do { - if (!BLI_ghash_haskey(walker->visithash, curedge)) { + if (!BLI_gset_haskey(walker->visit_set, curedge)) { if (!walker->restrictflag || (walker->restrictflag && BMO_elem_flag_test(walker->bm, curedge, walker->restrictflag))) { @@ -187,7 +197,7 @@ static void *bmw_ShellWalker_step(BMWalker *walker) /* push a new state onto the stac */ newState = BMW_state_add(walker); - BLI_ghash_insert(walker->visithash, curedge, NULL); + BLI_gset_insert(walker->visit_set, curedge); /* populate the new stat */ @@ -211,7 +221,7 @@ static void bmw_ConnectedVertexWalker_visitVertex(BMWalker *walker, BMVert *v) { BMwConnectedVertexWalker *vwalk; - if (BLI_ghash_haskey(walker->visithash, v)) { + if (BLI_gset_haskey(walker->visit_set, v)) { /* already visited */ return; } @@ -223,7 +233,7 @@ static void bmw_ConnectedVertexWalker_visitVertex(BMWalker *walker, BMVert *v) vwalk = BMW_state_add(walker); vwalk->curvert = v; - BLI_ghash_insert(walker->visithash, v, NULL); + BLI_gset_insert(walker->visit_set, v); } static void bmw_ConnectedVertexWalker_begin(BMWalker *walker, void *data) @@ -240,18 +250,19 @@ static void *bmw_ConnectedVertexWalker_yield(BMWalker *walker) static void *bmw_ConnectedVertexWalker_step(BMWalker *walker) { - BMwConnectedVertexWalker *vwalk = BMW_current_state(walker); + BMwConnectedVertexWalker *vwalk, owalk; BMVert *v, *v2; BMEdge *e; BMIter iter; - v = vwalk->curvert; + BMW_state_remove_r(walker, &owalk); + vwalk = &owalk; - BMW_state_remove(walker); + v = vwalk->curvert; BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { v2 = BM_edge_other_vert(e, v); - if (!BLI_ghash_haskey(walker->visithash, v2)) { + if (!BLI_gset_haskey(walker->visit_set, v2)) { bmw_ConnectedVertexWalker_visitVertex(walker, v2); } } @@ -276,7 +287,7 @@ static void bmw_IslandboundWalker_begin(BMWalker *walker, void *data) iwalk->base = iwalk->curloop = l; iwalk->lastv = l->v; - BLI_ghash_insert(walker->visithash, data, NULL); + BLI_gset_insert(walker->visit_set, data); } @@ -289,14 +300,19 @@ static void *bmw_IslandboundWalker_yield(BMWalker *walker) static void *bmw_IslandboundWalker_step(BMWalker *walker) { - BMwIslandboundWalker *iwalk = BMW_current_state(walker), owalk; + BMwIslandboundWalker *iwalk, owalk; BMVert *v; - BMEdge *e = iwalk->curloop->e; + BMEdge *e; BMFace *f; - BMLoop *l = iwalk->curloop; + BMLoop *l; /* int found = 0; */ - owalk = *iwalk; + memcpy(&owalk, BMW_current_state(walker), sizeof(owalk)); + /* normally we'd remove here, but delay until after error checking */ + iwalk = &owalk; + + l = iwalk->curloop; + e = l->e; v = BM_edge_other_vert(e, iwalk->lastv); @@ -307,7 +323,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker) return NULL; } - /* pop off current stat */ + /* pop off current state */ BMW_state_remove(walker); f = l->f; @@ -334,11 +350,11 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker) if (l == owalk.curloop) { return NULL; } - else if (BLI_ghash_haskey(walker->visithash, l)) { + else if (BLI_gset_haskey(walker->visit_set, l)) { return owalk.curloop; } - BLI_ghash_insert(walker->visithash, l, NULL); + BLI_gset_insert(walker->visit_set, l); iwalk = BMW_state_add(walker); iwalk->base = owalk.base; @@ -367,7 +383,7 @@ static void bmw_IslandWalker_begin(BMWalker *walker, void *data) } iwalk = BMW_state_add(walker); - BLI_ghash_insert(walker->visithash, data, NULL); + BLI_gset_insert(walker->visit_set, data); iwalk->cur = data; } @@ -381,13 +397,13 @@ static void *bmw_IslandWalker_yield(BMWalker *walker) static void *bmw_IslandWalker_step(BMWalker *walker) { - BMwIslandWalker *iwalk = BMW_current_state(walker); - /* BMwIslandWalker *owalk = iwalk; */ /* UNUSED */ + BMwIslandWalker *iwalk, owalk; BMIter iter, liter; - BMFace *f, *curf = iwalk->cur; + BMFace *f; BMLoop *l; - BMW_state_remove(walker); + BMW_state_remove_r(walker, &owalk); + iwalk = &owalk; l = BM_iter_new(&liter, walker->bm, BM_LOOPS_OF_FACE, iwalk->cur); for ( ; l; l = BM_iter_step(&liter)) { @@ -403,23 +419,23 @@ static void *bmw_IslandWalker_step(BMWalker *walker) continue; } - /* saves checking BLI_ghash_haskey below (manifold edges theres a 50% chance) */ + /* saves checking BLI_gset_haskey below (manifold edges theres a 50% chance) */ if (f == iwalk->cur) { continue; } - if (BLI_ghash_haskey(walker->visithash, f)) { + if (BLI_gset_haskey(walker->visit_set, f)) { continue; } iwalk = BMW_state_add(walker); iwalk->cur = f; - BLI_ghash_insert(walker->visithash, f, NULL); + BLI_gset_insert(walker->visit_set, f); break; } } - return curf; + return owalk.cur; } @@ -448,7 +464,7 @@ static void bmw_LoopWalker_begin(BMWalker *walker, void *data) v = e->v1; lwalk = BMW_state_add(walker); - BLI_ghash_insert(walker->visithash, e, NULL); + BLI_gset_insert(walker->visit_set, e); lwalk->cur = lwalk->start = e; lwalk->lastv = lwalk->startv = v; @@ -494,9 +510,8 @@ static void bmw_LoopWalker_begin(BMWalker *walker, void *data) lwalk->lastv = lwalk->startv = BM_edge_other_vert(owalk.cur, lwalk->lastv); - BLI_ghash_free(walker->visithash, NULL, NULL); - walker->visithash = BLI_ghash_ptr_new("bmesh walkers 2"); - BLI_ghash_insert(walker->visithash, owalk.cur, NULL); + BLI_gset_clear(walker->visit_set, NULL); + BLI_gset_insert(walker->visit_set, owalk.cur); } static void *bmw_LoopWalker_yield(BMWalker *walker) @@ -508,15 +523,16 @@ static void *bmw_LoopWalker_yield(BMWalker *walker) static void *bmw_LoopWalker_step(BMWalker *walker) { - BMwLoopWalker *lwalk = BMW_current_state(walker), owalk; - BMEdge *e = lwalk->cur, *nexte = NULL; + BMwLoopWalker *lwalk, owalk; + BMEdge *e, *nexte = NULL; BMLoop *l; BMVert *v; int i = 0; - owalk = *lwalk; - BMW_state_remove(walker); + BMW_state_remove_r(walker, &owalk); + lwalk = &owalk; + e = lwalk->cur; l = e->l; if (owalk.f_hub) { /* NGON EDGE */ @@ -531,7 +547,7 @@ static void *bmw_LoopWalker_step(BMWalker *walker) nexte = BM_edge_exists(v, l->v); if (bmw_mask_check_edge(walker, nexte) && - !BLI_ghash_haskey(walker->visithash, nexte) && + !BLI_gset_haskey(walker->visit_set, nexte) && /* never step onto a boundary edge, this gives odd-results */ (BM_edge_is_boundary(nexte) == false)) { @@ -543,7 +559,7 @@ static void *bmw_LoopWalker_step(BMWalker *walker) lwalk->is_single = owalk.is_single; lwalk->f_hub = owalk.f_hub; - BLI_ghash_insert(walker->visithash, nexte, NULL); + BLI_gset_insert(walker->visit_set, nexte); } } } @@ -557,7 +573,7 @@ static void *bmw_LoopWalker_step(BMWalker *walker) BM_ITER_ELEM (nexte, &eiter, v, BM_EDGES_OF_VERT) { if ((nexte->l == NULL) && bmw_mask_check_edge(walker, nexte) && - !BLI_ghash_haskey(walker->visithash, nexte)) + !BLI_gset_haskey(walker->visit_set, nexte)) { lwalk = BMW_state_add(walker); lwalk->cur = nexte; @@ -567,7 +583,7 @@ static void *bmw_LoopWalker_step(BMWalker *walker) lwalk->is_single = owalk.is_single; lwalk->f_hub = owalk.f_hub; - BLI_ghash_insert(walker->visithash, nexte, NULL); + BLI_gset_insert(walker->visit_set, nexte); } } } @@ -602,7 +618,7 @@ static void *bmw_LoopWalker_step(BMWalker *walker) if (l != NULL) { if (l != e->l && bmw_mask_check_edge(walker, l->e) && - !BLI_ghash_haskey(walker->visithash, l->e)) + !BLI_gset_haskey(walker->visit_set, l->e)) { lwalk = BMW_state_add(walker); lwalk->cur = l->e; @@ -612,7 +628,7 @@ static void *bmw_LoopWalker_step(BMWalker *walker) lwalk->is_single = owalk.is_single; lwalk->f_hub = owalk.f_hub; - BLI_ghash_insert(walker->visithash, l->e, NULL); + BLI_gset_insert(walker->visit_set, l->e); } } } @@ -655,7 +671,7 @@ static void *bmw_LoopWalker_step(BMWalker *walker) if (l != NULL) { if (l != e->l && bmw_mask_check_edge(walker, l->e) && - !BLI_ghash_haskey(walker->visithash, l->e)) + !BLI_gset_haskey(walker->visit_set, l->e)) { lwalk = BMW_state_add(walker); lwalk->cur = l->e; @@ -665,7 +681,7 @@ static void *bmw_LoopWalker_step(BMWalker *walker) lwalk->is_single = owalk.is_single; lwalk->f_hub = owalk.f_hub; - BLI_ghash_insert(walker->visithash, l->e, NULL); + BLI_gset_insert(walker->visit_set, l->e); } } } @@ -694,8 +710,8 @@ static bool bmw_FaceLoopWalker_include_face(BMWalker *walker, BMLoop *l) return false; } - /* the face must not have been already visite */ - if (BLI_ghash_haskey(walker->visithash, l->f) && BLI_ghash_haskey(walker->secvisithash, l->e)) { + /* the face must not have been already visited */ + if (BLI_gset_haskey(walker->visit_set, l->f) && BLI_gset_haskey(walker->visit_set_alt, l->e)) { return false; } @@ -739,9 +755,9 @@ static void bmw_FaceLoopWalker_begin(BMWalker *walker, void *data) lwalk = BMW_state_add(walker); lwalk->l = e->l; lwalk->no_calc = false; - BLI_ghash_insert(walker->visithash, lwalk->l->f, NULL); + BLI_gset_insert(walker->visit_set, lwalk->l->f); - /* rewin */ + /* rewind */ while ((owalk_pt = BMW_current_state(walker))) { owalk = *((BMwFaceLoopWalker *)owalk_pt); BMW_walk(walker); @@ -751,13 +767,11 @@ static void bmw_FaceLoopWalker_begin(BMWalker *walker, void *data) *lwalk = owalk; lwalk->no_calc = false; - BLI_ghash_free(walker->secvisithash, NULL, NULL); - walker->secvisithash = BLI_ghash_ptr_new("bmesh walkers 3"); - BLI_ghash_insert(walker->visithash, lwalk->l->e, NULL); + BLI_gset_clear(walker->visit_set_alt, NULL); + BLI_gset_insert(walker->visit_set_alt, lwalk->l->e); - BLI_ghash_free(walker->visithash, NULL, NULL); - walker->visithash = BLI_ghash_ptr_new("bmesh walkers 3"); - BLI_ghash_insert(walker->visithash, lwalk->l->f, NULL); + BLI_gset_clear(walker->visit_set, NULL); + BLI_gset_insert(walker->visit_set, lwalk->l->f); } static void *bmw_FaceLoopWalker_yield(BMWalker *walker) @@ -773,13 +787,15 @@ static void *bmw_FaceLoopWalker_yield(BMWalker *walker) static void *bmw_FaceLoopWalker_step(BMWalker *walker) { - BMwFaceLoopWalker *lwalk = BMW_current_state(walker); - BMFace *f = lwalk->l->f; - BMLoop *l = lwalk->l, *origl = lwalk->l; + BMwFaceLoopWalker *lwalk, owalk; + BMFace *f; + BMLoop *l; - BMW_state_remove(walker); + BMW_state_remove_r(walker, &owalk); + lwalk = &owalk; - l = l->radial_next; + f = lwalk->l->f; + l = lwalk->l->radial_next; if (lwalk->no_calc) { return f; @@ -800,14 +816,15 @@ static void *bmw_FaceLoopWalker_step(BMWalker *walker) if (l->f->len != 4) { lwalk->no_calc = true; - lwalk->l = origl; + lwalk->l = owalk.l; } else { lwalk->no_calc = false; } - BLI_ghash_insert(walker->secvisithash, l->e, NULL); - BLI_ghash_insert(walker->visithash, l->f, NULL); + /* both may already exist */ + BLI_gset_reinsert(walker->visit_set_alt, l->e, NULL); + BLI_gset_reinsert(walker->visit_set, l->f, NULL); } return f; @@ -838,7 +855,7 @@ static void bmw_EdgeringWalker_begin(BMWalker *walker, void *data) lwalk->wireedge = NULL; } - BLI_ghash_insert(walker->visithash, lwalk->l->e, NULL); + BLI_gset_insert(walker->visit_set, lwalk->l->e); /* rewind */ while ((owalk_pt = BMW_current_state(walker))) { @@ -858,9 +875,8 @@ static void bmw_EdgeringWalker_begin(BMWalker *walker, void *data) lwalk->l = lwalk->l->radial_next; } - BLI_ghash_free(walker->visithash, NULL, NULL); - walker->visithash = BLI_ghash_ptr_new("bmesh walkers 4"); - BLI_ghash_insert(walker->visithash, lwalk->l->e, NULL); + BLI_gset_clear(walker->visit_set, NULL); + BLI_gset_insert(walker->visit_set, lwalk->l->e); } static void *bmw_EdgeringWalker_yield(BMWalker *walker) @@ -881,19 +897,21 @@ static void *bmw_EdgeringWalker_yield(BMWalker *walker) static void *bmw_EdgeringWalker_step(BMWalker *walker) { - BMwEdgeringWalker *lwalk = BMW_current_state(walker); - BMEdge *e, *wireedge = lwalk->wireedge; - BMLoop *l = lwalk->l, *origl = lwalk->l; + BMwEdgeringWalker *lwalk, owalk; + BMEdge *e; + BMLoop *l; #ifdef BMW_EDGERING_NGON int i, len; #endif #define EDGE_CHECK(e) (bmw_mask_check_edge(walker, e) && (BM_edge_is_boundary(e) || BM_edge_is_manifold(e))) - BMW_state_remove(walker); + BMW_state_remove_r(walker, &owalk); + lwalk = &owalk; + l = lwalk->l; if (!l) - return wireedge; + return lwalk->wireedge; e = l->e; if (!EDGE_CHECK(e)) { @@ -916,7 +934,7 @@ static void *bmw_EdgeringWalker_step(BMWalker *walker) if ((len <= 0) || (len % 2 != 0) || !EDGE_CHECK(l->e) || !bmw_mask_check_face(walker, l->f)) { - l = origl; + l = owalk.l; i = len; while (i > 0) { l = l->next; @@ -925,7 +943,7 @@ static void *bmw_EdgeringWalker_step(BMWalker *walker) } /* only walk to manifold edge */ if ((l->f->len % 2 == 0) && EDGE_CHECK(l->e) && - !BLI_ghash_haskey(walker->visithash, l->e)) + !BLI_gset_haskey(walker->visit_set, l->e)) #else @@ -933,18 +951,18 @@ static void *bmw_EdgeringWalker_step(BMWalker *walker) l = l->next->next; if ((l->f->len != 4) || !EDGE_CHECK(l->e) || !bmw_mask_check_face(walker, l->f)) { - l = origl->next->next; + l = owalk.l->next->next; } /* only walk to manifold edge */ if ((l->f->len == 4) && EDGE_CHECK(l->e) && - !BLI_ghash_haskey(walker->visithash, l->e)) + !BLI_gset_haskey(walker->visit_set, l->e)) #endif { lwalk = BMW_state_add(walker); lwalk->l = l; lwalk->wireedge = NULL; - BLI_ghash_insert(walker->visithash, l->e, NULL); + BLI_gset_insert(walker->visit_set, l->e); } return e; @@ -957,12 +975,12 @@ static void bmw_UVEdgeWalker_begin(BMWalker *walker, void *data) BMwUVEdgeWalker *lwalk; BMLoop *l = data; - if (BLI_ghash_haskey(walker->visithash, l)) + if (BLI_gset_haskey(walker->visit_set, l)) return; lwalk = BMW_state_add(walker); lwalk->l = l; - BLI_ghash_insert(walker->visithash, l, NULL); + BLI_gset_insert(walker->visit_set, l); } static void *bmw_UVEdgeWalker_yield(BMWalker *walker) @@ -978,17 +996,18 @@ static void *bmw_UVEdgeWalker_yield(BMWalker *walker) static void *bmw_UVEdgeWalker_step(BMWalker *walker) { - BMwUVEdgeWalker *lwalk = BMW_current_state(walker); + const int type = walker->bm->ldata.layers[walker->layer].type; + BMwUVEdgeWalker *lwalk, owalk; BMLoop *l, *l2, *l3, *nl, *cl; BMIter liter; void *d1, *d2; - int i, j, rlen, type; + int i, j, rlen; + + BMW_state_remove_r(walker, &owalk); + lwalk = &owalk; l = lwalk->l; nl = l->next; - type = walker->bm->ldata.layers[walker->layer].type; - - BMW_state_remove(walker); if (!bmw_mask_check_edge(walker, l->e)) { return l; @@ -1004,7 +1023,7 @@ static void *bmw_UVEdgeWalker_step(BMWalker *walker) rlen = BM_edge_face_count(l2->e); for (j = 0; j < rlen; j++) { - if (BLI_ghash_haskey(walker->visithash, l2)) { + if (BLI_gset_haskey(walker->visit_set, l2)) { continue; } @@ -1022,7 +1041,7 @@ static void *bmw_UVEdgeWalker_step(BMWalker *walker) continue; lwalk = BMW_state_add(walker); - BLI_ghash_insert(walker->visithash, l2, NULL); + BLI_gset_insert(walker->visit_set, l2); lwalk->l = l2; diff --git a/source/blender/bmesh/operators/bmo_beautify.c b/source/blender/bmesh/operators/bmo_beautify.c index 22b686db64e..bd20e384234 100644 --- a/source/blender/bmesh/operators/bmo_beautify.c +++ b/source/blender/bmesh/operators/bmo_beautify.c @@ -28,7 +28,7 @@ * * In principle this is very simple however there is the possibility of * going into an eternal loop where edges keep rotating. - * To avoid this - each edge stores a hash of it previous + * To avoid this - each edge stores a set of it previous * states so as not to rotate back. * * TODO @@ -43,10 +43,13 @@ #include "bmesh.h" #include "intern/bmesh_operators_private.h" +#include "BLI_strict_flags.h" + // #define DEBUG_TIME #ifdef DEBUG_TIME # include "PIL_time.h" +# include "PIL_time_utildefines.h" #endif enum { @@ -54,14 +57,14 @@ enum { }; /* -------------------------------------------------------------------- */ -/* GHash for edge rotation */ +/* GSet for edge rotation */ typedef struct EdRotState { int v1, v2; /* edge vert, small -> large */ int f1, f2; /* face vert, small -> large */ } EdRotState; -static unsigned int erot_ghashutil_hash(const void *ptr) +static unsigned int erot_gsetutil_hash(const void *ptr) { const EdRotState *e_state = (const EdRotState *)ptr; unsigned int @@ -71,7 +74,7 @@ static unsigned int erot_ghashutil_hash(const void *ptr) hash ^= BLI_ghashutil_inthash(SET_INT_IN_POINTER(e_state->f2)); return hash; } -static int erot_ghashutil_cmp(const void *a, const void *b) +static int erot_gsetutil_cmp(const void *a, const void *b) { const EdRotState *e_state_a = (const EdRotState *)a; const EdRotState *e_state_b = (const EdRotState *)b; @@ -86,9 +89,9 @@ static int erot_ghashutil_cmp(const void *a, const void *b) else return 0; } -static GHash *erot_ghash_new(void) +static GSet *erot_gset_new(void) { - return BLI_ghash_new(erot_ghashutil_hash, erot_ghashutil_cmp, __func__); + return BLI_gset_new(erot_gsetutil_hash, erot_gsetutil_cmp, __func__); } /* ensure v0 is smaller */ @@ -133,7 +136,8 @@ static void erot_state_alternate(const BMEdge *e, EdRotState *e_state) /** * \return a negative value means the edge can be rotated. */ -static float bm_edge_calc_rotate_beauty(const BMEdge *e, const int flag) +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 { @@ -141,28 +145,10 @@ static float bm_edge_calc_rotate_beauty(const BMEdge *e, const int flag) /* first get the 2d values */ { - const float *v1, *v2, *v3, *v4; bool is_zero_a, is_zero_b; float no[3]; float axis_mat[3][3]; - v1 = e->l->prev->v->co; /* first face co */ - v2 = e->l->v->co; /* e->v1 or e->v2*/ - v3 = e->l->radial_next->prev->v->co; /* second face co */ - v4 = e->l->next->v->co; /* e->v1 or e->v2*/ - - if (flag & VERT_RESTRICT_TAG) { - BMVert *v_a = e->l->prev->v, *v_b = e->l->radial_next->prev->v; - if (BM_elem_flag_test(v_a, BM_ELEM_TAG) == BM_elem_flag_test(v_b, BM_ELEM_TAG)) { - break; - } - } - - if (UNLIKELY(v1 == v3)) { - // printf("This should never happen, but does sometimes!\n"); - break; - } - // printf("%p %p %p %p - %p %p\n", v1, v2, v3, v4, e->l->f, e->l->radial_next->f); BLI_assert((ELEM3(v1, v2, v3, v4) == false) && (ELEM3(v2, v1, v3, v4) == false) && @@ -204,28 +190,101 @@ static float bm_edge_calc_rotate_beauty(const BMEdge *e, const int flag) // printf("%p %p %p %p - %p %p\n", v1, v2, v3, v4, e->l->f, e->l->radial_next->f); if (is_quad_convex_v2(v1_xy, v2_xy, v3_xy, v4_xy)) { - float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2; - /* testing rule: - * the area divided by the total edge lengths - */ - len1 = len_v2v2(v1_xy, v2_xy); - len2 = len_v2v2(v2_xy, v3_xy); - len3 = len_v2v2(v3_xy, v4_xy); - len4 = len_v2v2(v4_xy, v1_xy); - len5 = len_v2v2(v1_xy, v3_xy); - len6 = len_v2v2(v2_xy, v4_xy); - - opp1 = area_tri_v2(v1_xy, v2_xy, v3_xy); - opp2 = area_tri_v2(v1_xy, v3_xy, v4_xy); - - fac1 = opp1 / (len1 + len2 + len5) + opp2 / (len3 + len4 + len5); - - opp1 = area_tri_v2(v2_xy, v3_xy, v4_xy); - opp2 = area_tri_v2(v2_xy, v4_xy, v1_xy); - - fac2 = opp1 / (len2 + len3 + len6) + opp2 / (len4 + len1 + len6); - /* negative number if we're OK */ - return fac2 - fac1; + /* 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; + } + } while (false); + + return FLT_MAX; +} + +static float bm_edge_calc_rotate_beauty__angle( + 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 no_a[3], no_b[3]; + float angle_24, angle_13; + + /* edge (2-4), current state */ + normal_tri_v3(no_a, v2, v3, v4); + normal_tri_v3(no_b, v2, v4, v1); + angle_24 = angle_normalized_v3v3(no_a, no_b); + + /* edge (1-3), new state */ + /* only check new state for degenerate outcome */ + if ((normal_tri_v3(no_a, v1, v2, v3) == 0.0f) || + (normal_tri_v3(no_b, v1, v3, v4) == 0.0f)) + { + break; + } + angle_13 = angle_normalized_v3v3(no_a, no_b); + + return angle_13 - angle_24; + } while (false); + + return FLT_MAX; +} + +static float bm_edge_calc_rotate_beauty(const BMEdge *e, const short flag, const short method) +{ + /* not a loop (only to be able to break out) */ + do { + const float *v1, *v2, *v3, *v4; + + v1 = e->l->prev->v->co; /* first face co */ + v2 = e->l->v->co; /* e->v1 or e->v2*/ + v3 = e->l->radial_next->prev->v->co; /* second face co */ + v4 = e->l->next->v->co; /* e->v1 or e->v2*/ + + if (flag & VERT_RESTRICT_TAG) { + BMVert *v_a = e->l->prev->v, *v_b = e->l->radial_next->prev->v; + if (BM_elem_flag_test(v_a, BM_ELEM_TAG) == BM_elem_flag_test(v_b, BM_ELEM_TAG)) { + break; + } + } + + if (UNLIKELY(v1 == v3)) { + // printf("This should never happen, but does sometimes!\n"); + break; + } + + switch (method) { + case 0: + return bm_edge_calc_rotate_beauty__area(v1, v2, v3, v4); + default: + return bm_edge_calc_rotate_beauty__angle(v1, v2, v3, v4); } } while (false); @@ -236,12 +295,12 @@ static float bm_edge_calc_rotate_beauty(const BMEdge *e, const int flag) /* Update the edge cost of rotation in the heap */ /* recalc an edge in the heap (surrounding geometry has changed) */ -static void bm_edge_update_beauty_cost_single(BMEdge *e, Heap *eheap, HeapNode **eheap_table, GHash **edge_state_arr, - const int flag) +static void bm_edge_update_beauty_cost_single(BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr, + const short flag, const short method) { if (BM_elem_flag_test(e, BM_ELEM_TAG)) { const int i = BM_elem_index_get(e); - GHash *e_state_hash = edge_state_arr[i]; + GSet *e_state_set = edge_state_arr[i]; if (eheap_table[i]) { BLI_heap_remove(eheap, eheap_table[i]); @@ -254,10 +313,10 @@ static void bm_edge_update_beauty_cost_single(BMEdge *e, Heap *eheap, HeapNode * // BMO_elem_flag_test(bm, e->l->radial_next->f, FACE_MARK)); /* check we're not moving back into a state we have been in before */ - if (e_state_hash != NULL) { + if (e_state_set != NULL) { EdRotState e_state_alt; erot_state_alternate(e, &e_state_alt); - if (BLI_ghash_haskey(e_state_hash, (void *)&e_state_alt)) { + if (BLI_gset_haskey(e_state_set, (void *)&e_state_alt)) { // printf(" skipping, we already have this state\n"); return; } @@ -265,7 +324,7 @@ static void bm_edge_update_beauty_cost_single(BMEdge *e, Heap *eheap, HeapNode * { /* recalculate edge */ - const float cost = bm_edge_calc_rotate_beauty(e, flag); + const float cost = bm_edge_calc_rotate_beauty(e, flag, method); if (cost < 0.0f) { eheap_table[i] = BLI_heap_insert(eheap, cost, e); } @@ -277,19 +336,19 @@ static void bm_edge_update_beauty_cost_single(BMEdge *e, Heap *eheap, HeapNode * } /* we have rotated an edge, tag other edges and clear this one */ -static void bm_edge_update_beauty_cost(BMEdge *e, Heap *eheap, HeapNode **eheap_table, GHash **edge_state_arr, - const int flag) +static void bm_edge_update_beauty_cost(BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr, + const short flag, const short method) { BMLoop *l; BLI_assert(e->l->f->len == 3 && e->l->radial_next->f->len == 3); l = e->l; - bm_edge_update_beauty_cost_single(l->next->e, eheap, eheap_table, edge_state_arr, flag); - bm_edge_update_beauty_cost_single(l->prev->e, eheap, eheap_table, edge_state_arr, flag); + bm_edge_update_beauty_cost_single(l->next->e, eheap, eheap_table, edge_state_arr, flag, method); + bm_edge_update_beauty_cost_single(l->prev->e, eheap, eheap_table, edge_state_arr, flag, method); l = l->radial_next; - bm_edge_update_beauty_cost_single(l->next->e, eheap, eheap_table, edge_state_arr, flag); - bm_edge_update_beauty_cost_single(l->prev->e, eheap, eheap_table, edge_state_arr, flag); + bm_edge_update_beauty_cost_single(l->next->e, eheap, eheap_table, edge_state_arr, flag, method); + bm_edge_update_beauty_cost_single(l->prev->e, eheap, eheap_table, edge_state_arr, flag, method); } /* -------------------------------------------------------------------- */ @@ -303,12 +362,12 @@ static void bm_edge_update_beauty_cost(BMEdge *e, Heap *eheap, HeapNode **eheap_ * have their index values set according to their position in the array. */ static void bm_mesh_beautify_fill(BMesh *bm, BMEdge **edge_array, const int edge_array_len, - const int flag) + const short flag, const short method) { Heap *eheap; /* edge heap */ HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */ - GHash **edge_state_arr = MEM_callocN(edge_array_len * sizeof(GHash *), __func__); + GSet **edge_state_arr = MEM_callocN((size_t)edge_array_len * sizeof(GSet *), __func__); BLI_mempool *edge_state_pool = BLI_mempool_create(sizeof(EdRotState), 512, 512, BLI_MEMPOOL_SYSMALLOC); int i; @@ -316,13 +375,13 @@ static void bm_mesh_beautify_fill(BMesh *bm, BMEdge **edge_array, const int edge TIMEIT_START(beautify_fill); #endif - eheap = BLI_heap_new_ex(edge_array_len); - eheap_table = MEM_mallocN(sizeof(HeapNode *) * edge_array_len, __func__); + eheap = BLI_heap_new_ex((unsigned int)edge_array_len); + eheap_table = MEM_mallocN(sizeof(HeapNode *) * (size_t)edge_array_len, __func__); /* build heap */ for (i = 0; i < edge_array_len; i++) { BMEdge *e = edge_array[i]; - const float cost = bm_edge_calc_rotate_beauty(e, flag); + const float cost = bm_edge_calc_rotate_beauty(e, flag, method); if (cost < 0.0f) { eheap_table[i] = BLI_heap_insert(eheap, cost, e); } @@ -338,18 +397,18 @@ static void bm_mesh_beautify_fill(BMesh *bm, BMEdge **edge_array, const int edge e = BM_edge_rotate(bm, e, false, BM_EDGEROT_CHECK_EXISTS); if (LIKELY(e)) { - GHash *e_state_hash = edge_state_arr[i]; + GSet *e_state_set = edge_state_arr[i]; - /* add the new state into the hash so we don't move into this state again + /* add the new state into the set so we don't move into this state again * note: we could add the previous state too but this isn't essential) * for avoiding eternal loops */ EdRotState *e_state = BLI_mempool_alloc(edge_state_pool); erot_state_current(e, e_state); - if (UNLIKELY(e_state_hash == NULL)) { - edge_state_arr[i] = e_state_hash = erot_ghash_new(); /* store previous state */ + if (UNLIKELY(e_state_set == NULL)) { + edge_state_arr[i] = e_state_set = erot_gset_new(); /* store previous state */ } - BLI_assert(BLI_ghash_haskey(e_state_hash, (void *)e_state) == false); - BLI_ghash_insert(e_state_hash, e_state, NULL); + BLI_assert(BLI_gset_haskey(e_state_set, (void *)e_state) == false); + BLI_gset_insert(e_state_set, e_state); // printf(" %d -> %d, %d\n", i, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2)); @@ -359,7 +418,7 @@ static void bm_mesh_beautify_fill(BMesh *bm, BMEdge **edge_array, const int edge BM_elem_index_set(e, i); /* recalculate faces connected on the heap */ - bm_edge_update_beauty_cost(e, eheap, eheap_table, edge_state_arr, flag); + bm_edge_update_beauty_cost(e, eheap, eheap_table, edge_state_arr, flag, method); /* update flags */ BMO_elem_flag_enable(bm, e, ELE_NEW); @@ -373,7 +432,7 @@ static void bm_mesh_beautify_fill(BMesh *bm, BMEdge **edge_array, const int edge for (i = 0; i < edge_array_len; i++) { if (edge_state_arr[i]) { - BLI_ghash_free(edge_state_arr[i], NULL, NULL); + BLI_gset_free(edge_state_arr[i], NULL); } } @@ -393,11 +452,11 @@ void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op) BMFace *f; BMEdge *e; const bool use_restrict_tag = BMO_slot_bool_get(op->slots_in, "use_restrict_tag"); - const int flag = (use_restrict_tag ? VERT_RESTRICT_TAG : 0); + const short flag = (use_restrict_tag ? VERT_RESTRICT_TAG : 0); + const short method = (short)BMO_slot_int_get(op->slots_in, "method"); BMEdge **edge_array; int edge_array_len = 0; - BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { if (f->len == 3) { BMO_elem_flag_enable(bm, f, FACE_MARK); @@ -409,7 +468,7 @@ void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op) } /* will over alloc if some edges can't be rotated */ - edge_array = MEM_mallocN(sizeof(*edge_array) * BMO_slot_buffer_count(op->slots_in, "edges"), __func__); + edge_array = MEM_mallocN(sizeof(*edge_array) * (size_t)BMO_slot_buffer_count(op->slots_in, "edges"), __func__); BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { @@ -427,7 +486,7 @@ void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op) } bm->elem_index_dirty |= BM_EDGE; - bm_mesh_beautify_fill(bm, edge_array, edge_array_len, flag); + bm_mesh_beautify_fill(bm, edge_array, edge_array_len, flag, method); MEM_freeN(edge_array); diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index dc06b0b4f13..eef470e0d85 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -29,6 +29,7 @@ #include "BLI_utildefines.h" #include "bmesh.h" +#include "bmesh_tools.h" #include "intern/bmesh_operators_private.h" /* own include */ diff --git a/source/blender/bmesh/operators/bmo_bisect_plane.c b/source/blender/bmesh/operators/bmo_bisect_plane.c new file mode 100644 index 00000000000..74cb9d67e88 --- /dev/null +++ b/source/blender/bmesh/operators/bmo_bisect_plane.c @@ -0,0 +1,112 @@ +/* + * ***** 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. + * + * Contributor(s): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/operators/bmo_bisect_plane.c + * \ingroup bmesh + * + * Wrapper around #BM_mesh_bisect_plane + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "bmesh.h" +#include "bmesh_tools.h" + +#include "intern/bmesh_operators_private.h" /* own include */ + +#define ELE_NEW 1 +#define ELE_INPUT 2 + +void bmo_bisect_plane_exec(BMesh *bm, BMOperator *op) +{ + const float dist = BMO_slot_float_get(op->slots_in, "dist"); + const bool use_snap_center = BMO_slot_bool_get(op->slots_in, "use_snap_center"); + const bool clear_outer = BMO_slot_bool_get(op->slots_in, "clear_outer"); + const bool clear_inner = BMO_slot_bool_get(op->slots_in, "clear_inner"); + + float plane_co[3]; + float plane_no[3]; + float plane[4]; + + BMO_slot_vec_get(op->slots_in, "plane_co", plane_co); + BMO_slot_vec_get(op->slots_in, "plane_no", plane_no); + + if (is_zero_v3(plane_no)) { + BMO_error_raise(bm, op, BMERR_MESH_ERROR, "Zero normal given"); + return; + } + + plane_from_point_normal_v3(plane, plane_co, plane_no); + + /* tag geometry to bisect */ + BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "geom", BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + + BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_ALL_NOLOOP, ELE_INPUT); + + + BM_mesh_bisect_plane(bm, plane, use_snap_center, true, + ELE_NEW, dist); + + + if (clear_outer || clear_inner) { + /* Use an array of vertices because 'geom' contains both vers and edges that may use them. + * Removing a vert may remove and edge which is later checked by BMO_ITER. + * over-alloc the total possible vert count */ + const int vert_arr_max = min_ii(bm->totvert, BMO_slot_buffer_count(op->slots_in, "geom")); + BMVert **vert_arr = MEM_mallocN(sizeof(*vert_arr) * (size_t)vert_arr_max, __func__); + BMOIter siter; + BMVert *v; + float plane_inner[4]; + float plane_outer[4]; + + STACK_DECLARE(vert_arr); + + copy_v3_v3(plane_outer, plane); + copy_v3_v3(plane_inner, plane); + plane_outer[3] = plane[3] - dist; + plane_inner[3] = plane[3] + dist; + + STACK_INIT(vert_arr); + + BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) { + if ((clear_outer && plane_point_side_v3(plane_outer, v->co) > 0.0f) || + (clear_inner && plane_point_side_v3(plane_inner, v->co) < 0.0f)) + { + STACK_PUSH(vert_arr, v); + } + } + + while ((v = STACK_POP(vert_arr))) { + BM_vert_kill(bm, v); + } + + STACK_FREE(vert_arr); + MEM_freeN(vert_arr); + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_NEW | ELE_INPUT); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom_cut.out", BM_VERT | BM_EDGE, ELE_NEW); +} diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index f63e742d8ba..9dfbf951fc0 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -121,7 +121,7 @@ static void bm_bridge_best_rotation(struct BMEdgeLoopStore *el_store_a, struct B } if (el_b_best) { - BLI_rotatelist(lb_b, el_b_best); + BLI_rotatelist_first(lb_b, el_b_best); } } @@ -273,9 +273,8 @@ static void bridge_loop_pair(BMesh *bm, if (twist_offset != 0) { const int len_b = BM_edgeloop_length_get(el_store_b); ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); - const int offset = twist_offset % len_b; - LinkData *el_b = BLI_rfindlink(lb_b, (offset < 0) ? (offset + len_b) : offset); - BLI_rotatelist(lb_b, el_b); + LinkData *el_b = BLI_rfindlink(lb_b, mod_i(twist_offset, len_b)); + BLI_rotatelist_first(lb_b, el_b); } } @@ -343,7 +342,7 @@ static void bridge_loop_pair(BMesh *bm, BMVert *v_arr[4] = {v_a, v_b, v_b_next, v_a_next}; if (BM_face_exists(v_arr, 4, &f) == false) { /* copy if loop data if its is missing on one ring */ - f = BM_face_create_ngon_verts(bm, v_arr, 4, 0, false, true); + f = BM_face_create_verts(bm, v_arr, 4, NULL, BM_CREATE_NOP, true); l_iter = BM_FACE_FIRST_LOOP(f); if (l_b) BM_elem_attrs_copy(bm, bm, l_b, l_iter); l_iter = l_iter->next; @@ -356,7 +355,7 @@ static void bridge_loop_pair(BMesh *bm, BMVert *v_arr[3] = {v_a, v_b, v_a_next}; if (BM_face_exists(v_arr, 3, &f) == false) { /* fan-fill a triangle */ - f = BM_face_create_ngon_verts(bm, v_arr, 3, 0, false, true); + f = BM_face_create_verts(bm, v_arr, 3, NULL, BM_CREATE_NOP, true); l_iter = BM_FACE_FIRST_LOOP(f); if (l_b) BM_elem_attrs_copy(bm, bm, l_b, l_iter); l_iter = l_iter->next; @@ -422,8 +421,8 @@ static void bridge_loop_pair(BMesh *bm, BMO_op_initf(bm, &op_sub, 0, - "beautify_fill faces=%hf edges=ae use_restrict_tag=%b", - BM_ELEM_TAG, true); + "beautify_fill faces=%hf edges=ae use_restrict_tag=%b method=%i", + BM_ELEM_TAG, true, 1); if (use_edgeout) { BMOIter siter; diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c index c718cac4bd6..b3a42ba533e 100644 --- a/source/blender/bmesh/operators/bmo_connect.c +++ b/source/blender/bmesh/operators/bmo_connect.c @@ -31,6 +31,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_alloca.h" +#include "BLI_linklist_stack.h" #include "bmesh.h" @@ -117,10 +118,9 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) BMIter iter; BMVert *v; BMFace *f; - BMFace **faces = MEM_mallocN(sizeof(BMFace *) * bm->totface, __func__); - STACK_DECLARE(faces); + BLI_LINKSTACK_DECLARE(faces, BMFace *); - STACK_INIT(faces); + BLI_LINKSTACK_INIT(faces); /* add all faces connected to verts */ BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { @@ -129,20 +129,20 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) if (!BMO_elem_flag_test(bm, f, FACE_TAG)) { BMO_elem_flag_enable(bm, f, FACE_TAG); if (f->len > 3) { - STACK_PUSH(faces, f); + BLI_LINKSTACK_PUSH(faces, f); } } } } /* connect faces */ - while ((f = STACK_POP(faces))) { + while ((f = BLI_LINKSTACK_POP(faces))) { if (bm_face_connect_verts(bm, f) == -1) { BMO_error_raise(bm, op, BMERR_CONNECTVERT_FAILED, NULL); } } - MEM_freeN(faces); + BLI_LINKSTACK_FREE(faces); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT); } diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c index 6d30b327a6c..61085596acc 100644 --- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c +++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c @@ -31,6 +31,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_alloca.h" +#include "BLI_linklist_stack.h" #include "bmesh.h" @@ -179,9 +180,7 @@ void bmo_connect_verts_nonplanar_exec(BMesh *bm, BMOperator *op) BMOIter siter; BMFace *f; int totface = 0, totloop = 0; - int tottris; - BMFace **fstack; - STACK_DECLARE(fstack); + BLI_LINKSTACK_DECLARE(fstack, BMFace *); const float angle_limit = BMO_slot_float_get(op->slots_in, "angle_limit"); @@ -197,32 +196,28 @@ void bmo_connect_verts_nonplanar_exec(BMesh *bm, BMOperator *op) return; } - /* over alloc, if we split every face */ - tottris = poly_to_tri_count(totface, totloop); - fstack = MEM_mallocN(sizeof(BMFace *) * tottris, __func__); - - STACK_INIT(fstack); + BLI_LINKSTACK_INIT(fstack); BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { if (f->len > 3) { - STACK_PUSH(fstack, f); + BLI_LINKSTACK_PUSH(fstack, f); } } - while ((f = STACK_POP(fstack))) { + while ((f = BLI_LINKSTACK_POP(fstack))) { BMFace *f_pair[2]; if (bm_face_split_by_angle(bm, f, f_pair, angle_limit)) { int j; for (j = 0; j < 2; j++) { BM_face_normal_update(f_pair[j]); if (f_pair[j]->len > 3) { - STACK_PUSH(fstack, f_pair[j]); + BLI_LINKSTACK_PUSH(fstack, f_pair[j]); } } } } - MEM_freeN(fstack); + BLI_LINKSTACK_FREE(fstack); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c index 64d0ec6ac27..dd814fa8bfb 100644 --- a/source/blender/bmesh/operators/bmo_create.c +++ b/source/blender/bmesh/operators/bmo_create.c @@ -145,6 +145,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) /* EdgeNet Create */ if (tote != 0) { /* call edgenet prepare op so additional face creation cases work */ + BMOperator op_sub; BMO_op_initf(bm, &op_sub, op->flag, "edgenet_prepare edges=%fe", ELE_NEW); BMO_op_exec(bm, &op_sub); @@ -152,8 +153,8 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) BMO_op_finish(bm, &op_sub); BMO_op_initf(bm, &op_sub, op->flag, - "edgenet_fill edges=%fe use_fill_check=%b mat_nr=%i use_smooth=%b", - ELE_NEW, true, mat_nr, use_smooth); + "edgenet_fill edges=%fe mat_nr=%i use_smooth=%b sides=%i", + ELE_NEW, mat_nr, use_smooth, 10000); BMO_op_exec(bm, &op_sub); @@ -181,7 +182,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) /* if we dissolved anything, then return */ if (BMO_slot_buffer_count(op_sub.slots_out, "region.out")) { BMO_slot_copy(&op_sub, slots_out, "region.out", - op, slots_out, "faces.out"); + op, slots_out, "faces.out"); BMO_op_finish(bm, &op_sub); return; } @@ -282,7 +283,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) BMFace *f; BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)vert_arr, totv); - f = BM_face_create_ngon_vcloud(bm, vert_arr, totv, BM_CREATE_NO_DOUBLE); + f = BM_face_create_ngon_vcloud(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE); if (f) { BMO_elem_flag_enable(bm, f, ELE_OUT); diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index d633182de42..cf36e88ea98 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -32,17 +32,26 @@ #include "BLI_math.h" #include "bmesh.h" +#include "bmesh_tools.h" + #include "intern/bmesh_operators_private.h" +/* ***_ISGC: mark for garbage-collection */ + #define FACE_MARK 1 #define FACE_ORIG 2 #define FACE_NEW 4 + #define EDGE_MARK 1 #define EDGE_TAG 2 +#define EDGE_ISGC 8 #define VERT_MARK 1 #define VERT_TAG 2 +#define VERT_ISGC 8 + + static bool UNUSED_FUNCTION(check_hole_in_region) (BMesh *bm, BMFace *f) { @@ -230,14 +239,12 @@ cleanup: void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) { - /* might want to make this an option or mode - campbell */ - /* BMOperator fop; */ BMFace *act_face = bm->act_face; BMOIter eiter; - BMEdge *e; - BMIter viter; - BMVert *v; + BMIter iter; + BMEdge *e, *e_next; + BMVert *v, *v_next; const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts"); const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split"); @@ -245,10 +252,10 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) if (use_face_split) { BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_TAG); - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - BMIter iter; + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BMIter itersub; int untag_count = 0; - BM_ITER_ELEM(e, &iter, v, BM_EDGES_OF_VERT) { + BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) { if (!BMO_elem_flag_test(bm, e, EDGE_TAG)) { untag_count++; } @@ -264,22 +271,34 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) } if (use_verts) { - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { BMO_elem_flag_set(bm, v, VERT_MARK, (BM_vert_edge_count(v) != 2)); } } + /* tag all verts/edges connected to faces */ BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) { - BMFace *fa, *fb; + BMFace *f_pair[2]; + if (BM_edge_face_pair(e, &f_pair[0], &f_pair[1])) { + unsigned int j; + for (j = 0; j < 2; j++) { + BMLoop *l_first, *l_iter; + l_iter = l_first = BM_FACE_FIRST_LOOP(f_pair[j]); + do { + BMO_elem_flag_enable(bm, l_iter->v, VERT_ISGC); + BMO_elem_flag_enable(bm, l_iter->e, EDGE_ISGC); + } while ((l_iter = l_iter->next) != l_first); + } + } + } + BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) { + BMFace *fa, *fb; if (BM_edge_face_pair(e, &fa, &fb)) { BMFace *f_new; /* join faces */ - - /* BMESH_TODO - check on delaying edge removal since we may end up removing more than - * one edge, and later reference a removed edge */ - f_new = BM_faces_join_pair(bm, fa, fb, e, true); + f_new = BM_faces_join_pair(bm, fa, fb, e, false); if (f_new) { /* maintain active face */ @@ -290,8 +309,23 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) } } + /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on) + * so do this in a separate pass instead. */ + BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { + if ((e->l == NULL) && BMO_elem_flag_test(bm, e, EDGE_ISGC)) { + BM_edge_kill(bm, e); + } + } + BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { + if ((v->e == NULL) && BMO_elem_flag_test(bm, v, VERT_ISGC)) { + BM_vert_kill(bm, v); + } + } + /* done with cleanup */ + + if (use_verts) { - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { if (BMO_elem_flag_test(bm, v, VERT_MARK)) { if (BM_vert_edge_count(v) == 2) { BM_vert_collapse_edge(bm, v->e, v, true); @@ -310,21 +344,21 @@ static bool test_extra_verts(BMesh *bm, BMVert *v) /* test faces around verts for verts that would be wrongly killed * by dissolve faces. */ - BM_ITER_ELEM(f, &fiter, v, BM_FACES_OF_VERT) { - BM_ITER_ELEM(l, &liter, f, BM_LOOPS_OF_FACE) { + BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) { /* if an edge around a vert is a boundary edge, * then dissolve faces won't destroy it. * also if it forms a boundary with one * of the face region */ bool found = false; - BM_ITER_ELEM(e, &eiter, l->v, BM_EDGES_OF_VERT) { + BM_ITER_ELEM (e, &eiter, l->v, BM_EDGES_OF_VERT) { BMFace *f_iter; if (BM_edge_is_boundary(e)) { found = true; } else { - BM_ITER_ELEM(f_iter, &fiter_sub, e, BM_FACES_OF_EDGE) { + BM_ITER_ELEM (f_iter, &fiter_sub, e, BM_FACES_OF_EDGE) { if (!BMO_elem_flag_test(bm, f_iter, FACE_MARK)) { found = true; break; @@ -347,7 +381,7 @@ static bool test_extra_verts(BMesh *bm, BMVert *v) void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) { BMIter iter, fiter; - BMVert *v; + BMVert *v, *v_next; BMFace *f; const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split"); @@ -359,7 +393,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) bm_face_split(bm, VERT_MARK); } - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { if (BMO_elem_flag_test(bm, v, VERT_MARK)) { /* check if it's a two-valence ver */ if (BM_vert_edge_count(v) == 2) { @@ -407,7 +441,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) } /* clean up any remainin */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { if (BMO_elem_flag_test(bm, v, VERT_MARK)) { if (!BM_vert_dissolve(bm, v)) { BMO_error_raise(bm, op, BMERR_DISSOLVEVERTS_FAILED, NULL); diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c index 1dc7b0a414d..bd2485b92fb 100644 --- a/source/blender/bmesh/operators/bmo_dupe.c +++ b/source/blender/bmesh/operators/bmo_dupe.c @@ -46,23 +46,27 @@ * * Copy an existing vertex from one bmesh to another. */ -static BMVert *copy_vertex(BMesh *source_mesh, BMVert *source_vertex, BMesh *target_mesh, GHash *vhash) +static BMVert *bmo_vert_copy(BMOperator *op, + BMOpSlot *slot_vertmap_out, + BMesh *bm_dst, BMesh *bm_src, BMVert *v_src, GHash *vhash) { - BMVert *target_vertex = NULL; + BMVert *v_dst; /* Create a new vertex */ - target_vertex = BM_vert_create(target_mesh, source_vertex->co, NULL, BM_CREATE_SKIP_CD); - + v_dst = BM_vert_create(bm_dst, v_src->co, NULL, BM_CREATE_SKIP_CD); + BMO_slot_map_elem_insert(op, slot_vertmap_out, v_src, v_dst); + BMO_slot_map_elem_insert(op, slot_vertmap_out, v_dst, v_src); + /* Insert new vertex into the vert hash */ - BLI_ghash_insert(vhash, source_vertex, target_vertex); - + BLI_ghash_insert(vhash, v_src, v_dst); + /* Copy attributes */ - BM_elem_attrs_copy(source_mesh, target_mesh, source_vertex, target_vertex); - - /* Set internal op flags */ - BMO_elem_flag_enable(target_mesh, target_vertex, DUPE_NEW); + BM_elem_attrs_copy(bm_src, bm_dst, v_src, v_dst); + + /* Mark the vert for output */ + BMO_elem_flag_enable(bm_dst, v_dst, DUPE_NEW); - return target_vertex; + return v_dst; } /** @@ -70,55 +74,58 @@ static BMVert *copy_vertex(BMesh *source_mesh, BMVert *source_vertex, BMesh *tar * * Copy an existing edge from one bmesh to another. */ -static BMEdge *copy_edge(BMOperator *op, - BMOpSlot *slot_boundarymap_out, - BMesh *source_mesh, - BMEdge *source_edge, BMesh *target_mesh, - GHash *vhash, GHash *ehash) +static BMEdge *bmo_edge_copy(BMOperator *op, + BMOpSlot *slot_edgemap_out, + BMOpSlot *slot_boundarymap_out, + BMesh *bm_dst, BMesh *bm_src, + BMEdge *e_src, + GHash *vhash, GHash *ehash) { - BMEdge *target_edge = NULL; - BMVert *target_vert1, *target_vert2; - BMFace *face; - BMIter fiter; - int rlen; + BMEdge *e_dst; + BMVert *e_dst_v1, *e_dst_v2; + unsigned int rlen; /* see if any of the neighboring faces are * not being duplicated. in that case, * add it to the new/old map. */ + /* lookup edge */ rlen = 0; - for (face = BM_iter_new(&fiter, source_mesh, BM_FACES_OF_EDGE, source_edge); - face; - face = BM_iter_step(&fiter)) - { - if (BMO_elem_flag_test(source_mesh, face, DUPE_INPUT)) { - rlen++; - } + if (e_src->l) { + BMLoop *l_iter_src, *l_first_src; + l_iter_src = l_first_src = e_src->l; + do { + if (BMO_elem_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) { + rlen++; + } + } while ((l_iter_src = l_iter_src->radial_next) != l_first_src); } /* Lookup v1 and v2 */ - target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1); - target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2); + e_dst_v1 = BLI_ghash_lookup(vhash, e_src->v1); + e_dst_v2 = BLI_ghash_lookup(vhash, e_src->v2); /* Create a new edge */ - target_edge = BM_edge_create(target_mesh, target_vert1, target_vert2, NULL, BM_CREATE_SKIP_CD); - + e_dst = BM_edge_create(bm_dst, e_dst_v1, e_dst_v2, NULL, BM_CREATE_SKIP_CD); + BMO_slot_map_elem_insert(op, slot_edgemap_out, e_src, e_dst); + BMO_slot_map_elem_insert(op, slot_edgemap_out, e_dst, e_src); + /* add to new/old edge map if necassary */ if (rlen < 2) { /* not sure what non-manifold cases of greater then three * radial should do. */ - BMO_slot_map_elem_insert(op, slot_boundarymap_out, source_edge, target_edge); + BMO_slot_map_elem_insert(op, slot_boundarymap_out, e_src, e_dst); } /* Insert new edge into the edge hash */ - BLI_ghash_insert(ehash, source_edge, target_edge); - + BLI_ghash_insert(ehash, e_src, e_dst); + /* Copy attributes */ - BM_elem_attrs_copy(source_mesh, target_mesh, source_edge, target_edge); - - /* Set internal op flags */ - BMO_elem_flag_enable(target_mesh, target_edge, DUPE_NEW); + BM_elem_attrs_copy(bm_src, bm_dst, e_src, e_dst); + + /* Mark the edge for output */ + BMO_elem_flag_enable(bm_dst, e_dst, DUPE_NEW); - return target_edge; + return e_dst; } /** @@ -126,56 +133,49 @@ static BMEdge *copy_edge(BMOperator *op, * * Copy an existing face from one bmesh to another. */ -static BMFace *copy_face(BMOperator *op, - BMOpSlot *slot_facemap_out, - BMesh *source_mesh, - BMFace *source_face, BMesh *target_mesh, - GHash *vhash, GHash *ehash) +static BMFace *bmo_face_copy(BMOperator *op, + BMOpSlot *slot_facemap_out, + BMesh *bm_dst, BMesh *bm_src, + BMFace *f_src, + GHash *vhash, GHash *ehash) { - /* BMVert *target_vert1, *target_vert2; */ /* UNUSED */ - BMVert **vtar = BLI_array_alloca(vtar, source_face->len); - BMEdge **edar = BLI_array_alloca(edar, source_face->len); - BMLoop *source_loop, *target_loop; - BMFace *target_face = NULL; - BMIter iter, iter2; + BMFace *f_dst; + BMVert **vtar = BLI_array_alloca(vtar, f_src->len); + BMEdge **edar = BLI_array_alloca(edar, f_src->len); + BMLoop *l_iter_src, *l_iter_dst, *l_first_src; int i; - - /* lookup the first and second vert */ -#if 0 /* UNUSED */ - target_vert1 = BLI_ghash_lookup(vhash, BM_iter_new(&iter, source_mesh, BM_VERTS_OF_FACE, source_face)); - target_vert2 = BLI_ghash_lookup(vhash, BM_iter_step(&iter)); -#else - BM_iter_new(&iter, source_mesh, BM_VERTS_OF_FACE, source_face); - BM_iter_step(&iter); -#endif + + l_first_src = BM_FACE_FIRST_LOOP(f_src); /* lookup edge */ - BM_ITER_ELEM_INDEX (source_loop, &iter, source_face, BM_LOOPS_OF_FACE, i) { - vtar[i] = BLI_ghash_lookup(vhash, source_loop->v); - edar[i] = BLI_ghash_lookup(ehash, source_loop->e); - } + l_iter_src = l_first_src; + i = 0; + do { + vtar[i] = BLI_ghash_lookup(vhash, l_iter_src->v); + edar[i] = BLI_ghash_lookup(ehash, l_iter_src->e); + i++; + } while ((l_iter_src = l_iter_src->next) != l_first_src); /* create new face */ - target_face = BM_face_create(target_mesh, vtar, edar, source_face->len, BM_CREATE_SKIP_CD); - BMO_slot_map_elem_insert(op, slot_facemap_out, source_face, target_face); - BMO_slot_map_elem_insert(op, slot_facemap_out, target_face, source_face); - - BM_elem_attrs_copy(source_mesh, target_mesh, source_face, target_face); + f_dst = BM_face_create(bm_dst, vtar, edar, f_src->len, NULL, BM_CREATE_SKIP_CD); + BMO_slot_map_elem_insert(op, slot_facemap_out, f_src, f_dst); + BMO_slot_map_elem_insert(op, slot_facemap_out, f_dst, f_src); - /* mark the face for output */ - BMO_elem_flag_enable(target_mesh, target_face, DUPE_NEW); + /* Copy attributes */ + BM_elem_attrs_copy(bm_src, bm_dst, f_src, f_dst); /* copy per-loop custom data */ - BM_ITER_ELEM (source_loop, &iter, source_face, BM_LOOPS_OF_FACE) { - BM_ITER_ELEM (target_loop, &iter2, target_face, BM_LOOPS_OF_FACE) { - if (BLI_ghash_lookup(vhash, source_loop->v) == target_loop->v) { - BM_elem_attrs_copy(source_mesh, target_mesh, source_loop, target_loop); - break; - } - } - } + l_iter_src = l_first_src; + l_iter_dst = BM_FACE_FIRST_LOOP(f_dst); + do { + BM_elem_attrs_copy(bm_src, bm_dst, l_iter_src, l_iter_dst); + } while ((l_iter_dst = l_iter_dst->next), + (l_iter_src = l_iter_src->next) != l_first_src); + + /* Mark the face for output */ + BMO_elem_flag_enable(bm_dst, f_dst, DUPE_NEW); - return target_face; + return f_dst; } /** @@ -183,7 +183,7 @@ static BMFace *copy_face(BMOperator *op, * * Internal Copy function. */ -static void bmo_mesh_copy(BMOperator *op, BMesh *bm_src, BMesh *bm_dst) +static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) { BMVert *v = NULL, *v2; @@ -194,9 +194,12 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_src, BMesh *bm_dst) GHash *vhash, *ehash; BMOpSlot *slot_boundary_map_out = BMO_slot_get(op->slots_out, "boundary_map.out"); - BMOpSlot *slot_face_map_out = BMO_slot_get(op->slots_out, "face_map.out"); BMOpSlot *slot_isovert_map_out = BMO_slot_get(op->slots_out, "isovert_map.out"); + BMOpSlot *slot_vert_map_out = BMO_slot_get(op->slots_out, "vert_map.out"); + BMOpSlot *slot_edge_map_out = BMO_slot_get(op->slots_out, "edge_map.out"); + BMOpSlot *slot_face_map_out = BMO_slot_get(op->slots_out, "face_map.out"); + /* initialize pointer hashes */ vhash = BLI_ghash_ptr_new("bmesh dupeops v"); ehash = BLI_ghash_ptr_new("bmesh dupeops e"); @@ -209,7 +212,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_src, BMesh *bm_dst) BMIter iter; bool isolated = true; - v2 = copy_vertex(bm_src, v, bm_dst, vhash); + v2 = bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash); BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { if (BMO_elem_flag_test(bm_src, f, DUPE_INPUT)) { @@ -242,15 +245,16 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_src, BMesh *bm_dst) { /* make sure that verts are copied */ if (!BMO_elem_flag_test(bm_src, e->v1, DUPE_DONE)) { - copy_vertex(bm_src, e->v1, bm_dst, vhash); + bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v1, vhash); BMO_elem_flag_enable(bm_src, e->v1, DUPE_DONE); } if (!BMO_elem_flag_test(bm_src, e->v2, DUPE_DONE)) { - copy_vertex(bm_src, e->v2, bm_dst, vhash); + bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v2, vhash); BMO_elem_flag_enable(bm_src, e->v2, DUPE_DONE); } /* now copy the actual edge */ - copy_edge(op, slot_boundary_map_out, bm_src, e, bm_dst, vhash, ehash); + bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out, + bm_dst, bm_src, e, vhash, ehash); BMO_elem_flag_enable(bm_src, e, DUPE_DONE); } } @@ -261,7 +265,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_src, BMesh *bm_dst) /* vertex pass */ BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) { if (!BMO_elem_flag_test(bm_src, v, DUPE_DONE)) { - copy_vertex(bm_src, v, bm_dst, vhash); + bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash); BMO_elem_flag_enable(bm_src, v, DUPE_DONE); } } @@ -269,12 +273,13 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_src, BMesh *bm_dst) /* edge pass */ BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) { if (!BMO_elem_flag_test(bm_src, e, DUPE_DONE)) { - copy_edge(op, slot_boundary_map_out, bm_src, e, bm_dst, vhash, ehash); + bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out, + bm_dst, bm_src, e, vhash, ehash); BMO_elem_flag_enable(bm_src, e, DUPE_DONE); } } - copy_face(op, slot_face_map_out, bm_src, f, bm_dst, vhash, ehash); + bmo_face_copy(op, slot_face_map_out, bm_dst, bm_src, f, vhash, ehash); BMO_elem_flag_enable(bm_src, f, DUPE_DONE); } } @@ -307,16 +312,16 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_src, BMesh *bm_dst) void bmo_duplicate_exec(BMesh *bm, BMOperator *op) { BMOperator *dupeop = op; - BMesh *bm2 = BMO_slot_ptr_get(op->slots_in, "dest"); + BMesh *bm_dst = BMO_slot_ptr_get(op->slots_in, "dest"); - if (!bm2) - bm2 = bm; + if (!bm_dst) + bm_dst = bm; /* flag input */ BMO_slot_buffer_flag_enable(bm, dupeop->slots_in, "geom", BM_ALL_NOLOOP, DUPE_INPUT); /* use the internal copy function */ - bmo_mesh_copy(dupeop, bm, bm2); + bmo_mesh_copy(dupeop, bm_dst, bm); /* Output */ /* First copy the input buffers to output buffers - original data */ @@ -466,13 +471,14 @@ void bmo_spin_exec(BMesh *bm, BMOperator *op) float axis[3]; float rmat[3][3]; float phi; - int steps, do_dupli, a, usedvec; + int steps, do_dupli, a; + bool use_dvec; BMO_slot_vec_get(op->slots_in, "cent", cent); BMO_slot_vec_get(op->slots_in, "axis", axis); normalize_v3(axis); BMO_slot_vec_get(op->slots_in, "dvec", dvec); - usedvec = !is_zero_v3(dvec); + use_dvec = !is_zero_v3(dvec); steps = BMO_slot_int_get(op->slots_in, "steps"); phi = BMO_slot_float_get(op->slots_in, "angle") / steps; do_dupli = BMO_slot_bool_get(op->slots_in, "use_duplicate"); @@ -504,7 +510,7 @@ void bmo_spin_exec(BMesh *bm, BMOperator *op) BMO_op_finish(bm, &extop); } - if (usedvec) { + if (use_dvec) { mul_m3_v3(rmat, dvec); BMO_op_callf(bm, op->flag, "translate vec=%v space=%s verts=%S", diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c index 923b877b822..fdee80b9505 100644 --- a/source/blender/bmesh/operators/bmo_edgenet.c +++ b/source/blender/bmesh/operators/bmo_edgenet.c @@ -37,1028 +37,58 @@ #include "BLI_heap.h" #include "bmesh.h" +#include "bmesh_tools.h" #include "intern/bmesh_operators_private.h" /* own include */ #define EDGE_MARK 1 #define EDGE_VIS 2 -#define FACE_NEW 1 - #define ELE_NEW 1 -#define ELE_ORIG 4 - -#define FACE_IGNORE 16 - -typedef struct EPathNode { - struct EPathNode *next, *prev; - BMVert *v; - BMEdge *e; - BMEdge *cure; -} EPathNode; - -typedef struct EPath { - ListBase nodes; - float weight; - int group; -} EPath; - -typedef struct PathBase { - BLI_mempool *nodepool, *pathpool; -} PathBase; - -typedef struct EdgeData { - int tag; - int ftag; - BMDiskLink v1_disk_link, v2_disk_link; -} EdgeData; - -typedef struct VertData { - BMEdge *e; - float no[3], offco[3], sco[3]; /* offco is vertex coordinate slightly offset randomly */ - int tag; -} VertData; - -static int count_edge_faces(BMesh *bm, BMEdge *e); - -/**** rotation system code * */ - -BLI_INLINE BMDiskLink *rs_edge_link_get(BMEdge *e, BMVert *v, EdgeData *e_data) -{ - return v == ((BMEdge *)e)->v1 ? &(((EdgeData *)e_data)->v1_disk_link) : - &(((EdgeData *)e_data)->v2_disk_link); -} - -static bool rotsys_append_edge(BMEdge *e, BMVert *v, - EdgeData *edata, VertData *vdata) -{ - EdgeData *ed = &edata[BM_elem_index_get(e)]; - VertData *vd = &vdata[BM_elem_index_get(v)]; - - if (!vd->e) { - Link *e1 = (Link *)rs_edge_link_get(e, v, ed); - - vd->e = e; - e1->next = e1->prev = (Link *)e; - } - else { - BMDiskLink *dl1, *dl2, *dl3; - EdgeData *ved = &edata[BM_elem_index_get(vd->e)]; - - dl1 = rs_edge_link_get(e, v, ed); - dl2 = rs_edge_link_get(vd->e, v, ved); - dl3 = dl2->prev ? rs_edge_link_get(dl2->prev, v, &edata[BM_elem_index_get(dl2->prev)]) : NULL; - - dl1->next = vd->e; - dl1->prev = dl2->prev; - - dl2->prev = e; - if (dl3) { - dl3->next = e; - } - } - - return true; -} - -static void UNUSED_FUNCTION(rotsys_remove_edge)(BMEdge *e, BMVert *v, - EdgeData *edata, VertData *vdata) -{ - EdgeData *ed = edata + BM_elem_index_get(e); - VertData *vd = vdata + BM_elem_index_get(v); - BMDiskLink *e1, *e2; - - e1 = rs_edge_link_get(e, v, ed); - if (e1->prev) { - e2 = rs_edge_link_get(e1->prev, v, ed); - e2->next = e1->next; - } - - if (e1->next) { - e2 = rs_edge_link_get(e1->next, v, ed); - e2->prev = e1->prev; - } - - if (vd->e == e) - vd->e = (e != e1->next) ? e1->next : NULL; - - e1->next = e1->prev = NULL; -} - -static BMEdge *rotsys_nextedge(BMEdge *e, BMVert *v, - EdgeData *edata, VertData *UNUSED(vdata)) -{ - if (v == e->v1) - return edata[BM_elem_index_get(e)].v1_disk_link.next; - if (v == e->v2) - return edata[BM_elem_index_get(e)].v2_disk_link.next; - return NULL; -} - -static BMEdge *rotsys_prevedge(BMEdge *e, BMVert *v, - EdgeData *edata, VertData *UNUSED(vdata)) -{ - if (v == e->v1) - return edata[BM_elem_index_get(e)].v1_disk_link.prev; - if (v == e->v2) - return edata[BM_elem_index_get(e)].v2_disk_link.prev; - return NULL; -} - -static void rotsys_reverse(BMEdge *UNUSED(e), BMVert *v, EdgeData *edata, VertData *vdata) -{ - BMEdge **edges = NULL; - BMEdge *e_first; - BMEdge *e; - BLI_array_staticdeclare(edges, BM_DEFAULT_NGON_STACK_SIZE); - int i, totedge; - - e = e_first = vdata[BM_elem_index_get(v)].e; - do { - BLI_array_append(edges, e); - e = rotsys_nextedge(e, v, edata, vdata); - } while (e != e_first); - - totedge = BLI_array_count(edges); - for (i = 0; i < totedge / 2; i++) { - SWAP(BMEdge *, edges[i], edges[totedge - 1 - i]); - } - - vdata[BM_elem_index_get(v)].e = NULL; - for (i = 0; i < totedge; i++) { - rotsys_append_edge(edges[i], v, edata, vdata); - } - - BLI_array_free(edges); -} - -static int UNUSED_FUNCTION(rotsys_count)(BMVert *v, EdgeData *edata, VertData *vdata) -{ - BMEdge *e = vdata[BM_elem_index_get(v)].e; - int i = 0; - - if (!e) - return 0; - - do { - if (!e) - return 0; - e = rotsys_nextedge(e, v, edata, vdata); - - if (i >= (1 << 20)) { - printf("bmesh error: infinite loop in disk cycle!\n"); - return 0; - } - - i += 1; - } while (e != vdata[BM_elem_index_get(v)].e); - - return i; -} - -static int UNUSED_FUNCTION(rotsys_fill_faces)(BMesh *bm, EdgeData *edata, VertData *vdata) -{ - BMIter iter; - BMEdge *e, **edges = NULL; - BLI_array_declare(edges); - BMVert *v, **verts = NULL; - BMFace *f; - BLI_array_declare(verts); - SmallHash visithash, *hash = &visithash; - int i; - - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - BMEdge *e2, *starte; - BMVert *startv; - int rad, ok; - - rad = count_edge_faces(bm, e); - - if (rad < 2) { - starte = e; - } - else { - continue; - } - - /* do two passes, going forward then backward */ - for (i = 0; i < 2; i++) { - BLI_smallhash_init(hash); - - BLI_array_empty(verts); - BLI_array_empty(edges); - - startv = v = starte->v1; - e2 = starte; - ok = 1; - if (!v || !e2) - continue; - - do { - if (BLI_smallhash_haskey(hash, (uintptr_t)e2) || - BLI_smallhash_haskey(hash, (uintptr_t)v)) - { - ok = 0; - break; - } - - BLI_array_append(verts, v); - BLI_array_append(edges, e2); - - BLI_smallhash_insert(hash, (uintptr_t)e2, NULL); - - v = BM_edge_other_vert(e2, v); - e2 = i ? rotsys_prevedge(e2, v, edata, vdata) : rotsys_nextedge(e2, v, edata, vdata); - } while (e2 != starte && v != startv); - - BLI_smallhash_release(hash); - - if (!ok || BLI_array_count(edges) < 3) - continue; - - f = BM_face_create_ngon(bm, verts[0], verts[1], edges, BLI_array_count(edges), BM_CREATE_NO_DOUBLE); - if (UNLIKELY(f == NULL)) { - continue; - } - } - } - - return 0; -} - -static void rotsys_make_consistent(BMesh *bm, EdgeData *edata, VertData *vdata) -{ - BMIter iter; - BMEdge *e; - BMVert *v, **stack = NULL; - BLI_array_declare(stack); - int i; - - for (i = 0; i < bm->totvert; i++) { - vdata[i].tag = 0; - } - - while (1) { - VertData *vd; - BMVert *startv = NULL; - float dis; - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - vd = vdata + BM_elem_index_get(v); - - if (vd->tag) - continue; - - if (!startv || dot_v3v3(vd->offco, vd->offco) > dis) { - dis = dot_v3v3(vd->offco, vd->offco); - startv = v; - } - } - - if (!startv) - break; - - vd = vdata + BM_elem_index_get(startv); - - BLI_array_empty(stack); - BLI_array_append(stack, startv); - - vd->tag = 1; - - while (BLI_array_count(stack)) { - v = BLI_array_pop(stack); - vd = vdata + BM_elem_index_get(v); - - if (!vd->e) - continue; - - e = vd->e; - do { - BMVert *v2 = BM_edge_other_vert(e, v); - VertData *vd2 = vdata + BM_elem_index_get(v2); - - if (dot_v3v3(vd->no, vd2->no) < 0.0f + FLT_EPSILON * 2) { - rotsys_reverse(e, v2, edata, vdata); - mul_v3_fl(vd2->no, -1.0f); - } - - if (!vd2->tag) { - BLI_array_append(stack, v2); - vd2->tag = 1; - } - - e = rotsys_nextedge(e, v, edata, vdata); - } while (e != vd->e); - } - } - - BLI_array_free(stack); -} - -static void init_rotsys(BMesh *bm, EdgeData *edata, VertData *vdata) -{ - BMIter iter; - BMEdge *e; - BMEdge **edges = NULL; - BLI_array_staticdeclare(edges, BM_DEFAULT_NGON_STACK_SIZE); - BMVert *v; - RNG *rng; - /* BMVert **verts = NULL; */ - /* BLI_array_staticdeclare(verts, BM_DEFAULT_NGON_STACK_SIZE); */ /* UNUSE */ - int i; - - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMIter eiter; - float no[3], cent[3]; - int j, k = 0, totedge = 0; - - if (BM_elem_index_get(v) == -1) - continue; - - BLI_array_empty(edges); - - BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { - BLI_array_append(edges, e); - totedge++; - } - } - - copy_v3_v3(cent, v->co); - - zero_v3(no); - for (i = 0; i < totedge; i++) { - BMEdge *e1, *e2; - float cno[3], vec1[3], vec2[3]; - - e1 = edges[i]; - e2 = edges[(i + 1) % totedge]; - - sub_v3_v3v3(vec1, (BM_edge_other_vert(e1, v))->co, v->co); - sub_v3_v3v3(vec2, (BM_edge_other_vert(e2, v))->co, v->co); - - cross_v3_v3v3(cno, vec1, vec2); - normalize_v3(cno); - - if (i && dot_v3v3(cno, no) < 0.0f + FLT_EPSILON * 10) - mul_v3_fl(cno, -1.0f); - - add_v3_v3(no, cno); - normalize_v3(no); - } - - /* generate plane-flattened coordinates */ - for (i = 0; i < totedge; i++) { - BMEdge *e1; - BMVert *v2; - float cvec[3], vec1[3]; - - e1 = edges[i]; - v2 = BM_edge_other_vert(e1, v); - - sub_v3_v3v3(vec1, v2->co, v->co); - - cross_v3_v3v3(cvec, vec1, no); - cross_v3_v3v3(vec1, cvec, no); - normalize_v3(vec1); - - mul_v3_fl(vec1, len_v3v3(v2->co, v->co)); - add_v3_v3(vec1, v->co); - - copy_v3_v3(vdata[BM_elem_index_get(v2)].sco, vec1); - } - - rng = BLI_rng_new_srandom(0); - - /* first, ensure no 0 or 180 angles between adjacent - * (and that adjacent's adjacent) edges */ - for (i = 0, k = 0; i < totedge; i++) { - BMEdge *e1, *e2, *e3 = NULL; - BMVert *v1, *v2, *v3; - VertData *vd1, *vd2, *vd3; - float vec1[3], vec2[3], vec3[3], size; - int s1, s2, s3; - - if (totedge < 3) - continue; - - e1 = edges[(i + totedge - 1) % totedge]; - e2 = edges[i]; - e3 = edges[(i + 1) % totedge]; - - v1 = BM_edge_other_vert(e1, v); - v2 = BM_edge_other_vert(e2, v); - v3 = BM_edge_other_vert(e3, v); - - vd1 = vdata + BM_elem_index_get(v1); - vd2 = vdata + BM_elem_index_get(v2); - vd3 = vdata + BM_elem_index_get(v3); - - sub_v3_v3v3(vec1, vd1->sco, cent); - sub_v3_v3v3(vec2, vd2->sco, cent); - sub_v3_v3v3(vec3, vd3->sco, cent); - - size = (len_v3(vec1) + len_v3(vec3)) * 0.01f; - normalize_v3(vec1); normalize_v3(vec2); normalize_v3(vec3); - -#ifdef STRAIGHT -#undef STRAIGHT -#endif -#define STRAIGHT(vec11, vec22) (fabsf(dot_v3v3((vec11), (vec22))) > 1.0f - ((float)FLT_EPSILON * 1000.0f)) - - s1 = STRAIGHT(vec1, vec2); s2 = STRAIGHT(vec2, vec3); s3 = STRAIGHT(vec1, vec3); - - if (s1 || s2 || s3) { - copy_v3_v3(cent, v->co); - - for (j = 0; j < 3; j++) { - float fac = (BLI_rng_get_float(rng) - 0.5f) * size; - cent[j] += fac; - } - - if (k < 2000) { - i = 0; - k++; - continue; - } - else { - k++; - continue; - } - - } - } - - BLI_rng_free(rng); - - copy_v3_v3(vdata[BM_elem_index_get(v)].offco, cent); - //copy_v3_v3(v->co, cent); - - /* now, sort edges so the triangle fan of all edges - * has a consistent normal. this is the same as - * sorting by polar coordinates along a group normal */ - for (j = 0; j < totedge; j++) { - for (i = 0; i < totedge; i++) { - BMEdge *e1, *e2, *e3 = NULL; - BMVert *v1, *v2, *v3; - VertData *vd1, *vd2, *vd3; - float vec1[3], vec2[3], vec3[3], n1[3], n2[3], n3[3]; - - e1 = edges[(i + totedge - 1) % totedge]; - e2 = edges[i]; - e3 = edges[(i + 1) % totedge]; - - v1 = BM_edge_other_vert(e1, v); - v2 = BM_edge_other_vert(e2, v); - v3 = BM_edge_other_vert(e3, v); - - vd1 = vdata + BM_elem_index_get(v1); - vd2 = vdata + BM_elem_index_get(v2); - vd3 = vdata + BM_elem_index_get(v3); - - sub_v3_v3v3(vec1, vd1->sco, cent); - sub_v3_v3v3(vec2, vd2->sco, cent); - sub_v3_v3v3(vec3, vd3->sco, cent); - - cross_v3_v3v3(n1, vec1, vec2); - cross_v3_v3v3(n2, vec2, vec3); - cross_v3_v3v3(n3, vec1, vec3); - - /* this case happens often enough and probably not worth bothering users with, - * maybe enable for debugging code but not for everyday use - campbell */ -#if 0 - /* Other way to determine if two vectors approach are (nearly) parallel: the - * cross product of the two vectors will approach zero */ - { - int s1, s2, s3; - s1 = (dot_v3v3(n1, n1) < (0.0f + FLT_EPSILON * 10)); - s2 = (dot_v3v3(n2, n2) < (0.0f + FLT_EPSILON * 10)); - s3 = (totedge < 3) ? 0 : (dot_v3v3(n3, n3) < (0.0f + FLT_EPSILON * 10)); - - if (s1 || s2 || s3) { - fprintf(stderr, "%s: s1: %d, s2: %d, s3: %dx (bmesh internal error)\n", __func__, s1, s2, s3); - } - } -#endif - - normalize_v3(n1); normalize_v3(n2); normalize_v3(n3); - - - if (dot_v3v3(n1, n2) < 0.0f) { - if (dot_v3v3(n1, n3) >= 0.0f + FLT_EPSILON * 10) { - SWAP(BMEdge *, edges[i], edges[(i + 1) % totedge]); - } - else { - SWAP(BMEdge *, edges[(i + totedge - 1) % totedge], edges[(i + 1) % totedge]); - SWAP(BMEdge *, edges[i], edges[(i + 1) % totedge]); - } - } - } - } - -#undef STRAIGHT - - zero_v3(no); - - /* yay, edges are sorted */ - for (i = 0; i < totedge; i++) { - BMEdge *e1 = edges[i], *e2 = edges[(i + 1) % totedge]; - float eno[3]; - - normal_tri_v3(eno, BM_edge_other_vert(e1, v)->co, v->co, BM_edge_other_vert(e2, v)->co); - add_v3_v3(no, eno); - - rotsys_append_edge(edges[i], v, edata, vdata); - } - - normalize_v3(no); - copy_v3_v3(vdata[BM_elem_index_get(v)].no, no); - } - - /* now, make sure rotation system is topologically consistent - * (e.g. vert normals consistently point either inside or outside) */ - rotsys_make_consistent(bm, edata, vdata); - - //rotsys_fill_faces(bm, edata, vdata); - -#if 0 - /* create visualizing geometry */ - BMVert *lastv; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMVert *v2; - BMFace *f; - int totedge = BM_vert_edge_count(v); - - if (BM_elem_index_get(v) == -1) - continue; - - //cv = BM_vert_create(bm, cent, v); - //BM_elem_index_set(cv, -1); /* set_dirty! */ - i = 0; - e = vdata[BM_elem_index_get(v)].e; - lastv = NULL; - do { - BMEdge *e2; - BMVert *v2; - float f = ((float)i / (float)totedge) * 0.35 + 0.05; - float co[3]; - - if (!e) - break; - - if (!BM_edge_other_vert(e, v)) - continue; - - sub_v3_v3v3(co, (BM_edge_other_vert(e, v))->co, vdata[BM_elem_index_get(v)].offco); - mul_v3_fl(co, f); - add_v3_v3(co, vdata[BM_elem_index_get(v)].offco); - - v2 = BM_vert_create(bm, co, NULL); - BM_elem_index_set(v2, -1); /* set_dirty! */ - //BM_edge_create(bm, cv, v2, NULL, 0); - - BM_vert_select_set(bm, v2, true); - if (lastv) { - e2 = BM_edge_create(bm, lastv, v2, NULL, 0); - BM_edge_select_set(bm, e2, true); - } - - lastv = v2; - - e = rotsys_nextedge(e, v, edata, vdata); - i++; - } while (e != vdata[BM_elem_index_get(v)].e); - } -#endif - - BLI_array_free(edges); -} - -static PathBase *edge_pathbase_new(void) -{ - PathBase *pb = MEM_callocN(sizeof(PathBase), "PathBase"); - - pb->nodepool = BLI_mempool_create(sizeof(EPathNode), 1, 512, BLI_MEMPOOL_SYSMALLOC); - pb->pathpool = BLI_mempool_create(sizeof(EPath), 1, 512, BLI_MEMPOOL_SYSMALLOC); - - return pb; -} - -static void edge_pathbase_free(PathBase *pathbase) -{ - BLI_mempool_destroy(pathbase->nodepool); - BLI_mempool_destroy(pathbase->pathpool); - MEM_freeN(pathbase); -} - -static EPath *edge_copy_add_path(PathBase *pb, EPath *path, BMVert *appendv, BMEdge *e) -{ - EPath *path2; - EPathNode *node, *node2; - - path2 = BLI_mempool_alloc(pb->pathpool); - path2->nodes.first = path2->nodes.last = NULL; - path2->weight = 0.0f; - path2->group = path->group; - - for (node = path->nodes.first; node; node = node->next) { - node2 = BLI_mempool_alloc(pb->nodepool); - *node2 = *node; - BLI_addtail(&path2->nodes, node2); - } - - node2 = BLI_mempool_alloc(pb->nodepool); - node2->v = appendv; - node2->e = e; - node2->cure = NULL; - - BLI_addtail(&path2->nodes, node2); - - return path2; -} - -static EPath *edge_path_new(PathBase *pb, BMVert *start, BMEdge *starte) -{ - EPath *path; - EPathNode *node; - - path = BLI_mempool_alloc(pb->pathpool); - node = BLI_mempool_alloc(pb->nodepool); - - path->nodes.first = path->nodes.last = NULL; - - node->v = start; - node->e = starte; - node->cure = NULL; - - BLI_addtail(&path->nodes, node); - path->weight = 0.0f; - - return path; -} - -static float edge_weight_path(EPath *path, EdgeData *edata, VertData *UNUSED(vdata)) -{ - EPathNode *node, *first = path->nodes.first; - float w = 0.0; - - for (node = path->nodes.first; node; node = node->next) { - if (node->e && node != path->nodes.first) { - w += edata[BM_elem_index_get(node->e)].ftag; - if (node->prev) { - /* BMESH_TOD */ - (void)first; - //w += len_v3v3(node->v->co, first->e->v1->co) * 0.0001f; - //w += len_v3v3(node->v->co, first->e->v2->co) * 0.0001f; - } - } - - w += 1.0f; - } - - return w; -} - - -static void edge_free_path(PathBase *pathbase, EPath *path) -{ - EPathNode *node, *next; - - for (node = path->nodes.first; node; node = next) { - next = node->next; - BLI_mempool_free(pathbase->nodepool, node); - } - - BLI_mempool_free(pathbase->pathpool, path); -} - -static EPath *edge_find_shortest_path(BMesh *bm, BMOperator *op, BMEdge *edge, EdgeData *edata, - VertData *vdata, PathBase *pathbase, int group) -{ - BMEdge *e; - GHash *gh = BLI_ghash_ptr_new("createops find shortest path"); - BMVert *v1, *v2; - BMVert **verts = NULL; - BLI_array_staticdeclare(verts, 1024); - Heap *heap = BLI_heap_new(); - EPath *path = NULL, *path2; - BMVert *startv; - BMVert *endv; - EPathNode *node; - int i; - const bool use_restrict = BMO_slot_bool_get(op->slots_in, "use_restrict"); - BMOpSlot *slot_restrict = BMO_slot_get(op->slots_in, "restrict"); - - - startv = edata[BM_elem_index_get(edge)].ftag ? edge->v2 : edge->v1; - endv = edata[BM_elem_index_get(edge)].ftag ? edge->v1 : edge->v2; - - path = edge_path_new(pathbase, startv, edge); - BLI_ghash_insert(gh, startv, NULL); - BLI_heap_insert(heap, path->weight, path); - path->group = group; - - while (BLI_heap_size(heap)) { - VertData *vd; - EPathNode *last; - BMFace *f = NULL; - - path = BLI_heap_popmin(heap); - last = path->nodes.last; - v1 = last->v; - - if (v1 == endv) { - /* make sure this path loop doesn't already exists */ - i = 0; - BLI_array_empty(verts); - for (i = 0, node = path->nodes.first; node; node = node->next, i++) { - BLI_array_grow_one(verts); - verts[i] = node->v; - } - - if (BM_face_exists(verts, i, &f)) { - if (!BMO_elem_flag_test(bm, f, FACE_IGNORE)) { - BLI_ghash_remove(gh, endv, NULL, NULL); - continue; - } - } - break; - } - - vd = vdata + BM_elem_index_get(v1); - if (!vd->e) - continue; - - v2 = NULL; - while (1) { - if (!last->cure) { - last->cure = e = vdata[BM_elem_index_get(last->v)].e; - } - else { - last->cure = e = rotsys_nextedge(last->cure, last->v, edata, vdata); - if (last->cure == vdata[BM_elem_index_get(last->v)].e) { - v2 = NULL; - break; - } - } - - if (e == edge || !BMO_elem_flag_test(bm, e, EDGE_MARK)) { - continue; - } - - v2 = BM_edge_other_vert(e, last->v); - - if (BLI_ghash_haskey(gh, v2)) { - v2 = NULL; - continue; - } - - if (use_restrict) { - int *group_flag = (int *)BMO_slot_map_data_get(slot_restrict, e); - if (group_flag) { - if (!(*group_flag & path->group)) { - v2 = NULL; - continue; - } - } - } - - break; - } - - if (!v2) { - edge_free_path(pathbase, path); - path = NULL; - continue; - } - - /* add path back into heap */ - BLI_heap_insert(heap, path->weight, path); - - /* put v2 in gh ma */ - BLI_ghash_insert(gh, v2, NULL); - - path2 = edge_copy_add_path(pathbase, path, v2, e); - path2->weight = edge_weight_path(path2, edata, vdata); - - BLI_heap_insert(heap, path2->weight, path2); - } - - if (path && ((EPathNode *)path->nodes.last)->v != endv) { - edge_free_path(pathbase, path); - path = NULL; - } - - BLI_array_free(verts); - BLI_heap_free(heap, NULL); - BLI_ghash_free(gh, NULL, NULL); - - return path; -} - -static int count_edge_faces(BMesh *bm, BMEdge *e) -{ - int i = 0; - BMLoop *l = e->l; - - if (!l) { - return 0; - } - - do { - if (!BMO_elem_flag_test(bm, l->f, FACE_IGNORE)) { - i++; - } - - l = l->radial_next; - } while (l != e->l); - - return i; -} - -BLI_INLINE void vote_on_winding(BMEdge *edge, EPathNode *node, unsigned int winding[2]) -{ - BMVert *test_v1, *test_v2; - /* we want to use the reverse winding to the existing order */ - BM_edge_ordered_verts(edge, &test_v2, &test_v1); - - /* edges vote on which winding wins out */ - winding[(test_v1 == node->v)]++; -} - -static BMFace *bm_face_from_path(BMesh *bm, EPath *path, - EdgeData *edata, - const bool use_fill_check) -{ - /* accumulte winding directions for each edge which has a face */ - const unsigned int path_len = BLI_countlist(&path->nodes); - unsigned int winding[2] = {0, 0}; - unsigned int i; - - EPathNode *node; - - BMVert **verts = BLI_array_alloca(verts, path_len); - BMEdge **edges = BLI_array_alloca(edges, path_len); - BMEdge *e; - BMVert *v; - - for (node = path->nodes.first, i = 0; node; node = node->next, i++) { - - v = node->v; - e = BM_edge_exists(v, node->next ? - node->next->v : - ((EPathNode *)path->nodes.first)->v); - - /* check on the winding */ - if (e->l) { - if (UNLIKELY(count_edge_faces(bm, e) >= 2)) { - return NULL; - } - - vote_on_winding(e, node, winding); - } - - verts[i] = v; - edges[i] = e; - } - - /* do after incase we bail early, above */ - for (i = 0; i < path_len; i++) { - edata[BM_elem_index_get(edges[i])].ftag++; - } - - - /* if these are even it doesn't really matter what to do, - * with consistent geometry one will be zero, the choice is clear */ - if (winding[0] > winding[1]) { - BLI_array_wrap(verts, path_len, -1); - BLI_array_reverse(verts, path_len); - BLI_array_reverse(edges, path_len); - } - - if ((use_fill_check == false) || - /* fairly expensive check - see if there are already faces filling this area */ - (BM_face_exists_multi(verts, edges, path_len) == false)) - { - return BM_face_create(bm, verts, edges, path_len, BM_CREATE_NO_DOUBLE); - } - else { - return NULL; - } -} void bmo_edgenet_fill_exec(BMesh *bm, BMOperator *op) { - BMIter iter; + BMOperator op_attr; BMOIter siter; BMFace *f; - BMEdge *e; - EPath *path; - EdgeData *edata; - VertData *vdata; - PathBase *pathbase; - const bool use_restrict = BMO_slot_bool_get(op->slots_in, "use_restrict"); - const bool use_fill_check = BMO_slot_bool_get(op->slots_in, "use_fill_check"); const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); - int i; - BMOpSlot *slot_restrict = BMO_slot_get(op->slots_in, "restrict"); - BMOpSlot *slot_face_groupmap_out = BMO_slot_get(op->slots_out, "face_groupmap.out"); +// const int sides = BMO_slot_int_get(op->slots_in, "sides"); if (!bm->totvert || !bm->totedge) return; - pathbase = edge_pathbase_new(); - - edata = MEM_callocN(sizeof(EdgeData) * bm->totedge, "EdgeData"); - vdata = MEM_callocN(sizeof(VertData) * bm->totvert, "VertData"); + BM_mesh_elem_hflag_disable_all(bm, BM_EDGE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "edges", BM_EDGE, BM_ELEM_TAG, false); - BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK); - BMO_slot_buffer_flag_enable(bm, op->slots_in, "exclude_faces", BM_FACE, FACE_IGNORE); - - BM_mesh_elem_index_ensure(bm, BM_VERT); - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - BMO_elem_flag_enable(bm, f, ELE_ORIG); - } + BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); + BM_mesh_edgenet(bm, true, true); // TODO, sides - BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) { - BM_elem_index_set(e, i); /* set_inline */ + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); - if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) { - edata[i].tag = 2; + BMO_ITER (f, &siter, op->slots_out, "faces.out", BM_FACE) { + f->mat_nr = mat_nr; + if (use_smooth) { + BM_elem_flag_enable(f, BM_ELEM_SMOOTH); } + /* normals are zero'd */ + BM_face_normal_update(f); } - bm->elem_index_dirty &= ~BM_EDGE; - init_rotsys(bm, edata, vdata); + /* --- Attribute Fill --- */ + /* may as well since we have the faces already in a buffer */ + BMO_op_initf(bm, &op_attr, op->flag, + "face_attribute_fill faces=%S use_normals=%b", + op, "faces.out", true); - while (1) { - BMEdge *edge = NULL; - int group = 0; + BMO_op_exec(bm, &op_attr); - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - /* if restrict is on, only start on faces in the restrict map */ - if (use_restrict && !BMO_slot_map_contains(slot_restrict, e)) - continue; - - if (edata[BM_elem_index_get(e)].tag < 2) { - edge = e; - - if (use_restrict) { - int gi_iter = 0, gi_count = 0, gi = 0; - - group = BMO_slot_map_int_get(slot_restrict, e); - - for (gi_iter = 0; gi_iter < 30; gi_iter++) { - if (group & (1 << gi_iter)) { - gi_count++; - gi = gi_iter; - - if (gi_count - 1 == edata[BM_elem_index_get(e)].tag) { - break; - } - } - } - - group = (1 << gi); - } - - break; - } - } - - if (!edge) - break; - - edata[BM_elem_index_get(edge)].tag += 1; - - path = edge_find_shortest_path(bm, op, edge, edata, vdata, pathbase, group); - if (path && path->nodes.first) { - BMFace *f = bm_face_from_path(bm, path, edata, - use_fill_check); - - if (f && !BMO_elem_flag_test(bm, f, ELE_ORIG)) { - BMO_elem_flag_enable(bm, f, FACE_NEW); - f->mat_nr = mat_nr; - if (use_smooth) { - BM_elem_flag_enable(f, BM_ELEM_SMOOTH); - } - } - - if (use_restrict) { - BMO_slot_map_int_insert(op, slot_face_groupmap_out, f, path->group); - } - - edge_free_path(pathbase, path); - } + /* check if some faces couldn't be touched */ + if (BMO_slot_buffer_count(op_attr.slots_out, "faces_fail.out")) { + BMO_op_callf(bm, op->flag, "recalc_face_normals faces=%S", &op_attr, "faces_fail.out"); } + BMO_op_finish(bm, &op_attr); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_NEW); - - edge_pathbase_free(pathbase); - MEM_freeN(edata); - MEM_freeN(vdata); } static BMEdge *edge_next(BMesh *bm, BMEdge *e) diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c index 070cc187045..90c514bfd02 100644 --- a/source/blender/bmesh/operators/bmo_extrude.c +++ b/source/blender/bmesh/operators/bmo_extrude.c @@ -77,7 +77,7 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) f_side = BM_face_create_quad_tri(bm, l_org->next->v, l_new->next->v, l_new->v, l_org->v, - f_org, false); + f_org, BM_CREATE_NOP); l_side_iter = BM_FACE_FIRST_LOOP(f_side); @@ -163,14 +163,14 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op) /* disable root flag on all new skin nodes */ if (CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) { BMVert *v; - BMO_ITER(v, &siter, dupeop.slots_out, "geom.out", BM_VERT) { + BMO_ITER (v, &siter, dupeop.slots_out, "geom.out", BM_VERT) { bm_extrude_disable_skin_root(bm, v); } } for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e; e = BMO_iter_step(&siter)) { BMVert *f_verts[4]; - e_new = *(BMEdge **)BMO_iter_map_value(&siter); + e_new = BMO_iter_map_value_ptr(&siter); if (e->l && e->v1 != e->l->v) { f_verts[0] = e->v1; @@ -185,7 +185,7 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op) f_verts[3] = e_new->v2; } /* not sure what to do about example face, pass NULL for now */ - f = BM_face_create_quad_tri_v(bm, f_verts, 4, NULL, false); + f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true); bm_extrude_copy_face_loop_attributes(bm, f); if (BMO_elem_flag_test(bm, e, EXT_INPUT)) @@ -211,11 +211,11 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) const bool has_vskin = CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN); for (v = BMO_iter_new(&siter, op->slots_in, "verts", BM_VERT); v; v = BMO_iter_step(&siter)) { - dupev = BM_vert_create(bm, v->co, v, 0); + dupev = BM_vert_create(bm, v->co, v, BM_CREATE_NOP); if (has_vskin) bm_extrude_disable_skin_root(bm, v); - e = BM_edge_create(bm, v, dupev, NULL, 0); + e = BM_edge_create(bm, v, dupev, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, e, EXT_KEEP); BMO_elem_flag_enable(bm, dupev, EXT_KEEP); @@ -319,7 +319,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) /* disable root flag on all new skin nodes */ if (CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) { - BMO_ITER(v, &siter, dupeop.slots_out, "geom.out", BM_VERT) { + BMO_ITER (v, &siter, dupeop.slots_out, "geom.out", BM_VERT) { bm_extrude_disable_skin_root(bm, v); } } @@ -372,7 +372,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) continue; } - e_new = *(BMEdge **)BMO_iter_map_value(&siter); + e_new = BMO_iter_map_value_ptr(&siter); if (!e_new) { continue; @@ -401,13 +401,13 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) } /* not sure what to do about example face, pass NULL for now */ - f = BM_face_create_quad_tri_v(bm, f_verts, 4, NULL, false); + f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true); bm_extrude_copy_face_loop_attributes(bm, f); } /* link isolated vert */ for (v = BMO_iter_new(&siter, dupeop.slots_out, "isovert_map.out", 0); v; v = BMO_iter_step(&siter)) { - BMVert *v2 = *((void **)BMO_iter_map_value(&siter)); + BMVert *v2 = BMO_iter_map_value_ptr(&siter); BM_edge_create(bm, v, v2, v->e, BM_CREATE_NO_DOUBLE); } diff --git a/source/blender/bmesh/operators/bmo_fill_attribute.c b/source/blender/bmesh/operators/bmo_fill_attribute.c new file mode 100644 index 00000000000..f53b4536e44 --- /dev/null +++ b/source/blender/bmesh/operators/bmo_fill_attribute.c @@ -0,0 +1,176 @@ + +/* + * ***** 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. + * + * Contributor(s): Campbell Barton. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/operators/bmo_fill_attribute.c + * \ingroup bmesh + * + * Fill in geometry with the attributes of their adjacent data. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_linklist_stack.h" + +#include "bmesh.h" + +#include "intern/bmesh_operators_private.h" /* own include */ + +/** + * Check if all other loops are tagged. + */ +static bool bm_loop_is_all_radial_tag(BMLoop *l) +{ + BMLoop *l_iter; + l_iter = l->radial_next; + do { + if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG) == 0) { + return false; + } + } while ((l_iter = l_iter->radial_next) != l); + + return true; +} + +/** + * Callback to run on source-loops for #BM_face_copy_shared + */ +static bool bm_loop_is_face_untag(BMElem *ele, void *UNUSED(user_data)) +{ + return (BM_elem_flag_test(((BMLoop *)ele)->f, BM_ELEM_TAG) == 0); +} + +/** + * Copy all attributes from adjacent untagged faces. + */ +static void bm_face_copy_shared_all(BMesh *bm, BMLoop *l, + const bool use_normals, const bool use_data) +{ + BMLoop *l_other = l->radial_next; + BMFace *f = l->f, *f_other; + while (BM_elem_flag_test(l_other->f, BM_ELEM_TAG)) { + l_other = l_other->radial_next; + } + f_other = l_other->f; + + if (use_data) { + /* copy face-attrs */ + BM_elem_attrs_copy(bm, bm, f_other, f); + + /* copy loop-attrs */ + BM_face_copy_shared(bm, f, bm_loop_is_face_untag, NULL); + } + + if (use_normals) { + /* copy winding (flipping) */ + if (l->v == l_other->v) { + BM_face_normal_flip(bm, f); + } + } +} + +/** + * Flood fill attributes. + */ +static unsigned int bmesh_face_attribute_fill(BMesh *bm, + const bool use_normals, const bool use_data) +{ + BLI_LINKSTACK_DECLARE(loop_queue_prev, BMLoop *); + BLI_LINKSTACK_DECLARE(loop_queue_next, BMLoop *); + + BMFace *f; + BMIter iter; + BMLoop *l; + + unsigned int face_tot = 0; + + + BLI_LINKSTACK_INIT(loop_queue_prev); + BLI_LINKSTACK_INIT(loop_queue_next); + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG)) { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (bm_loop_is_all_radial_tag(l_iter) == false) { + BLI_LINKSTACK_PUSH(loop_queue_prev, l_iter); + } + } while ((l_iter = l_iter->next) != l_first); + } + } + + while (BLI_LINKSTACK_SIZE(loop_queue_prev)) { + while ((l = BLI_LINKSTACK_POP(loop_queue_prev))) { + /* check we're still un-assigned */ + if (BM_elem_flag_test(l->f, BM_ELEM_TAG)) { + BMLoop *l_iter; + + BM_elem_flag_disable(l->f, BM_ELEM_TAG); + + l_iter = l->next; + do { + BMLoop *l_radial_iter = l_iter->radial_next; + if (l_radial_iter != l_iter) { + do { + if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) { + BLI_LINKSTACK_PUSH(loop_queue_next, l_radial_iter); + } + } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter); + } + } while ((l_iter = l_iter->next) != l); + + /* do last because of face flipping */ + bm_face_copy_shared_all(bm, l, + use_normals, use_data); + face_tot += 1; + } + } + + BLI_LINKSTACK_SWAP(loop_queue_prev, loop_queue_next); + } + + BLI_LINKSTACK_FREE(loop_queue_prev); + BLI_LINKSTACK_FREE(loop_queue_next); + + return face_tot; +} + +void bmo_face_attribute_fill_exec(BMesh *bm, BMOperator *op) +{ + const bool use_normals = BMO_slot_bool_get(op->slots_in, "use_normals"); + const bool use_data = BMO_slot_bool_get(op->slots_in, "use_data"); + + int face_tot; + + BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); /* do inline */ + + /* now we can copy adjacent data */ + face_tot = bmesh_face_attribute_fill(bm, use_normals, use_data); + + if (face_tot != BMO_slot_buffer_count(op->slots_in, "faces")) { + /* any remaining tags will be skipped */ + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces_fail.out", BM_FACE, BM_ELEM_TAG); + } +} diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c index bd0466ff499..0fbaf5ff11a 100644 --- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c +++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c @@ -140,7 +140,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) BMFace *f; /* don't use calc_edges option because we already have the edges */ - f = BM_face_create_ngon_verts(bm, f_verts, i, 0, true, false); + f = BM_face_create_ngon_verts(bm, f_verts, i, NULL, BM_CREATE_NOP, true, false); BMO_elem_flag_enable(bm, f, ELE_OUT); f->mat_nr = mat_nr; if (use_smooth) { diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c index 7d4b780baf5..a4b1237bc5d 100644 --- a/source/blender/bmesh/operators/bmo_fill_grid.c +++ b/source/blender/bmesh/operators/bmo_fill_grid.c @@ -37,6 +37,8 @@ #include "intern/bmesh_operators_private.h" /* own include */ +#include "BLI_strict_flags.h" + #define EDGE_MARK 4 #define FACE_OUT 16 @@ -103,17 +105,130 @@ static void quad_verts_to_barycentric_tri( #endif +/* -------------------------------------------------------------------- */ +/* Handle Loop Pairs */ + +/** \name Loop Pairs + * \{ */ + +/** + * Assign a loop pair from 2 verts (which _must_ share an edge) + */ +static void bm_loop_pair_from_verts(BMVert *v_a, BMVert *v_b, + BMLoop *l_pair[2]) +{ + BMEdge *e = BM_edge_exists(v_a, v_b); + if (e->l) { + if (e->l->v == v_a) { + l_pair[0] = e->l; + l_pair[1] = e->l->next; + } + else { + l_pair[0] = e->l->next; + l_pair[1] = e->l; + } + } + else { + l_pair[0] = NULL; + l_pair[1] = NULL; + } +} + +/** + * Copy loop pair from one side to the other if either is missing, + * this simplifies interpolation code so we only need to check if x/y are missing, + * rather then checking each loop. + */ +static void bm_loop_pair_test_copy(BMLoop *l_pair_a[2], BMLoop *l_pair_b[2]) +{ + /* if the first one is set, we know the second is too */ + if (l_pair_a[0] && l_pair_b[0] == NULL) { + l_pair_b[0] = l_pair_a[1]; + l_pair_b[1] = l_pair_a[0]; + } + else if (l_pair_b[0] && l_pair_a[0] == NULL) { + l_pair_a[0] = l_pair_b[1]; + l_pair_a[1] = l_pair_b[0]; + } +} + +/** + * Interpolate from boundary loops. + * + * \note These weights will be calculated multiple times per vertex. + */ +static void bm_loop_interp_from_grid_boundary_4(BMesh *bm, BMLoop *l, BMLoop *l_bound[4], const float w[4]) +{ + void *l_cdata[4] = { + l_bound[0]->head.data, + l_bound[1]->head.data, + l_bound[2]->head.data, + l_bound[3]->head.data}; + + CustomData_bmesh_interp(&bm->ldata, l_cdata, w, NULL, 4, l->head.data); +} + +static void bm_loop_interp_from_grid_boundary_2(BMesh *bm, BMLoop *l, BMLoop *l_bound[2], const float t) +{ + + void *l_cdata[2] = { + l_bound[0]->head.data, + l_bound[1]->head.data}; + + const float w[2] = {1.0f - t, t}; + + CustomData_bmesh_interp(&bm->ldata, l_cdata, w, NULL, 2, l->head.data); +} + +/** \} */ + + +/** + * Avoids calling #barycentric_weights_v2_quad often by caching weights into an array. + */ +static void barycentric_weights_v2_grid_cache(const unsigned int xtot, const unsigned int ytot, + float (*weight_table)[4]) +{ + float x_step = 1.0f / (float)(xtot - 1); + float y_step = 1.0f / (float)(ytot - 1); + unsigned int i = 0; + float xy_fl[2]; + + unsigned int x, y; + for (y = 0; y < ytot; y++) { + xy_fl[1] = y_step * (float)y; + for (x = 0; x < xtot; x++) { + xy_fl[0] = x_step * (float)x; + { + const float cos[4][2] = { + {xy_fl[0], 0.0f}, + {0.0f, xy_fl[1]}, + {xy_fl[0], 1.0f}, + {1.0f, xy_fl[1]}}; + barycentric_weights_v2_quad(UNPACK4(cos), xy_fl, weight_table[i++]); + } + } + } +} + + /** * This may be useful outside the bmesh operator. * * \param v_grid 2d array of verts, all boundary verts must be set, we fill in the middle. */ -static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const int ytot, +static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const unsigned int xtot, unsigned const int ytot, const short mat_nr, const bool use_smooth, - const bool use_flip) + const bool use_flip, const bool use_interp_simple) { const bool use_vert_interp = CustomData_has_interp(&bm->vdata); - int x, y; + const bool use_loop_interp = CustomData_has_interp(&bm->ldata); + unsigned int x, y; + + /* for use_loop_interp */ + BMLoop *((*larr_x_a)[2]), *((*larr_x_b)[2]), *((*larr_y_a)[2]), *((*larr_y_b)[2]); + + float (*weight_table)[4]; #define XY(_x, _y) ((_x) + ((_y) * (xtot))) @@ -141,6 +256,39 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const true); #endif + if (use_interp_simple || use_vert_interp || use_loop_interp) { + weight_table = MEM_mallocN(sizeof(*weight_table) * (size_t)(xtot * ytot), __func__); + barycentric_weights_v2_grid_cache(xtot, ytot, weight_table); + } + else { + weight_table = NULL; + } + + + /* Store loops */ + if (use_loop_interp) { + /* x2 because each edge connects 2 loops */ + larr_x_a = MEM_mallocN(sizeof(*larr_x_a) * (xtot - 1), __func__); + larr_x_b = MEM_mallocN(sizeof(*larr_x_b) * (xtot - 1), __func__); + + larr_y_a = MEM_mallocN(sizeof(*larr_y_a) * (ytot - 1), __func__); + larr_y_b = MEM_mallocN(sizeof(*larr_y_b) * (ytot - 1), __func__); + + /* fill in the loops */ + for (x = 0; x < xtot - 1; x++) { + bm_loop_pair_from_verts(v_grid[XY(x, 0)], v_grid[XY(x + 1, 0)], larr_x_a[x]); + bm_loop_pair_from_verts(v_grid[XY(x, ytot - 1)], v_grid[XY(x + 1, ytot - 1)], larr_x_b[x]); + bm_loop_pair_test_copy(larr_x_a[x], larr_x_b[x]); + } + + for (y = 0; y < ytot - 1; y++) { + bm_loop_pair_from_verts(v_grid[XY(0, y)], v_grid[XY(0, y + 1)], larr_y_a[y]); + bm_loop_pair_from_verts(v_grid[XY(xtot - 1, y)], v_grid[XY(xtot - 1, y + 1)], larr_y_b[y]); + bm_loop_pair_test_copy(larr_y_a[y], larr_y_b[y]); + } + } + + /* Build Verts */ for (y = 1; y < ytot - 1; y++) { #ifdef BARYCENTRIC_INTERP @@ -162,7 +310,7 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const /* place the vertex */ #ifdef BARYCENTRIC_INTERP - { + if (use_interp_simple == false) { float co_a[3], co_b[3]; barycentric_transform( @@ -178,28 +326,34 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const interp_v3_v3v3(co, co_a, co_b, (float)y / ((float)ytot - 1)); } - -#else - interp_v3_v3v3( - co, - v_grid[x]->co, - v_grid[(xtot * ytot) + (x - xtot)]->co, - (float)y / ((float)ytot - 1)); + else #endif + { + const float *w = weight_table[XY(x, y)]; + + zero_v3(co); + madd_v3_v3fl(co, v_grid[XY(x, 0)]->co, w[0]); + madd_v3_v3fl(co, v_grid[XY(0, y)]->co, w[1]); + madd_v3_v3fl(co, v_grid[XY(x, ytot - 1)]->co, w[2]); + madd_v3_v3fl(co, v_grid[XY(xtot - 1, y)]->co, w[3]); + } - v = BM_vert_create(bm, co, NULL, 0); + v = BM_vert_create(bm, co, NULL, BM_CREATE_NOP); v_grid[(y * xtot) + x] = v; /* interpolate only along one axis, this could be changed * but from user pov gives predictable results since these are selected loop */ if (use_vert_interp) { - void *v_cdata[2] = { - v_grid[XY(x, 0)]->head.data, - v_grid[XY(x, (ytot - 1))]->head.data, + const float *w = weight_table[XY(x, y)]; + + void *v_cdata[4] = { + v_grid[XY(x, 0)]->head.data, + v_grid[XY(0, y)]->head.data, + v_grid[XY(x, ytot - 1)]->head.data, + v_grid[XY(xtot - 1, y)]->head.data, }; - const float t = (float)y / ((float)ytot - 1); - const float w[2] = {1.0f - t, t}; - CustomData_bmesh_interp(&bm->vdata, v_cdata, w, NULL, 2, v->head.data); + + CustomData_bmesh_interp(&bm->vdata, v_cdata, w, NULL, 4, v->head.data); } } @@ -218,7 +372,7 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const v_grid[XY(x + 1, y + 1)], /* TR */ v_grid[XY(x + 1, y + 0)], /* BR */ NULL, - false); + BM_CREATE_NOP); } else { f = BM_face_create_quad_tri( @@ -228,8 +382,88 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const v_grid[XY(x, y + 1)], /* TL */ v_grid[XY(x, y + 0)], /* BL */ NULL, - false); + BM_CREATE_NOP); + } + + + if (use_loop_interp && (larr_x_a[x][0] || larr_y_a[y][0])) { + /* bottom/left/top/right */ + BMLoop *l_quad[4]; + BMLoop *l_bound[4]; + BMLoop *l_tmp; + unsigned int x_side, y_side, i; + char interp_from; + + + if (larr_x_a[x][0] && larr_y_a[y][0]) { + interp_from = 'B'; /* B == both */ + l_tmp = larr_x_a[x][0]; + } + else if (larr_x_a[x][0]) { + interp_from = 'X'; + l_tmp = larr_x_a[x][0]; + } + else { + interp_from = 'Y'; + l_tmp = larr_y_a[y][0]; + } + + BM_elem_attrs_copy(bm, bm, l_tmp->f, f); + + + BM_face_as_array_loop_quad(f, l_quad); + + l_tmp = BM_FACE_FIRST_LOOP(f); + + if (use_flip) { + l_quad[0] = l_tmp; l_tmp = l_tmp->next; + l_quad[1] = l_tmp; l_tmp = l_tmp->next; + l_quad[3] = l_tmp; l_tmp = l_tmp->next; + l_quad[2] = l_tmp; + } + else { + l_quad[2] = l_tmp; l_tmp = l_tmp->next; + l_quad[3] = l_tmp; l_tmp = l_tmp->next; + l_quad[1] = l_tmp; l_tmp = l_tmp->next; + l_quad[0] = l_tmp; + } + + i = 0; + + for (x_side = 0; x_side < 2; x_side++) { + for (y_side = 0; y_side < 2; y_side++) { + if (interp_from == 'B') { + const float *w = weight_table[XY(x + x_side, y + y_side)]; + l_bound[0] = larr_x_a[x][x_side]; /* B */ + l_bound[1] = larr_y_a[y][y_side]; /* L */ + l_bound[2] = larr_x_b[x][x_side]; /* T */ + l_bound[3] = larr_y_b[y][y_side]; /* R */ + + bm_loop_interp_from_grid_boundary_4(bm, l_quad[i++], l_bound, w); + } + else if (interp_from == 'X') { + const float t = (float)(y + y_side) / (float)(ytot - 1); + l_bound[0] = larr_x_a[x][x_side]; /* B */ + l_bound[1] = larr_x_b[x][x_side]; /* T */ + + bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, t); + } + else if (interp_from == 'Y') { + const float t = (float)(x + x_side) / (float)(xtot - 1); + l_bound[0] = larr_y_a[y][y_side]; /* L */ + l_bound[1] = larr_y_b[y][y_side]; /* R */ + + bm_loop_interp_from_grid_boundary_2(bm, l_quad[i++], l_bound, t); + } + else { + BLI_assert(0); + } + } + } } + /* end interp */ + + BMO_elem_flag_enable(bm, f, FACE_OUT); f->mat_nr = mat_nr; if (use_smooth) { @@ -237,22 +471,34 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const int xtot, const } } } + + if (use_loop_interp) { + MEM_freeN(larr_x_a); + MEM_freeN(larr_y_a); + MEM_freeN(larr_x_b); + MEM_freeN(larr_y_b); + } + + if (weight_table) { + MEM_freeN(weight_table); + } + #undef XY } static void bm_grid_fill(BMesh *bm, struct BMEdgeLoopStore *estore_a, struct BMEdgeLoopStore *estore_b, struct BMEdgeLoopStore *estore_rail_a, struct BMEdgeLoopStore *estore_rail_b, - const short mat_nr, const bool use_smooth) + const short mat_nr, const bool use_smooth, const bool use_interp_simple) { #define USE_FLIP_DETECT - const int xtot = BM_edgeloop_length_get(estore_a); - const int ytot = BM_edgeloop_length_get(estore_rail_a); + const unsigned int xtot = (unsigned int)BM_edgeloop_length_get(estore_a); + const unsigned int ytot = (unsigned int)BM_edgeloop_length_get(estore_rail_a); //BMVert *v; - int i; + unsigned int i; #ifdef DEBUG - int x, y; + unsigned int x, y; #endif LinkData *el; bool use_flip = false; @@ -263,7 +509,7 @@ static void bm_grid_fill(BMesh *bm, ListBase *lb_rail_a = BM_edgeloop_verts_get(estore_rail_a); ListBase *lb_rail_b = BM_edgeloop_verts_get(estore_rail_b); - BMVert **v_grid = MEM_callocN(sizeof(BMVert *) * xtot * ytot, __func__); + BMVert **v_grid = MEM_callocN(sizeof(BMVert *) * (size_t)(xtot * ytot), __func__); /** * <pre> * estore_b @@ -314,7 +560,7 @@ static void bm_grid_fill(BMesh *bm, #endif - bm_grid_fill_array(bm, v_grid, xtot, ytot, mat_nr, use_smooth, use_flip); + bm_grid_fill_array(bm, v_grid, xtot, ytot, mat_nr, use_smooth, use_flip, use_interp_simple); MEM_freeN(v_grid); #undef USE_FLIP_DETECT @@ -322,7 +568,7 @@ static void bm_grid_fill(BMesh *bm, static bool bm_edge_test_cb(BMEdge *e, void *bm_v) { - return BMO_elem_flag_test((BMesh *)bm_v, e, EDGE_MARK); + return BMO_elem_flag_test_bool((BMesh *)bm_v, e, EDGE_MARK); } static bool bm_edge_test_rail_cb(BMEdge *e, void *UNUSED(bm_v)) @@ -343,8 +589,9 @@ void bmo_grid_fill_exec(BMesh *bm, BMOperator *op) struct BMEdgeLoopStore *estore_rail_a, *estore_rail_b; BMVert *v_a_first, *v_a_last; BMVert *v_b_first, *v_b_last; - const short mat_nr = BMO_slot_int_get(op->slots_in, "mat_nr"); - const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); + const short mat_nr = (short)BMO_slot_int_get(op->slots_in, "mat_nr"); + const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth"); + const bool use_interp_simple = BMO_slot_bool_get(op->slots_in, "use_interp_simple"); int count; bool change = false; @@ -436,9 +683,11 @@ void bmo_grid_fill_exec(BMesh *bm, BMOperator *op) /* finally we have all edge loops needed */ bm_grid_fill(bm, estore_a, estore_b, estore_rail_a, estore_rail_b, - mat_nr, use_smooth); + mat_nr, use_smooth, use_interp_simple); change = true; + + cleanup: BM_mesh_edgeloops_free(&eloops); BM_mesh_edgeloops_free(&eloops_rail); diff --git a/source/blender/bmesh/operators/bmo_fill_holes.c b/source/blender/bmesh/operators/bmo_fill_holes.c index 40a682e790d..8160d28d7a7 100644 --- a/source/blender/bmesh/operators/bmo_fill_holes.c +++ b/source/blender/bmesh/operators/bmo_fill_holes.c @@ -28,110 +28,58 @@ #include "MEM_guardedalloc.h" -#include "BLI_listbase.h" -#include "BLI_alloca.h" -#include "BLI_math.h" +#include "BLI_utildefines.h" #include "bmesh.h" +#include "bmesh_tools.h" #include "intern/bmesh_operators_private.h" /* own include */ -#define EDGE_MARK 2 -#define ELE_OUT 4 - -/** - * Clone of BM_face_find_longest_loop that ensures the loop has an adjacent face - */ -static BMLoop *bm_face_find_longest_loop_manifold(BMFace *f) -{ - BMLoop *longest_loop = NULL; - float longest_len = 0.0f; - BMLoop *l_iter, *l_first; - - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - - do { - if (BM_edge_is_wire(l_iter->e) == false) { - const float len = len_squared_v3v3(l_iter->v->co, l_iter->next->v->co); - if (len >= longest_len) { - longest_loop = l_iter; - longest_len = len; - } - } - } while ((l_iter = l_iter->next) != l_first); - - return longest_loop; -} - -static BMFace *bm_face_from_eloop(BMesh *bm, struct BMEdgeLoopStore *el_store) -{ - LinkData *node = BM_edgeloop_verts_get(el_store)->first; - const int len = BM_edgeloop_length_get(el_store); - BMVert **f_verts = BLI_array_alloca(f_verts, len); - BMFace *f; - BMLoop *l; - unsigned int i = 0; - - do { - f_verts[i++] = node->data; - } while ((node = node->next)); - - f = BM_face_create_ngon_verts(bm, f_verts, len, 0, true, false); - BM_face_copy_shared(bm, f); - - l = bm_face_find_longest_loop_manifold(f); - if (l) { - BMFace *f_other = l->radial_next->f; - BLI_assert(l->radial_next != l); - BM_elem_attrs_copy(bm, bm, f_other, f); - } - - return f; -} - -static bool bm_edge_test_cb(BMEdge *e, void *bm_v) -{ - return BMO_elem_flag_test((BMesh *)bm_v, e, EDGE_MARK); -} - void bmo_holes_fill_exec(BMesh *bm, BMOperator *op) { - ListBase eloops = {NULL, NULL}; - LinkData *el_store; + BMOperator op_attr; + const unsigned int sides = BMO_slot_int_get(op->slots_in, "sides"); - BMEdge *e; - int count; - BMOIter siter; + BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "edges", BM_EDGE, BM_ELEM_TAG, false); - const int sides = BMO_slot_int_get(op->slots_in, "sides"); + BM_mesh_edgenet(bm, true, true); // TODO, sides - /* clear tags */ - BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); + /* bad - remove faces after as a workaround */ + if (sides != 0) { + BMOIter siter; + BMFace *f; - /* tag edges that may be apart of loops */ - BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - BMO_elem_flag_set(bm, e, EDGE_MARK, BM_edge_is_boundary(e)); + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); + BMO_ITER (f, &siter, op->slots_out, "faces.out", BM_FACE) { + if (f->len > sides) { + BM_face_kill(bm, f); + } + } } - count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_cb, (void *)bm); + BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); - for (el_store = eloops.first; el_store; el_store = el_store->next) { - if (BM_edgeloop_is_closed((struct BMEdgeLoopStore *)el_store)) { - const int len = BM_edgeloop_length_get((struct BMEdgeLoopStore *)el_store); - if ((sides == 0) || (len <= sides)) { - BMFace *f; + /* --- Attribute Fill --- */ + /* may as well since we have the faces already in a buffer */ + BMO_op_initf(bm, &op_attr, op->flag, + "face_attribute_fill faces=%S use_normals=%b use_data=%b", + op, "faces.out", true, true); - f = bm_face_from_eloop(bm, (struct BMEdgeLoopStore *)el_store); - BMO_elem_flag_enable(bm, f, ELE_OUT); - } - } - } + BMO_op_exec(bm, &op_attr); - (void)count; + /* check if some faces couldn't be touched */ + if (BMO_slot_buffer_count(op_attr.slots_out, "faces_fail.out")) { + BMOIter siter; + BMFace *f; - BM_mesh_edgeloops_free(&eloops); + BMO_ITER (f, &siter, op_attr.slots_out, "faces_fail.out", BM_FACE) { + BM_face_normal_update(f); /* normals are zero'd */ + } - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_OUT); + BMO_op_callf(bm, op->flag, "recalc_face_normals faces=%S", &op_attr, "faces_fail.out"); + } + BMO_op_finish(bm, &op_attr); } diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c index 500e984f4c9..1737e27c84a 100644 --- a/source/blender/bmesh/operators/bmo_hull.c +++ b/source/blender/bmesh/operators/bmo_hull.c @@ -67,7 +67,7 @@ typedef struct HullTriangle { /*************************** Hull Triangles ***************************/ -static void hull_add_triangle(BMesh *bm, GHash *hull_triangles, BLI_mempool *pool, +static void hull_add_triangle(BMesh *bm, GSet *hull_triangles, BLI_mempool *pool, BMVert *v1, BMVert *v2, BMVert *v3) { HullTriangle *t; @@ -82,7 +82,7 @@ static void hull_add_triangle(BMesh *bm, GHash *hull_triangles, BLI_mempool *poo for (i = 0; i < 3; i++) BMO_elem_flag_disable(bm, t->v[i], HULL_FLAG_INTERIOR_ELE); - BLI_ghash_insert(hull_triangles, t, NULL); + BLI_gset_insert(hull_triangles, t); normal_tri_v3(t->no, v1->co, v2->co, v3->co); } @@ -102,12 +102,12 @@ static BMFace *hull_find_example_face(BMesh *bm, BMEdge *e) return NULL; } -static void hull_output_triangles(BMesh *bm, GHash *hull_triangles) +static void hull_output_triangles(BMesh *bm, GSet *hull_triangles) { - GHashIterator iter; + GSetIterator iter; - GHASH_ITER (iter, hull_triangles) { - HullTriangle *t = BLI_ghashIterator_getKey(&iter); + GSET_ITER (iter, hull_triangles) { + HullTriangle *t = BLI_gsetIterator_getKey(&iter); int i; if (!t->skip) { @@ -135,8 +135,8 @@ static void hull_output_triangles(BMesh *bm, GHash *hull_triangles) } /* Create new hull face */ - f = BM_face_create_quad_tri_v(bm, t->v, 3, example, true); - BM_face_copy_shared(bm, f); + f = BM_face_create_verts(bm, t->v, 3, example, BM_CREATE_NO_DOUBLE, true); + BM_face_copy_shared(bm, f, NULL, NULL); } /* Mark face for 'geom.out' slot and select */ BMO_elem_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM); @@ -206,22 +206,22 @@ static int hull_final_edges_lookup(HullFinalEdges *final_edges, } /* Used for checking whether a pre-existing edge lies on the hull */ -static HullFinalEdges *hull_final_edges(GHash *hull_triangles) +static HullFinalEdges *hull_final_edges(GSet *hull_triangles) { HullFinalEdges *final_edges; - GHashIterator iter; + GSetIterator iter; final_edges = MEM_callocN(sizeof(HullFinalEdges), "HullFinalEdges"); final_edges->edges = BLI_ghash_ptr_new("final edges ghash"); final_edges->base_pool = BLI_mempool_create(sizeof(ListBase), 128, 128, 0); final_edges->link_pool = BLI_mempool_create(sizeof(LinkData), 128, 128, 0); - GHASH_ITER (iter, hull_triangles) { + GSET_ITER (iter, hull_triangles) { LinkData *link; int i; for (i = 0; i < 3; i++) { - HullTriangle *t = BLI_ghashIterator_getKey(&iter); + HullTriangle *t = BLI_gsetIterator_getKey(&iter); BMVert *v1 = t->v[i]; BMVert *v2 = t->v[(i + 1) % 3]; ListBase *adj; @@ -259,13 +259,13 @@ static void hull_final_edges_free(HullFinalEdges *final_edges) /**************************** Final Output ****************************/ -static void hull_remove_overlapping(BMesh *bm, GHash *hull_triangles, +static void hull_remove_overlapping(BMesh *bm, GSet *hull_triangles, HullFinalEdges *final_edges) { - GHashIterator hull_iter; + GSetIterator hull_iter; - GHASH_ITER (hull_iter, hull_triangles) { - HullTriangle *t = BLI_ghashIterator_getKey(&hull_iter); + GSET_ITER (hull_iter, hull_triangles) { + HullTriangle *t = BLI_gsetIterator_getKey(&hull_iter); BMIter bm_iter1, bm_iter2; BMFace *f; bool f_on_hull; @@ -444,7 +444,7 @@ static BMVert **hull_input_verts_copy(BMOperator *op, static float (*hull_verts_for_bullet(BMVert **input_verts, const int num_input_verts))[3] { - float (*coords)[3] = MEM_callocN(sizeof(*coords) * num_input_verts, AT); + float (*coords)[3] = MEM_callocN(sizeof(*coords) * num_input_verts, __func__); int i; for (i = 0; i < num_input_verts; i++) { @@ -479,7 +479,7 @@ static BMVert **hull_verts_from_bullet(plConvexHull hull, } static void hull_from_bullet(BMesh *bm, BMOperator *op, - GHash *hull_triangles, + GSet *hull_triangles, BLI_mempool *pool) { int *fvi = NULL; @@ -556,7 +556,7 @@ void bmo_convex_hull_exec(BMesh *bm, BMOperator *op) BLI_mempool *hull_pool; BMElemF *ele; BMOIter oiter; - GHash *hull_triangles; + GSet *hull_triangles; /* Verify that at least three verts in the input */ if (!hull_num_input_verts_is_ok(op)) { @@ -575,7 +575,7 @@ void bmo_convex_hull_exec(BMesh *bm, BMOperator *op) } hull_pool = BLI_mempool_create(sizeof(HullTriangle), 128, 128, 0); - hull_triangles = BLI_ghash_ptr_new("hull_triangles"); + hull_triangles = BLI_gset_ptr_new("hull_triangles"); hull_from_bullet(bm, op, hull_triangles, hull_pool); @@ -597,7 +597,7 @@ void bmo_convex_hull_exec(BMesh *bm, BMOperator *op) hull_output_triangles(bm, hull_triangles); BLI_mempool_destroy(hull_pool); - BLI_ghash_free(hull_triangles, NULL, NULL); + BLI_gset_free(hull_triangles, NULL); hull_tag_unused(bm, op); diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c index a7b98cda2b3..20cd828af1e 100644 --- a/source/blender/bmesh/operators/bmo_inset.c +++ b/source/blender/bmesh/operators/bmo_inset.c @@ -32,6 +32,7 @@ #include "BLI_math.h" #include "BLI_array.h" +#include "BLI_alloca.h" #include "BLI_memarena.h" #include "BKE_customdata.h" @@ -42,199 +43,263 @@ #define ELE_NEW 1 - /* -------------------------------------------------------------------- */ -/* Inset Individual */ - - -/* Holds Per-Face Inset Edge Data */ -typedef struct EdgeInsetInfo { - float no[3]; - BMEdge *e_old; - BMEdge *e_new; -} EdgeInsetInfo; +/* Generic Interp Face (use for both types of inset) */ /** - * Individual Face Inset. - * Find all tagged faces (f), duplicate edges around faces, inset verts of - * created edges, create new faces between old and new edges, fill face - * between connected new edges, kill old face (f). - */ -void bmo_inset_individual_exec(BMesh *bm, BMOperator *op) -{ - BMEdge **f_edges = NULL; - BMVert **f_verts = NULL; + * Interpolation, this is more complex for regions since we're not creating new faces + * and throwing away old ones, so instead, store face data needed for interpolation. + * + * \note This uses CustomData functions in quite a low-level way which should be + * avoided, but in this case its hard to do without storing a duplicate mesh. */ + +/* just enough of a face to store interpolation data we can use once the inset is done */ +typedef struct InterpFace { BMFace *f; + void **blocks_l; + void **blocks_v; + float (*cos_2d)[2]; + float axis_mat[3][3]; +} InterpFace; - BMOIter oiter; - EdgeInsetInfo *eiinfo_arr = NULL; +/* basically a clone of #BM_vert_interp_from_face */ +static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemArena *interp_arena) +{ + BMLoop *l_iter, *l_first; + void **blocks_l = iface->blocks_l = BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks_l) * f->len); + void **blocks_v = iface->blocks_v = BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks_v) * f->len); + float (*cos_2d)[2] = iface->cos_2d = BLI_memarena_alloc(interp_arena, sizeof(*iface->cos_2d) * f->len); + void *axis_mat = iface->axis_mat; + int i; - BLI_array_declare(eiinfo_arr); - BLI_array_declare(f_edges); - BLI_array_declare(f_verts); + BLI_assert(BM_face_is_normal_valid(f)); - const float thickness = BMO_slot_float_get(op->slots_in, "thickness"); - const float depth = BMO_slot_float_get(op->slots_in, "depth"); - const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset"); - const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); - const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate"); + axis_dominant_v3_to_m3(axis_mat, f->no); - /* Only tag faces in slot */ - BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); + iface->f = f; - BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); + i = 0; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co); + blocks_l[i] = NULL; + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_iter->head.data, &blocks_l[i]); + /* if we were not modifying the loops later we would do... */ + // blocks[i] = l_iter->head.data; - BMO_ITER(f, &oiter, op->slots_in, "faces", BM_FACE) { - BMFace *f_new_inner; - BMLoop *l_iter, *l_first; - BMLoop *l_iter_inner = NULL; - int i; - - BLI_array_empty(f_verts); - BLI_array_empty(f_edges); - BLI_array_empty(eiinfo_arr); - BLI_array_grow_items(f_verts, f->len); - BLI_array_grow_items(f_edges, f->len); - BLI_array_grow_items(eiinfo_arr, f->len); - - /* create verts */ - i = 0; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - f_verts[i] = BM_vert_create(bm, l_iter->v->co, l_iter->v, 0); - i++; - } while ((l_iter = l_iter->next) != l_first); + blocks_v[i] = NULL; + CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, l_iter->v->head.data, &blocks_v[i]); - /* make edges */ - i = 0; - l_iter = l_first; - do { - f_edges[i] = BM_edge_create(bm, f_verts[i], f_verts[(i + 1) % f->len], l_iter->e, 0); + /* use later for index lookups */ + BM_elem_index_set(l_iter, i); /* set_ok */ + } while (i++, (l_iter = l_iter->next) != l_first); +} +static void bm_interp_face_free(InterpFace *iface, BMesh *bm) +{ + void **blocks_l = iface->blocks_l; + void **blocks_v = iface->blocks_v; + int i; - eiinfo_arr[i].e_new = f_edges[i]; - eiinfo_arr[i].e_old = l_iter->e; - BM_edge_calc_face_tangent(l_iter->e, l_iter, eiinfo_arr[i].no); + for (i = 0; i < iface->f->len; i++) { + CustomData_bmesh_free_block(&bm->ldata, &blocks_l[i]); + CustomData_bmesh_free_block(&bm->vdata, &blocks_v[i]); + } +} - /* Tagging (old elements) required when iterating over edges - * connected to verts for translation vector calculation */ - BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG); - BM_elem_index_set(l_iter->e, i); /* set_dirty! */ - i++; - } while ((l_iter = l_iter->next) != l_first); - /* done with edges */ - bm->elem_index_dirty |= BM_EDGE; +/* -------------------------------------------------------------------- */ +/* Inset Individual */ - /* Calculate translation vector for new */ - l_iter = l_first; - do { - EdgeInsetInfo *ei_prev = &eiinfo_arr[BM_elem_index_get(l_iter->prev->e)]; - EdgeInsetInfo *ei_next = &eiinfo_arr[BM_elem_index_get(l_iter->e)]; - float tvec[3]; - float v_new_co[3]; - int index = 0; +static void bmo_face_inset_individual( + BMesh *bm, BMFace *f, MemArena *interp_arena, + const float thickness, const float depth, + const bool use_even_offset, const bool use_relative_offset, const bool use_interpolate) +{ + InterpFace *iface = NULL; - add_v3_v3v3(tvec, ei_prev->no, ei_next->no); - normalize_v3(tvec); + /* stores verts split away from the face (aligned with face verts) */ + BMVert **verts = BLI_array_alloca(verts, f->len); + /* store edge normals (aligned with face-loop-edges) */ + float (*edge_nors)[3] = BLI_array_alloca(edge_nors, f->len); + float (*coords)[3] = BLI_array_alloca(coords, f->len); - /* l->e is traversed in order */ - index = BM_elem_index_get(l_iter->e); + BMLoop *l_iter, *l_first; + BMLoop *l_other; + unsigned int i; + float e_length_prev; - copy_v3_v3(v_new_co, eiinfo_arr[index].e_new->v1->co); + l_first = BM_FACE_FIRST_LOOP(f); - if (use_even_offset) { - mul_v3_fl(tvec, shell_angle_to_dist(angle_normalized_v3v3(ei_prev->no, ei_next->no) / 2.0f)); - } + /* split off all loops */ + l_iter = l_first; + i = 0; + do { + BMVert *v_other = l_iter->v; + BMVert *v_sep = BM_face_loop_separate(bm, l_iter); + if (v_sep == v_other) { + v_other = BM_vert_create(bm, l_iter->v->co, l_iter->v, BM_CREATE_NOP); + } + verts[i] = v_other; - /* Modify vertices and their normals */ - if (use_relative_offset) { - mul_v3_fl(tvec, (BM_edge_calc_length(l_iter->e) + BM_edge_calc_length(l_iter->prev->e)) / 2.0f); - } + /* unrelated to splitting, but calc here */ + BM_edge_calc_face_tangent(l_iter->e, l_iter, edge_nors[i]); + } while (i++, ((l_iter = l_iter->next) != l_first)); - madd_v3_v3fl(v_new_co, tvec, thickness); - /* Set normal, add depth and write new vertex position*/ - copy_v3_v3(eiinfo_arr[index].e_new->v1->no, f->no); + /* build rim faces */ + l_iter = l_first; + i = 0; + do { + BMFace *f_new_outer; + BMVert *v_other = verts[i]; + BMVert *v_other_next = verts[(i + 1) % f->len]; + + BMEdge *e_other = BM_edge_create(bm, v_other, v_other_next, l_iter->e, BM_CREATE_NO_DOUBLE); + (void)e_other; + + f_new_outer = BM_face_create_quad_tri(bm, + v_other, + v_other_next, + l_iter->next->v, + l_iter->v, + f, BM_CREATE_NOP); + BMO_elem_flag_enable(bm, f_new_outer, ELE_NEW); + + /* copy loop data */ + l_other = l_iter->radial_next; + BM_elem_attrs_copy(bm, bm, l_iter->next, l_other->prev); + BM_elem_attrs_copy(bm, bm, l_iter, l_other->next->next); + + if (use_interpolate == false) { + BM_elem_attrs_copy(bm, bm, l_iter->next, l_other); + BM_elem_attrs_copy(bm, bm, l_iter, l_other->next); + } + } while (i++, ((l_iter = l_iter->next) != l_first)); - madd_v3_v3fl(v_new_co, f->no, depth); + /* hold interpolation values */ + if (use_interpolate) { + iface = BLI_memarena_alloc(interp_arena, sizeof(*iface)); + bm_interp_face_store(iface, bm, f, interp_arena); + } - copy_v3_v3(eiinfo_arr[index].e_new->v1->co, v_new_co); - } while ((l_iter = l_iter->next) != l_first); + /* Calculate translation vector for new */ + l_iter = l_first; + i = 0; + if (depth != 0.0f) { + e_length_prev = BM_edge_calc_length(l_iter->prev->e); + } - /* Create New Inset Faces */ - f_new_inner = BM_face_create(bm, f_verts, f_edges, f->len, 0); - BLI_assert(f_new_inner != NULL); /* no reason it should fail */ + do { + const float *eno_prev = edge_nors[(i ? i : f->len) - 1]; + const float *eno_next = edge_nors[i]; + float tvec[3]; + float v_new_co[3]; + add_v3_v3v3(tvec, eno_prev, eno_next); + normalize_v3(tvec); - // Don't tag, gives more useful inner/outer select option - // BMO_elem_flag_enable(bm, f_new_inner, ELE_NEW); + copy_v3_v3(v_new_co, l_iter->v->co); + if (use_even_offset) { + mul_v3_fl(tvec, shell_angle_to_dist(angle_normalized_v3v3(eno_prev, eno_next) / 2.0f)); + } - /* Copy Face Data */ - /* interpolate loop data or just stretch */ - if (use_interpolate) { - BM_face_interp_from_face(bm, f_new_inner, f, true); + /* Modify vertices and their normals */ + if (use_relative_offset) { + mul_v3_fl(tvec, (BM_edge_calc_length(l_iter->e) + BM_edge_calc_length(l_iter->prev->e)) / 2.0f); } - else { - BM_elem_attrs_copy(bm, bm, f, f_new_inner); + + madd_v3_v3fl(v_new_co, tvec, thickness); + + /* Set normal, add depth and write new vertex position*/ + copy_v3_v3(l_iter->v->no, f->no); + + if (depth != 0.0f) { + const float e_length = BM_edge_calc_length(l_iter->e); + const float fac = depth * (use_relative_offset ? ((e_length_prev + e_length) * 0.5f) : 1.0f); + e_length_prev = e_length; + + madd_v3_v3fl(v_new_co, f->no, fac); } - l_iter_inner = BM_FACE_FIRST_LOOP(f_new_inner); + + + copy_v3_v3(coords[i], v_new_co); + } while (i++, ((l_iter = l_iter->next) != l_first)); + + /* update the coords */ + l_iter = l_first; + i = 0; + do { + copy_v3_v3(l_iter->v->co, coords[i]); + } while (i++, ((l_iter = l_iter->next) != l_first)); + + + if (use_interpolate) { + BM_face_interp_from_face_ex(bm, iface->f, iface->f, true, + iface->blocks_l, iface->blocks_v, iface->cos_2d, iface->axis_mat); + + /* build rim faces */ l_iter = l_first; do { - BMFace *f_new_outer; + /* copy loop data */ + l_other = l_iter->radial_next; - BMLoop *l_a; - BMLoop *l_b; - - if (use_interpolate == false) { - BM_elem_attrs_copy(bm, bm, l_iter, l_iter_inner); - } + BM_elem_attrs_copy(bm, bm, l_iter->next, l_other); + BM_elem_attrs_copy(bm, bm, l_iter, l_other->next); + } while ((l_iter = l_iter->next) != l_first); - f_new_outer = BM_face_create_quad_tri(bm, - l_iter->v, - l_iter->next->v, - l_iter_inner->next->v, - l_iter_inner->v, - f, false); + bm_interp_face_free(iface, bm); + } +} - BLI_assert(f_new_outer != NULL); /* no reason it should fail */ - BM_elem_attrs_copy(bm, bm, f, f_new_outer); - BMO_elem_flag_enable(bm, f_new_outer, ELE_NEW); - BM_elem_flag_enable(f_new_outer, BM_ELEM_TAG); +/** + * Individual Face Inset. + * Find all tagged faces (f), duplicate edges around faces, inset verts of + * created edges, create new faces between old and new edges, fill face + * between connected new edges, kill old face (f). + */ +void bmo_inset_individual_exec(BMesh *bm, BMOperator *op) +{ + BMFace *f; - /* Copy Loop Data */ - l_a = BM_FACE_FIRST_LOOP(f_new_outer); - l_b = l_a->next; + BMOIter oiter; + MemArena *interp_arena = NULL; - /* first pair */ - BM_elem_attrs_copy(bm, bm, l_iter, l_a); - BM_elem_attrs_copy(bm, bm, l_iter->next, l_b); + const float thickness = BMO_slot_float_get(op->slots_in, "thickness"); + const float depth = BMO_slot_float_get(op->slots_in, "depth"); + const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset"); + const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); + const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate"); + /* Only tag faces in slot */ + BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - /* Move to the last two loops in new face */ - l_a = l_b->next; - l_b = l_a->next; + BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false); - /* This loop should always have >1 radials - * (associated edge connects new and old face) */ - BM_elem_attrs_copy(bm, bm, l_iter_inner, l_b); - BM_elem_attrs_copy(bm, bm, use_interpolate ? l_iter_inner->next : l_iter->next, l_a); + if (use_interpolate) { + interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + } - } while ((l_iter_inner = l_iter_inner->next), - (l_iter = l_iter->next) != l_first); + BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) { + bmo_face_inset_individual( + bm, f, interp_arena, + thickness, depth, + use_even_offset, use_relative_offset, use_interpolate); - BM_face_kill(bm, f); + if (use_interpolate) { + BLI_memarena_clear(interp_arena); + } } /* we could flag new edges/verts too, is it useful? */ BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW); - BLI_array_free(f_verts); - BLI_array_free(f_edges); - BLI_array_free(eiinfo_arr); + if (use_interpolate) { + BLI_memarena_free(interp_arena); + } } @@ -250,68 +315,6 @@ typedef struct SplitEdgeInfo { BMLoop *l; } SplitEdgeInfo; - -/** - * Interpolation, this is more complex for regions since we're not creating new faces - * and throwing away old ones, so instead, store face data needed for interpolation. - * - * \note This uses CustomData functions in quite a low-level way which should be - * avoided, but in this case its hard to do without storing a duplicate mesh. */ - -/* just enough of a face to store interpolation data we can use once the inset is done */ -typedef struct InterpFace { - BMFace *f; - void **blocks_l; - void **blocks_v; - float (*cos_2d)[2]; - float axis_mat[3][3]; -} InterpFace; - -/* basically a clone of #BM_vert_interp_from_face */ -static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemArena *interp_arena) -{ - BMLoop *l_iter, *l_first; - void **blocks_l = iface->blocks_l = BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks_l) * f->len); - void **blocks_v = iface->blocks_v = BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks_v) * f->len); - float (*cos_2d)[2] = iface->cos_2d = BLI_memarena_alloc(interp_arena, sizeof(*iface->cos_2d) * f->len); - void *axis_mat = iface->axis_mat; - int i; - - BLI_assert(BM_face_is_normal_valid(f)); - - axis_dominant_v3_to_m3(axis_mat, f->no); - - iface->f = f; - - i = 0; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co); - blocks_l[i] = NULL; - CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_iter->head.data, &blocks_l[i]); - /* if we were not modifying the loops later we would do... */ - // blocks[i] = l_iter->head.data; - - blocks_v[i] = NULL; - CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, l_iter->v->head.data, &blocks_v[i]); - - /* use later for index lookups */ - BM_elem_index_set(l_iter, i); /* set_ok */ - } while (i++, (l_iter = l_iter->next) != l_first); -} -static void bm_interp_face_free(InterpFace *iface, BMesh *bm) -{ - void **blocks_l = iface->blocks_l; - void **blocks_v = iface->blocks_v; - int i; - - for (i = 0; i < iface->f->len; i++) { - CustomData_bmesh_free_block(&bm->ldata, &blocks_l[i]); - CustomData_bmesh_free_block(&bm->vdata, &blocks_v[i]); - } -} - - /** * return the tag loop where there is... * - only 1 tagged face attached to this edge. @@ -350,6 +353,27 @@ static BMLoop *bm_edge_is_mixed_face_tag(BMLoop *l) } } +static float bm_edge_info_average_length(BMVert *v, SplitEdgeInfo *edge_info) +{ + BMIter iter; + BMEdge *e; + + float len = 0.0f; + int tot = 0; + + + BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { + const int i = BM_elem_index_get(e); + if (i != -1) { + len += edge_info[i].length; + tot++; + } + } + + BLI_assert(tot != 0); + return len / (float)tot; +} + /** * implementation is as follows... * @@ -465,7 +489,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) if (es->e_new == es->e_old) { /* happens on boundary edges */ /* take care here, we're creating this double edge which _must_ have its verts replaced later on */ - es->e_old = BM_edge_create(bm, es->e_new->v1, es->e_new->v2, es->e_new, 0); + es->e_old = BM_edge_create(bm, es->e_new->v1, es->e_new->v2, es->e_new, BM_CREATE_NOP); } /* store index back to original in 'edge_info' */ @@ -508,8 +532,8 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) mid_v3_v3v3(tvec, es->e_new->v1->co, es->e_new->v2->co); - v1 = BM_vert_create(bm, tvec, NULL); - v2 = BM_vert_create(bm, tvec, NULL); + v1 = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP); + v2 = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP); madd_v3_v3fl(v2->co, es->no, 0.1f); BM_edge_create(bm, v1, v2, NULL, 0); } @@ -787,7 +811,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) #endif /* no need to check doubles, we KNOW there won't be any */ /* yes - reverse face is correct in this case */ - f = BM_face_create_quad_tri_v(bm, varr, j, es->l->f, false); + f = BM_face_create_verts(bm, varr, j, es->l->f, BM_CREATE_NOP, true); BMO_elem_flag_enable(bm, f, ELE_NEW); /* copy for loop data, otherwise UV's and vcols are no good. @@ -796,7 +820,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) #if 0 /* don't use this because face boundaries have no adjacent loops and won't be filled in. * instead copy from the opposite side with the code below */ - BM_face_copy_shared(bm, f); + BM_face_copy_shared(bm, f, NULL, NULL); #else { /* 2 inner loops on the edge between the new face and the original */ @@ -894,7 +918,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { const float fac = (depth * - (use_relative_offset ? BM_vert_calc_mean_tagged_edge_length(v) : 1.0f) * + (use_relative_offset ? bm_edge_info_average_length(v, edge_info) : 1.0f) * (use_even_boundry ? BM_vert_calc_shell_factor(v) : 1.0f)); madd_v3_v3v3fl(varr_co[i], v->co, v->no, fac); } diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c index 12065743136..6562f26062f 100644 --- a/source/blender/bmesh/operators/bmo_join_triangles.c +++ b/source/blender/bmesh/operators/bmo_join_triangles.c @@ -34,6 +34,7 @@ #include "DNA_meshdata_types.h" #include "BLI_math.h" +#include "BLI_sort_utils.h" #include "BKE_customdata.h" @@ -181,10 +182,6 @@ static bool bm_edge_faces_cmp(BMesh *bm, BMEdge *e, const bool do_uv, const bool return true; } -typedef struct JoinEdge { - float weight; - BMEdge *e; -} JoinEdge; #define EDGE_MARK 1 #define EDGE_CHOSEN 2 @@ -192,14 +189,7 @@ typedef struct JoinEdge { #define FACE_MARK 1 #define FACE_INPUT 2 -static int fplcmp(const void *v1, const void *v2) -{ - const JoinEdge *e1 = (JoinEdge *)v1, *e2 = (JoinEdge *)v2; - if (e1->weight > e2->weight) return 1; - else if (e1->weight < e2->weight) return -1; - else return 0; -} void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) { @@ -213,8 +203,9 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) BMIter iter; BMOIter siter; BMFace *f; - BMEdge *e; - JoinEdge *jedges = NULL; + BMEdge *e, *e_next; + /* data: edge-to-join, sort_value: error weight */ + struct SortPointerByFloat *jedges; unsigned i, totedge; unsigned int totedge_tag = 0; @@ -271,19 +262,19 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) measure = measure_facepair(v1->co, v2->co, v3->co, v4->co, limit); if (measure < limit) { - jedges[i].e = e; - jedges[i].weight = measure; + jedges[i].data = e; + jedges[i].sort_value = measure; i++; } } totedge = i; - qsort(jedges, totedge, sizeof(JoinEdge), fplcmp); + qsort(jedges, totedge, sizeof(*jedges), BLI_sortutil_cmp_float); for (i = 0; i < totedge; i++) { BMFace *f_a, *f_b; - e = jedges[i].e; + e = jedges[i].data; f_a = e->l->f; f_b = e->l->radial_next->f; @@ -300,7 +291,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) MEM_freeN(jedges); /* join best weighted */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { BMFace *f_new; BMFace *f_a, *f_b; @@ -317,7 +308,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) } /* join 2-tri islands */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { BMLoop *l_a, *l_b; BMFace *f_a, *f_b; @@ -335,7 +326,11 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) (BMO_elem_flag_test(bm, l_a->next->e, EDGE_MARK) == false) && (BMO_elem_flag_test(bm, l_a->prev->e, EDGE_MARK) == false) && (BMO_elem_flag_test(bm, l_b->next->e, EDGE_MARK) == false) && - (BMO_elem_flag_test(bm, l_b->prev->e, EDGE_MARK) == false)) + (BMO_elem_flag_test(bm, l_b->prev->e, EDGE_MARK) == false) && + /* check for faces that use same verts, this is supported but raises an error + * and cancels the operation when performed from editmode, since this is only + * two triangles we only need to compare a single vertex */ + (LIKELY(l_a->prev->v != l_b->prev->v))) { BMFace *f_new; f_new = BM_faces_join_pair(bm, f_a, f_b, e, true); diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c index 025b8557331..1eaa0695ad2 100644 --- a/source/blender/bmesh/operators/bmo_normals.c +++ b/source/blender/bmesh/operators/bmo_normals.c @@ -29,6 +29,7 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" +#include "BLI_linklist_stack.h" #include "bmesh.h" @@ -46,7 +47,7 @@ static bool bmo_recalc_normal_edge_filter_cb(BMElem *ele, void *UNUSED(user_data } /** - * Given an array of faces, recalcualte their normals. + * Given an array of faces, recalculate their normals. * this functions assumes all faces in the array are connected by edges. * * \param bm @@ -65,8 +66,7 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f float f_len_best; BMFace *f; - BMFace **fstack = MEM_mallocN(sizeof(*fstack) * faces_len, __func__); - STACK_DECLARE(fstack); + BLI_LINKSTACK_DECLARE(fstack, BMFace *); zero_v3(cent); @@ -77,6 +77,7 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f madd_v3_v3fl(cent, f_cent, cent_fac); BLI_assert(BMO_elem_flag_test(bm, faces[i], FACE_TEMP) == 0); + BLI_assert(BM_face_is_normal_valid(faces[i])); } f_len_best = -FLT_MAX; @@ -102,12 +103,12 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f * have the same winding. this is done recursively, using a manual * stack (if we use simple function recursion, we'd end up overloading * the stack on large meshes). */ - STACK_INIT(fstack); + BLI_LINKSTACK_INIT(fstack); - STACK_PUSH(fstack, faces[f_start_index]); + BLI_LINKSTACK_PUSH(fstack, faces[f_start_index]); BMO_elem_flag_enable(bm, faces[f_start_index], FACE_TEMP); - while ((f = STACK_POP(fstack))) { + while ((f = BLI_LINKSTACK_POP(fstack))) { const bool flip_state = BMO_elem_flag_test_bool(bm, f, FACE_FLIP); BMLoop *l_iter, *l_first; @@ -119,13 +120,13 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f if (!BMO_elem_flag_test(bm, l_other->f, FACE_TEMP)) { BMO_elem_flag_enable(bm, l_other->f, FACE_TEMP); BMO_elem_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state); - STACK_PUSH(fstack, l_other->f); + BLI_LINKSTACK_PUSH(fstack, l_other->f); } } } while ((l_iter = l_iter->next) != l_first); } - MEM_freeN(fstack); + BLI_LINKSTACK_FREE(fstack); /* apply flipping to oflag'd faces */ for (i = 0; i < faces_len; i++) { diff --git a/source/blender/bmesh/operators/bmo_poke.c b/source/blender/bmesh/operators/bmo_poke.c index 03084ebb1b6..26f20656478 100644 --- a/source/blender/bmesh/operators/bmo_poke.c +++ b/source/blender/bmesh/operators/bmo_poke.c @@ -65,10 +65,10 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op) break; default: BLI_assert(0); - break; + return; } - BMO_ITER(f, &oiter, op->slots_in, "faces", BM_FACE) { + BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) { BMFace *f_new; float f_center[3]; BMVert *v_center = NULL; @@ -83,7 +83,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op) int i; bm_face_calc_center_fn(f, f_center); - v_center = BM_vert_create(bm, f_center, NULL, 0); + v_center = BM_vert_create(bm, f_center, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, v_center, ELE_NEW); /* handled by BM_loop_interp_from_face */ diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index 9f17c1dd8e3..45653f3411f 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -249,7 +249,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op) vec[2] = 0.0f; mul_m4_v3(mat, vec); - eve = BM_vert_create(bm, vec, NULL, 0); + eve = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, eve, VERT_MARK); if (a != 0) { @@ -318,11 +318,11 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) vec[0] = -dia * sinf(phi); vec[1] = 0.0; vec[2] = dia * cosf(phi); - eve = BM_vert_create(bm, vec, NULL, 0); + eve = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, eve, VERT_MARK); if (a != 0) { - e = BM_edge_create(bm, preveve, eve, NULL, 0); + e = BM_edge_create(bm, preveve, eve, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, e, EDGE_ORIG); } @@ -408,7 +408,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) vec[0] = dia_div * icovert[a][0]; vec[1] = dia_div * icovert[a][1]; vec[2] = dia_div * icovert[a][2]; - eva[a] = BM_vert_create(bm, vec, NULL, 0); + eva[a] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, eva[a], VERT_MARK); } @@ -471,12 +471,12 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) v[0] = (monkeyv[i][0] + 127) / 128.0, v[1] = monkeyv[i][1] / 128.0, v[2] = monkeyv[i][2] / 128.0; - tv[i] = BM_vert_create(bm, v, NULL, 0); + tv[i] = BM_vert_create(bm, v, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, tv[i], VERT_MARK); tv[monkeynv + i] = (fabsf(v[0] = -v[0]) < 0.001f) ? tv[i] : - (eve = BM_vert_create(bm, v, NULL, 0), mul_m4_v3(mat, eve->co), eve); + (eve = BM_vert_create(bm, v, NULL, BM_CREATE_NOP), mul_m4_v3(mat, eve->co), eve); BMO_elem_flag_enable(bm, tv[monkeynv + i], VERT_MARK); @@ -528,7 +528,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) zero_v3(vec); mul_m4_v3(mat, vec); - cent1 = BM_vert_create(bm, vec, NULL, 0); + cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, cent1, VERT_MARK); } @@ -538,12 +538,12 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) vec[1] = dia * cosf(phi); vec[2] = 0.0f; mul_m4_v3(mat, vec); - v1 = BM_vert_create(bm, vec, NULL, 0); + v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, v1, VERT_MARK); if (lastv1) - BM_edge_create(bm, v1, lastv1, NULL, 0); + BM_edge_create(bm, v1, lastv1, NULL, BM_CREATE_NOP); if (a && cap_ends) { BMFace *f; @@ -603,13 +603,13 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) vec[2] = -depth; mul_m4_v3(mat, vec); - cent1 = BM_vert_create(bm, vec, NULL, 0); + cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); vec[0] = vec[1] = 0.0f; vec[2] = depth; mul_m4_v3(mat, vec); - cent2 = BM_vert_create(bm, vec, NULL, 0); + cent2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, cent1, VERT_MARK); BMO_elem_flag_enable(bm, cent2, VERT_MARK); @@ -620,13 +620,13 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) vec[1] = dia1 * cosf(phi); vec[2] = -depth; mul_m4_v3(mat, vec); - v1 = BM_vert_create(bm, vec, NULL, 0); + v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); vec[0] = dia2 * sinf(phi); vec[1] = dia2 * cosf(phi); vec[2] = depth; mul_m4_v3(mat, vec); - v2 = BM_vert_create(bm, vec, NULL, 0); + v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, v1, VERT_MARK); BMO_elem_flag_enable(bm, v2, VERT_MARK); @@ -686,56 +686,56 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op) vec[1] = -off; vec[2] = -off; mul_m4_v3(mat, vec); - v1 = BM_vert_create(bm, vec, NULL, 0); + 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, 0); + 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, 0); + 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, 0); + 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, 0); + 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, 0); + 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, 0); + 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, 0); + v8 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, v8, VERT_MARK); /* the four sides */ diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index da70e201976..cc5a635092a 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -71,32 +71,11 @@ static void remdoubles_splitface(BMFace *f, BMesh *bm, BMOperator *op, BMOpSlot #define EDGE_COL 2 #define FACE_MARK 2 -#if 0 -int remdoubles_face_overlaps(BMesh *bm, BMVert **varr, - int len, BMFace *exclude, - BMFace **overlapface) -{ - BMIter vertfaces; - BMFace *f; - int i, amount; - - if (overlapface) *overlapface = NULL; - - for (i = 0; i < len; i++) { - f = BM_iter_new(&vertfaces, bm, BM_FACES_OF_VERT, varr[i]); - while (f) { - amount = BM_verts_in_face(bm, f, varr, len); - if (amount >= len) { - if (overlapface) *overlapface = f; - return true; - } - f = BM_iter_step(&vertfaces); - } - } - return false; -} -#endif - +/** + * \note with 'targetmap', multiple 'keys' are currently supported, though no callers should be using. + * (because slot maps currently use GHash without the GHASH_FLAG_ALLOW_DUPES flag set) + * + */ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) { BMIter iter, liter; @@ -215,10 +194,8 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) v2 = BMO_slot_map_elem_get(slot_targetmap, v2); } - f_new = BM_face_create_ngon(bm, v, v2, edges, a, BM_CREATE_NO_DOUBLE); + f_new = BM_face_create_ngon(bm, v, v2, edges, a, f, BM_CREATE_NO_DOUBLE); if (f_new && (f_new != f)) { - BM_elem_attrs_copy(bm, bm, f, f_new); - a = 0; BM_ITER_ELEM (l, &liter, f_new, BM_LOOPS_OF_FACE) { l_new = loops[a]; @@ -377,7 +354,7 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op) BMEdge *e, **edges = NULL; BLI_array_declare(edges); float min[3], max[3], center[3]; - int i, tot; + unsigned int i, tot; BMOpSlot *slot_targetmap; BMO_op_callf(bm, op->flag, "collapse_uvs edges=%s", op, "edges"); @@ -392,6 +369,8 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op) BMW_NIL_LAY); BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BMVert *v_tar; + if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) continue; @@ -404,19 +383,29 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op) minmax_v3v3_v3(min, max, e->v1->co); minmax_v3v3_v3(min, max, e->v2->co); + + /* prevent adding to slot_targetmap multiple times */ + BM_elem_flag_disable(e->v1, BM_ELEM_TAG); + BM_elem_flag_disable(e->v2, BM_ELEM_TAG); } mid_v3_v3v3(center, min, max); /* snap edges to a point. for initial testing purposes anyway */ + v_tar = edges[0]->v1; + for (i = 0; i < tot; i++) { - copy_v3_v3(edges[i]->v1->co, center); - copy_v3_v3(edges[i]->v2->co, center); - - if (edges[i]->v1 != edges[0]->v1) - BMO_slot_map_elem_insert(&weldop, slot_targetmap, edges[i]->v1, edges[0]->v1); - if (edges[i]->v2 != edges[0]->v1) - BMO_slot_map_elem_insert(&weldop, slot_targetmap, edges[i]->v2, edges[0]->v1); + unsigned int j; + + for (j = 0; j < 2; j++) { + BMVert *v_src = *((&edges[i]->v1) + j); + + copy_v3_v3(v_src->co, center); + if ((v_src != v_tar) && !BM_elem_flag_test(v_src, BM_ELEM_TAG)) { + BM_elem_flag_enable(v_src, BM_ELEM_TAG); + BMO_slot_map_elem_insert(&weldop, slot_targetmap, v_src, v_tar); + } + } } } @@ -521,13 +510,18 @@ static void bmesh_find_doubles_common(BMesh *bm, BMOperator *op, for (i = 0; i < verts_len; i++) { BMVert *v_check = verts[i]; - if (BMO_elem_flag_test(bm, v_check, VERT_DOUBLE)) { + if (BMO_elem_flag_test(bm, v_check, VERT_DOUBLE | VERT_TARGET)) { continue; } for (j = i + 1; j < verts_len; j++) { BMVert *v_other = verts[j]; + /* a match has already been found, (we could check which is best, for now don't) */ + if (BMO_elem_flag_test(bm, v_other, VERT_DOUBLE | VERT_TARGET)) { + continue; + } + /* Compare sort values of the verts using 3x tolerance (allowing for the tolerance * on each of the three axes). This avoids the more expensive length comparison * for most vertex pairs. */ diff --git a/source/blender/bmesh/operators/bmo_split_edges.c b/source/blender/bmesh/operators/bmo_split_edges.c index 7eea4c4878d..eb7946caff0 100644 --- a/source/blender/bmesh/operators/bmo_split_edges.c +++ b/source/blender/bmesh/operators/bmo_split_edges.c @@ -29,6 +29,7 @@ #include "BLI_utildefines.h" #include "bmesh.h" +#include "bmesh_tools.h" #include "intern/bmesh_operators_private.h" /* own include */ diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c index e669585a857..b3b9cecf389 100644 --- a/source/blender/bmesh/operators/bmo_subdivide.c +++ b/source/blender/bmesh/operators/bmo_subdivide.c @@ -921,7 +921,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) } if (BMO_elem_flag_test(bm, face, FACE_CUSTOMFILL)) { - pat = BMO_slot_map_data_get(params.slot_custom_patterns, face); + pat = *BMO_slot_map_data_get(params.slot_custom_patterns, face); for (i = 0; i < pat->len; i++) { matched = 1; for (j = 0; j < pat->len; j++) { diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c index fa39ae68cdf..13a7aa09335 100644 --- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c +++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c @@ -203,7 +203,7 @@ finally: /* -------------------------------------------------------------------- */ /* Edge Loop Pairs */ /* key (ordered loop pointers) */ -static GHash *bm_edgering_pair_calc(BMesh *bm, ListBase *eloops_rim) +static GSet *bm_edgering_pair_calc(BMesh *bm, ListBase *eloops_rim) { /** * Method for for finding pairs: @@ -219,7 +219,7 @@ static GHash *bm_edgering_pair_calc(BMesh *bm, ListBase *eloops_rim) * could sort and optimize this but not really so important. */ - GHash *eloop_pair_gh = BLI_ghash_pair_new(__func__); + GSet *eloop_pair_gs = BLI_gset_pair_new(__func__); GHash *vert_eloop_gh = BLI_ghash_ptr_new(__func__); struct BMEdgeLoopStore *el_store; @@ -256,9 +256,9 @@ static GHash *bm_edgering_pair_calc(BMesh *bm, ListBase *eloops_rim) if (pair_test.first > pair_test.second) SWAP(const void *, pair_test.first, pair_test.second); - if (!BLI_ghash_haskey(eloop_pair_gh, &pair_test)) { + if (!BLI_gset_haskey(eloop_pair_gs, &pair_test)) { GHashPair *pair = BLI_ghashutil_pairalloc(pair_test.first, pair_test.second); - BLI_ghash_insert(eloop_pair_gh, pair, NULL); + BLI_gset_insert(eloop_pair_gs, pair); } } @@ -268,12 +268,12 @@ static GHash *bm_edgering_pair_calc(BMesh *bm, ListBase *eloops_rim) BLI_ghash_free(vert_eloop_gh, NULL, NULL); - if (BLI_ghash_size(eloop_pair_gh) == 0) { - BLI_ghash_free(eloop_pair_gh, NULL, NULL); - eloop_pair_gh = NULL; + if (BLI_gset_size(eloop_pair_gs) == 0) { + BLI_gset_free(eloop_pair_gs, NULL); + eloop_pair_gs = NULL; } - return eloop_pair_gh; + return eloop_pair_gs; } @@ -919,13 +919,13 @@ static void bm_edgering_pair_order(BMesh *bm, } BLI_assert(node != NULL); - BLI_rotatelist(lb_b, node); + BLI_rotatelist_first(lb_b, node); /* now check we are winding the same way */ if (bm_edgering_pair_order_is_flipped(bm, el_store_a, el_store_b)) { BM_edgeloop_flip(bm, el_store_b); /* re-ensure the first node */ - BLI_rotatelist(lb_b, node); + BLI_rotatelist_first(lb_b, node); } /* sanity checks that we are aligned & winding now */ @@ -1175,23 +1175,23 @@ void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op) } } else { - GHashIterator gh_iter; + GSetIterator gs_iter; int i; - GHash *eloop_pairs_gh = bm_edgering_pair_calc(bm, &eloops_rim); + GSet *eloop_pairs_gs = bm_edgering_pair_calc(bm, &eloops_rim); LoopPairStore **lpair_arr; - if (eloop_pairs_gh == NULL) { + if (eloop_pairs_gs == NULL) { BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Edge-rings are not connected"); goto cleanup; } - lpair_arr = BLI_array_alloca(lpair_arr, BLI_ghash_size(eloop_pairs_gh)); + lpair_arr = BLI_array_alloca(lpair_arr, BLI_gset_size(eloop_pairs_gs)); /* first cache pairs */ - GHASH_ITER_INDEX (gh_iter, eloop_pairs_gh, i) { - GHashPair *eloop_pair = BLI_ghashIterator_getKey(&gh_iter); + GSET_ITER_INDEX (gs_iter, eloop_pairs_gs, i) { + GHashPair *eloop_pair = BLI_gsetIterator_getKey(&gs_iter); struct BMEdgeLoopStore *el_store_a = (void *)eloop_pair->first; struct BMEdgeLoopStore *el_store_b = (void *)eloop_pair->second; LoopPairStore *lpair; @@ -1207,8 +1207,8 @@ void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op) BLI_assert(bm_verts_tag_count(bm) == 0); } - GHASH_ITER_INDEX (gh_iter, eloop_pairs_gh, i) { - GHashPair *eloop_pair = BLI_ghashIterator_getKey(&gh_iter); + GSET_ITER_INDEX (gs_iter, eloop_pairs_gs, i) { + GHashPair *eloop_pair = BLI_gsetIterator_getKey(&gs_iter); struct BMEdgeLoopStore *el_store_a = (void *)eloop_pair->first; struct BMEdgeLoopStore *el_store_b = (void *)eloop_pair->second; LoopPairStore *lpair = lpair_arr[i]; @@ -1222,7 +1222,7 @@ void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op) BLI_assert(bm_verts_tag_count(bm) == 0); } - BLI_ghash_free(eloop_pairs_gh, MEM_freeN, NULL); + BLI_gset_free(eloop_pairs_gs, MEM_freeN); } cleanup: diff --git a/source/blender/bmesh/operators/bmo_symmetrize.c b/source/blender/bmesh/operators/bmo_symmetrize.c index b684240dc76..4b538dccb4e 100644 --- a/source/blender/bmesh/operators/bmo_symmetrize.c +++ b/source/blender/bmesh/operators/bmo_symmetrize.c @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor(s): Nicholas Bishop + * Contributor(s): Campbell Barton * * ***** END GPL LICENSE BLOCK ***** */ @@ -29,656 +29,81 @@ #include "MEM_guardedalloc.h" -#include "BLI_array.h" -#include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLI_math.h" #include "bmesh.h" #include "intern/bmesh_operators_private.h" -enum { - SYMM_OUTPUT_GEOM = (1 << 0) -}; - -/* Note: don't think there's much need to make these user-adjustable? */ -#define SYMM_AXIS_THRESHOLD 0.00002f -#define SYMM_VERT_THRESHOLD 0.00002f - -typedef enum { - /* Coordinate lies on the side being copied from */ - SYMM_SIDE_KEEP, - /* Coordinate lies on the side being copied from and within the - * axis threshold */ - SYMM_SIDE_AXIS, - /* Coordinate lies on the side being copied to */ - SYMM_SIDE_KILL -} SymmSide; - -typedef struct { - BMesh *bm; - BMOperator *op; - - int axis; - BMO_SymmDirection direction; - - /* Maps from input vertices to their mirrors. If the vertex - * doesn't have a mirror, it's not in this map. If the vertex is - * within the axis threshold, it's mapped to itself. */ - GHash *vert_symm_map; - - /* Edges that cross the symmetry plane and are asymmetric get - * split. This map goes from input edges to output vertices. If an - * edge is not split, it's not in this map. */ - GHash *edge_split_map; -} Symm; - -/* Return which side the coordinate lies on */ -static SymmSide symm_co_side(const Symm *symm, - const float *co) -{ - float comp = co[symm->axis]; - if (ELEM3(symm->direction, - BMO_SYMMETRIZE_NEGATIVE_X, - BMO_SYMMETRIZE_NEGATIVE_Y, - BMO_SYMMETRIZE_NEGATIVE_Z)) - { - comp = -comp; - } - - if (comp >= 0) { - if (comp < SYMM_AXIS_THRESHOLD) - return SYMM_SIDE_AXIS; - else - return SYMM_SIDE_KEEP; - } - else - return SYMM_SIDE_KILL; -} - -/* Output vertices and the vert_map array */ -static void symm_verts_mirror(Symm *symm) -{ - BMOIter oiter; - BMVert *src_v, *dst_v; - - symm->vert_symm_map = BLI_ghash_ptr_new(AT); - - BMO_ITER (src_v, &oiter, symm->op->slots_in, "input", BM_VERT) { - SymmSide side = symm_co_side(symm, src_v->co); - float co[3]; - - switch (side) { - case SYMM_SIDE_KEEP: - /* The vertex is outside the axis area; output its mirror */ - copy_v3_v3(co, src_v->co); - co[symm->axis] = -co[symm->axis]; - - dst_v = BM_vert_create(symm->bm, co, src_v, 0); - BMO_elem_flag_enable(symm->bm, dst_v, SYMM_OUTPUT_GEOM); - BLI_ghash_insert(symm->vert_symm_map, src_v, dst_v); - break; - - case SYMM_SIDE_AXIS: - /* The vertex is within the axis area, snap to center */ - src_v->co[symm->axis] = 0; - /* Vertex isn't copied, map to itself */ - BLI_ghash_insert(symm->vert_symm_map, src_v, src_v); - break; - - case SYMM_SIDE_KILL: - /* The vertex does not lie in the half-space being - * copied from, nothing to do */ - break; - } - } -} - -static int symm_edge_crosses_axis(const Symm *symm, const BMEdge *e) -{ - const int sides[2] = {symm_co_side(symm, e->v1->co), - symm_co_side(symm, e->v2->co)}; - - return ((sides[0] != SYMM_SIDE_AXIS) && - (sides[1] != SYMM_SIDE_AXIS) && - (sides[0] != sides[1])); -} - -/* Output edge split vertices for asymmetric edges and the edge_splits - * mapping array */ -static void symm_split_asymmetric_edges(Symm *symm) -{ - BMOIter oiter; - BMEdge *e; - - symm->edge_split_map = BLI_ghash_ptr_new(AT); - - BMO_ITER (e, &oiter, symm->op->slots_in, "input", BM_EDGE) { - float flipped[3]; - - copy_v3_v3(flipped, e->v1->co); - flipped[symm->axis] = -flipped[symm->axis]; - - if (symm_edge_crosses_axis(symm, e) && - (!compare_v3v3(e->v2->co, flipped, SYMM_VERT_THRESHOLD))) - { - /* Endpoints lie on opposite sides and are asymmetric */ - - BMVert *v; - float lambda = 0, edge_dir[3], co[3]; - float plane_co[3][3][3] = { - /* axis == 0 */ - {{0, 0, 0}, {0, 1, 0}, {0, 0, 1}}, - /* axis == 1 */ - {{0, 0, 0}, {1, 0, 0}, {0, 0, 1}}, - /* axis == 2 */ - {{0, 0, 0}, {1, 0, 0}, {0, 1, 0}}, - }; - int r; - - /* Find intersection of edge with symmetry plane */ - sub_v3_v3v3(edge_dir, e->v2->co, e->v1->co); - normalize_v3(edge_dir); - r = isect_ray_plane_v3(e->v1->co, - edge_dir, - plane_co[symm->axis][0], - plane_co[symm->axis][1], - plane_co[symm->axis][2], - &lambda, true); - BLI_assert(r); - - madd_v3_v3v3fl(co, e->v1->co, edge_dir, lambda); - co[symm->axis] = 0; - - /* Edge is asymmetric, split it with a new vertex */ - v = BM_vert_create(symm->bm, co, e->v1, 0); - BMO_elem_flag_enable(symm->bm, v, SYMM_OUTPUT_GEOM); - BLI_ghash_insert(symm->edge_split_map, e, v); - } - } -} - -static void symm_mirror_edges(Symm *symm) -{ - BMOIter oiter; - BMEdge *e; - - BMO_ITER (e, &oiter, symm->op->slots_in, "input", BM_EDGE) { - BMVert *v1 = NULL, *v2 = NULL; - BMEdge *e_new; - - v1 = BLI_ghash_lookup(symm->vert_symm_map, e->v1); - v2 = BLI_ghash_lookup(symm->vert_symm_map, e->v2); - - if (v1 && v2) { - e_new = BM_edge_create(symm->bm, v1, v2, e, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(symm->bm, e_new, SYMM_OUTPUT_GEOM); - } - else if (v1 || v2) { - if (BLI_ghash_haskey(symm->edge_split_map, e)) { - BMVert *v_split = BLI_ghash_lookup(symm->edge_split_map, e); - - /* Output the keep side of the split edge */ - if (!v1) { - e_new = BM_edge_create(symm->bm, v_split, e->v2, e, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(symm->bm, e_new, SYMM_OUTPUT_GEOM); - v1 = v_split; - } - else { - e_new = BM_edge_create(symm->bm, e->v1, v_split, e, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(symm->bm, e_new, SYMM_OUTPUT_GEOM); - v2 = v_split; - } - - /* Output the kill side of the split edge */ - e_new = BM_edge_create(symm->bm, v1, v2, e, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(symm->bm, e_new, SYMM_OUTPUT_GEOM); - } - } - } -} - -/****************************** SymmPoly ******************************/ - -typedef struct { - /* Indices into the source mvert array (or -1 if not in that array) */ - BMVert **src_verts; - /* Indices into the destination mvert array, these are vertices - * created by an edge split (-1 for vertices not created by edge - * split) */ - BMVert **edge_verts; - - /* Number of vertices in the polygon */ - int len; - - /* True only if none of the polygon's edges were split */ - bool already_symmetric; - - BMFace *src_face; -} SymmPoly; - -static void symm_poly_with_splits(const Symm *symm, - BMFace *f, - SymmPoly *out) -{ - BMIter iter; - BMLoop *l; - int i; - - out->src_face = f; - - /* Count vertices and check for edge splits */ - out->len = f->len; - out->already_symmetric = true; - BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { - if (BLI_ghash_haskey(symm->edge_split_map, l->e)) { - out->len++; - out->already_symmetric = false; - } - } - - i = 0; - BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { - BMVert *split = BLI_ghash_lookup(symm->edge_split_map, l->e); - - out->src_verts[i] = l->v; - out->edge_verts[i] = NULL; - i++; - - if (split) { - out->src_verts[i] = NULL; - out->edge_verts[i] = split; - i++; - } - } -} - -static const float *symm_poly_co(const SymmPoly *sp, int v) -{ - if (sp->src_verts[v]) - return sp->src_verts[v]->co; - else if (sp->edge_verts[v]) - return sp->edge_verts[v]->co; - else - return NULL; -} - -static SymmSide symm_poly_co_side(const Symm *symm, - const SymmPoly *sp, - int v) -{ - return symm_co_side(symm, symm_poly_co(sp, v)); -} - -/* Return the index of the vertex in the destination array at corner - * 'v' of the polygon, or -1 if not in that array */ -static BMVert *symm_poly_dst(const SymmPoly *sp, int v) -{ - if (sp->edge_verts[v]) - return sp->edge_verts[v]; - else if (sp->src_verts[v]) - return sp->src_verts[v]; - else - return NULL; -} - -/* Same as above, but returns the index of the mirror if available, or - * the same index if on the axis, or -1 otherwise */ -static BMVert *symm_poly_mirror_dst(const Symm *symm, - const SymmPoly *sp, - int v) -{ - if (sp->edge_verts[v]) - return sp->edge_verts[v]; - else if (sp->src_verts[v]) { - if (BLI_ghash_haskey(symm->vert_symm_map, sp->src_verts[v])) - return BLI_ghash_lookup(symm->vert_symm_map, sp->src_verts[v]); - else - return sp->src_verts[v]; - } - else - return NULL; -} - -static bool symm_poly_next_crossing(const Symm *symm, - const SymmPoly *sp, - int start, - int *l1, - int *l2) -{ - int i; - - for (i = 0; i < sp->len; i++) { - (*l1) = (start + i) % sp->len; - (*l2) = ((*l1) + 1) % sp->len; - - if ((symm_poly_co_side(symm, sp, *l1) == SYMM_SIDE_KILL) ^ - (symm_poly_co_side(symm, sp, *l2) == SYMM_SIDE_KILL)) - { - return true; - } - } - - BLI_assert(!"symm_poly_next_crossing failed"); - return false; -} - -static BMFace *symm_face_create_v(BMesh *bm, BMFace *example, - BMVert **fv, BMEdge **fe, int len) -{ - BMFace *f_new; - int i; - - /* TODO: calling symmetrize in dynamic-topology sculpt mode - * frequently tries to create faces of length less than two, - * should investigate further */ - if (len < 3) - return NULL; - - for (i = 0; i < len; i++) { - int j = (i + 1) % len; - fe[i] = BM_edge_exists(fv[i], fv[j]); - if (!fe[i]) { - fe[i] = BM_edge_create(bm, fv[i], fv[j], NULL, 0); - BMO_elem_flag_enable(bm, fe[i], SYMM_OUTPUT_GEOM); - } - } - f_new = BM_face_create(bm, fv, fe, len, BM_CREATE_NO_DOUBLE); - if (example) - BM_elem_attrs_copy(bm, bm, example, f_new); - BM_face_select_set(bm, f_new, true); - BMO_elem_flag_enable(bm, f_new, SYMM_OUTPUT_GEOM); +#define ELE_OUT 1 - return f_new; -} - -static void symm_mesh_output_poly_zero_splits(Symm *symm, - SymmPoly *sp, - BMVert **fv, - BMEdge **fe, - int segment_len, - int start) -{ - int i, j; - - j = 0; - - /* Output the keep side of the input polygon */ - for (i = 0; i < segment_len; i++) { - const int offset = (start + i) % sp->len; - BLI_assert(sp->src_verts[offset]); - fv[j++] = sp->src_verts[offset]; - } - - /* Output the kill side of the polygon */ - for (i = segment_len - 1; i >= 0; i--) { - const int offset = (start + i) % sp->len; - - if (symm_poly_co_side(symm, sp, offset) == SYMM_SIDE_KEEP) { - BLI_assert(sp->src_verts[offset]); - fv[j++] = BLI_ghash_lookup(symm->vert_symm_map, - sp->src_verts[offset]); - } - } - - symm_face_create_v(symm->bm, sp->src_face, fv, fe, j); -} - -static void symm_mesh_output_poly_with_splits(Symm *symm, - SymmPoly *sp, - BMVert **fv, - BMEdge **fe, - int segment_len, - int start) -{ - int i; - - /* Output the keep side of the input polygon */ - - for (i = 0; i < segment_len; i++) { - const int offset = (start + i) % sp->len; - BMVert *v = symm_poly_dst(sp, offset); - - BLI_assert(v); - - fv[i] = v; - } - - symm_face_create_v(symm->bm, sp->src_face, fv, fe, segment_len); - - /* Output the kill side of the input polygon */ - - for (i = 0; i < segment_len; i++) { - const int offset = (start + i) % sp->len; - BMVert *v = symm_poly_mirror_dst(symm, sp, offset); - - fv[segment_len - i - 1] = v; - - } - - symm_face_create_v(symm->bm, sp->src_face, fv, fe, segment_len); -} - -static void symm_mirror_polygons(Symm *symm) +void bmo_symmetrize_exec(BMesh *bm, BMOperator *op) { - BMOIter oiter; - BMFace *f; - BMVert **pv = NULL; - BMVert **fv = NULL; - BMEdge **fe = NULL; - BLI_array_declare(pv); - BLI_array_declare(fv); - BLI_array_declare(fe); - - BMO_ITER (f, &oiter, symm->op->slots_in, "input", BM_FACE) { - BMIter iter; - BMLoop *l; - bool mirror_all = true, ignore_all = true; - - /* Check if entire polygon can be mirrored or ignored */ - BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { - const SymmSide side = symm_co_side(symm, l->v->co); - if (side == SYMM_SIDE_KILL) - mirror_all = false; - else if (side == SYMM_SIDE_KEEP) - ignore_all = false; - } - - if (mirror_all) { - int i; - - /* Make a mirrored copy of the polygon */ - - BLI_array_empty(fv); - BLI_array_empty(fe); - BLI_array_grow_items(fv, f->len); - BLI_array_grow_items(fe, f->len); - - i = f->len; - BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { - i--; - - if (symm_co_side(symm, l->v->co) == SYMM_SIDE_KEEP) - fv[i] = BLI_ghash_lookup(symm->vert_symm_map, l->v); - else - fv[i] = l->v; - } - - symm_face_create_v(symm->bm, f, fv, fe, f->len); - } - else if (ignore_all) { - BM_face_kill(symm->bm, f); - } - else { - SymmPoly sp; - int l1, l2, l3, l4; - int double_l2, double_l3; - int segment_len; + const float dist = BMO_slot_float_get(op->slots_in, "dist"); + const int direction = BMO_slot_int_get(op->slots_in, "direction"); + const int axis = direction % 3; - BLI_array_empty(pv); - BLI_array_grow_items(pv, f->len * 4); - sp.src_verts = pv; - sp.edge_verts = pv + f->len * 2; - symm_poly_with_splits(symm, f, &sp); + BMOperator op_bisect; + BMOperator op_dupe; + BMOperator op_weld; - /* Find first loop edge crossing the axis */ - symm_poly_next_crossing(symm, &sp, 0, &l1, &l2); + BMOpSlot *slot_vertmap; + BMOpSlot *slot_targetmap; - /* If crossing isn't kill to keep, find the next one */ - if (symm_poly_co_side(symm, &sp, l1) != SYMM_SIDE_KILL) { - symm_poly_next_crossing(symm, &sp, l2, &l1, &l2); - } + float plane_no[3]; + float scale[3]; - /* Find next crossing (keep to kill) */ - symm_poly_next_crossing(symm, &sp, l2, &l3, &l4); - - if (l2 == l3) - segment_len = 0; - else if (l2 < l3) - segment_len = l3 - l2 + 1; - else - segment_len = (sp.len - l2 + 1) + l3; - - double_l2 = symm_poly_co_side(symm, &sp, l2) == SYMM_SIDE_KEEP; - double_l3 = symm_poly_co_side(symm, &sp, l3) == SYMM_SIDE_KEEP; + BMOIter siter; + BMVert *v; - /* Calculate number of new polygons/loops */ - if (segment_len == 0) { - } - else if (sp.already_symmetric) { - int new_loops; + copy_v3_fl(plane_no, 0.0f); + copy_v3_fl(scale, 1.0f); - if (double_l2 && double_l3) - new_loops = segment_len * 2; - else if (!double_l2 && !double_l3) - new_loops = segment_len * 2 - 2; - else - new_loops = segment_len * 2 - 1; + plane_no[axis] = direction > 2 ? 1.0f : -1.0f; + scale[axis] *= -1.0f; - BLI_array_empty(fv); - BLI_array_empty(fe); - BLI_array_grow_items(fv, new_loops); - BLI_array_grow_items(fe, new_loops); + /* Cut in half */ + BMO_op_initf(bm, &op_bisect, op->flag, + "bisect_plane geom=%s plane_no=%v dist=%f clear_outer=%b use_snap_center=%b", + op, "input", plane_no, dist, true, true); - symm_mesh_output_poly_zero_splits(symm, &sp, - fv, fe, - segment_len, l2); - BM_face_kill(symm->bm, f); - } - else if (!double_l2 && !double_l3) { - BLI_array_empty(fv); - BLI_array_empty(fe); - BLI_array_grow_items(fv, segment_len); - BLI_array_grow_items(fe, segment_len); + BMO_op_exec(bm, &op_bisect); - symm_mesh_output_poly_with_splits(symm, &sp, - fv, fe, - segment_len, - l2); + /* Duplicate */ + BMO_op_initf(bm, &op_dupe, op->flag, + "duplicate geom=%S", + &op_bisect, "geom.out"); - BM_face_kill(symm->bm, f); - } - else { - BLI_array_empty(fv); - BLI_array_empty(fe); - BLI_array_grow_items(fv, segment_len); - BLI_array_grow_items(fe, segment_len); + BMO_op_exec(bm, &op_dupe); - symm_mesh_output_poly_with_splits(symm, &sp, - fv, fe, - segment_len, - l2); + /* Flag for output (some will be merged) */ + BMO_slot_buffer_flag_enable(bm, op_bisect.slots_out, "geom.out", BM_ALL_NOLOOP, ELE_OUT); + BMO_slot_buffer_flag_enable(bm, op_dupe.slots_out, "geom.out", BM_ALL_NOLOOP, ELE_OUT); - BM_face_kill(symm->bm, f); - /* Output bridge triangle */ + BMO_op_callf(bm, op->flag, "scale verts=%S vec=%v", &op_dupe, "geom.out", scale); + BMO_op_callf(bm, op->flag, "reverse_faces faces=%S", &op_dupe, "geom.out"); - BLI_array_empty(fv); - BLI_array_empty(fe); - BLI_array_grow_items(fv, 3); - BLI_array_grow_items(fe, 3); - if (double_l2) { - fv[0] = symm_poly_dst(&sp, l2); - fv[1] = symm_poly_mirror_dst(symm, &sp, l2); - fv[2] = symm_poly_dst(&sp, l3); - } - else if (double_l3) { - fv[0] = symm_poly_dst(&sp, l3); - fv[1] = symm_poly_mirror_dst(symm, &sp, l3); - fv[2] = symm_poly_dst(&sp, l2); - } + /* Weld verts */ + BMO_op_init(bm, &op_weld, op->flag, "weld_verts"); - BLI_assert(fv[0] && fv[1] && fv[2]); + slot_vertmap = BMO_slot_get(op_dupe.slots_out, "vert_map.out"); + slot_targetmap = BMO_slot_get(op_weld.slots_in, "targetmap"); - symm_face_create_v(symm->bm, NULL, fv, fe, 3); - } - } + BMO_ITER (v, &siter, op_bisect.slots_out, "geom_cut.out", BM_VERT) { + BMVert *v_dupe = BMO_slot_map_elem_get(slot_vertmap, v); + BMO_slot_map_elem_insert(&op_weld, slot_targetmap, v_dupe, v); } - BLI_array_free(pv); - BLI_array_free(fv); - BLI_array_free(fe); -} - -/* Remove unused edges and vertices from the side being copied to */ -static void symm_kill_unused(Symm *symm) -{ - BMOIter oiter; - BMEdge *e; - BMVert *v; - - /* Kill unused edges */ - BMO_ITER (e, &oiter, symm->op->slots_in, "input", BM_EDGE) { - const int crosses = symm_edge_crosses_axis(symm, e); - const int symmetric = (crosses && - (!BLI_ghash_haskey(symm->edge_split_map, e))); - - if (((symm_co_side(symm, e->v1->co) == SYMM_SIDE_KILL) || - (symm_co_side(symm, e->v2->co) == SYMM_SIDE_KILL)) && - !symmetric) - { - /* The edge might be used by a face outside the input set */ - if (BM_edge_is_wire(e)) - BM_edge_kill(symm->bm, e); - } - } - - /* Kill unused vertices */ - BMO_ITER (v, &oiter, symm->op->slots_in, "input", BM_VERT) { - if (symm_co_side(symm, v->co) == SYMM_SIDE_KILL) { - if (BM_vert_edge_count(v) == 0) - BM_vert_kill(symm->bm, v); - } - } -} - -void bmo_symmetrize_exec(BMesh *bm, BMOperator *op) -{ - Symm symm; - BMO_SymmDirection direction = BMO_slot_int_get(op->slots_in, "direction"); - - symm.bm = bm; - symm.op = op; - symm.axis = (ELEM(direction, - BMO_SYMMETRIZE_NEGATIVE_X, - BMO_SYMMETRIZE_POSITIVE_X) ? 0 : - ELEM(direction, - BMO_SYMMETRIZE_NEGATIVE_Y, - BMO_SYMMETRIZE_POSITIVE_Y) ? 1 : - ELEM(direction, - BMO_SYMMETRIZE_NEGATIVE_Z, - BMO_SYMMETRIZE_POSITIVE_Z) ? 2 : 0); - symm.direction = direction; + BMO_op_exec(bm, &op_weld); - symm_verts_mirror(&symm); - symm_split_asymmetric_edges(&symm); - symm_mirror_edges(&symm); - symm_mirror_polygons(&symm); - symm_kill_unused(&symm); + /* Cleanup */ + BMO_op_finish(bm, &op_weld); - BLI_ghash_free(symm.vert_symm_map, NULL, NULL); - BLI_ghash_free(symm.edge_split_map, NULL, NULL); + BMO_op_finish(bm, &op_dupe); + BMO_op_finish(bm, &op_bisect); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", - BM_ALL_NOLOOP, SYMM_OUTPUT_GEOM); + /* Create output */ + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_OUT); } diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c index 754709b18c0..590b5ea97c4 100644 --- a/source/blender/bmesh/operators/bmo_triangulate.c +++ b/source/blender/bmesh/operators/bmo_triangulate.c @@ -34,6 +34,7 @@ #include "BLI_scanfill.h" #include "bmesh.h" +#include "bmesh_tools.h" #include "intern/bmesh_operators_private.h" @@ -58,6 +59,7 @@ void bmo_triangulate_exec(BMesh *bm, BMOperator *op) void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) { const bool use_beauty = BMO_slot_bool_get(op->slots_in, "use_beauty"); + const bool use_dissolve = BMO_slot_bool_get(op->slots_in, "use_dissolve"); BMOIter siter; BMEdge *e; ScanFillContext sf_ctx; @@ -65,8 +67,11 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) ScanFillVert *sf_vert, *sf_vert_1, *sf_vert_2; ScanFillFace *sf_tri; SmallHash hash; + float normal[3], *normal_pt; BLI_smallhash_init(&hash); + + BMO_slot_vec_get(op->slots_in, "normal", normal); BLI_scanfill_begin(&sf_ctx); @@ -91,7 +96,15 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) /* sf_edge->tmp.p = e; */ /* UNUSED */ } - BLI_scanfill_calc(&sf_ctx, BLI_SCANFILL_CALC_HOLES); + if (is_zero_v3(normal)) { + normal_pt = NULL; + } + else { + normalize_v3(normal); + normal_pt = normal; + } + + BLI_scanfill_calc_ex(&sf_ctx, BLI_SCANFILL_CALC_HOLES, normal_pt); for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { BMFace *f = BM_face_create_quad_tri(bm, @@ -121,4 +134,27 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) } BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW); + + if (use_dissolve) { + BMO_ITER (e, &siter, op->slots_out, "geom.out", BM_EDGE) { + if (LIKELY(e->l)) { /* in rare cases the edges face will have already been removed from the edge */ + BMFace *f_new; + f_new = BM_faces_join_pair(bm, e->l->f, + e->l->radial_next->f, e, + false); /* join faces */ + if (f_new) { + BMO_elem_flag_enable(bm, f_new, ELE_NEW); + BM_edge_kill(bm, e); + } + else { + BMO_error_clear(bm); + } + } + else { + BM_edge_kill(bm, e); + } + } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW); + } } diff --git a/source/blender/bmesh/operators/bmo_unsubdivide.c b/source/blender/bmesh/operators/bmo_unsubdivide.c index c1cfb1866f4..ec222b48751 100644 --- a/source/blender/bmesh/operators/bmo_unsubdivide.c +++ b/source/blender/bmesh/operators/bmo_unsubdivide.c @@ -31,6 +31,7 @@ #include "BLI_utildefines.h" #include "bmesh.h" +#include "bmesh_tools.h" #include "intern/bmesh_operators_private.h" /* own include */ diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index 8b8cab9d881..e23358bf4ff 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -41,14 +41,16 @@ #include "intern/bmesh_operators_private.h" /* own include */ +#define ELE_NEW 1 + void bmo_create_vert_exec(BMesh *bm, BMOperator *op) { float vec[3]; BMO_slot_vec_get(op->slots_in, "co", vec); - BMO_elem_flag_enable(bm, BM_vert_create(bm, vec, NULL, 0), 1); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "vert.out", BM_VERT, 1); + BMO_elem_flag_enable(bm, BM_vert_create(bm, vec, NULL, BM_CREATE_NOP), ELE_NEW); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "vert.out", BM_VERT, ELE_NEW); } void bmo_transform_exec(BMesh *UNUSED(bm), BMOperator *op) diff --git a/source/blender/bmesh/operators/bmo_wireframe.c b/source/blender/bmesh/operators/bmo_wireframe.c index c07e2c3bbf2..2e5db5210c4 100644 --- a/source/blender/bmesh/operators/bmo_wireframe.c +++ b/source/blender/bmesh/operators/bmo_wireframe.c @@ -159,10 +159,11 @@ void bmo_wireframe_exec(BMesh *bm, BMOperator *op) const bool use_boundary = BMO_slot_bool_get(op->slots_in, "use_boundary"); const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset"); const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); - const bool use_crease = (BMO_slot_bool_get(op->slots_in, "use_crease") && - CustomData_has_layer(&bm->edata, CD_CREASE)); + const bool use_crease = BMO_slot_bool_get(op->slots_in, "use_crease"); const float depth = BMO_slot_float_get(op->slots_in, "thickness"); const float inset = depth; + int cd_edge_crease_offset = use_crease ? CustomData_get_offset(&bm->edata, CD_CREASE) : -1; + const float crease_weight = 1.0f; const int totvert_orig = bm->totvert; @@ -196,6 +197,11 @@ void bmo_wireframe_exec(BMesh *bm, BMOperator *op) int i; + if (use_crease && cd_edge_crease_offset == -1) { + BM_data_layer_add(bm, &bm->edata, CD_CREASE); + cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); + } + BM_mesh_elem_index_ensure(bm, BM_VERT); BM_ITER_MESH_INDEX (v_src, &iter, bm, BM_VERTS_OF_MESH, i) { @@ -229,9 +235,9 @@ void bmo_wireframe_exec(BMesh *bm, BMOperator *op) } madd_v3_v3v3fl(tvec, v_src->co, v_src->no, -fac); - verts_neg[i] = BM_vert_create(bm, tvec, v_src, 0); + verts_neg[i] = BM_vert_create(bm, tvec, v_src, BM_CREATE_NOP); madd_v3_v3v3fl(tvec, v_src->co, v_src->no, fac); - verts_pos[i] = BM_vert_create(bm, tvec, v_src, 0); + verts_pos[i] = BM_vert_create(bm, tvec, v_src, BM_CREATE_NOP); } else { /* could skip this */ @@ -269,7 +275,7 @@ void bmo_wireframe_exec(BMesh *bm, BMOperator *op) } madd_v3_v3v3fl(tvec, l->v->co, tvec, fac); - verts_loop[verts_loop_tot] = BM_vert_create(bm, tvec, l->v, 0); + verts_loop[verts_loop_tot] = BM_vert_create(bm, tvec, l->v, BM_CREATE_NOP); if (use_boundary) { @@ -303,7 +309,7 @@ void bmo_wireframe_exec(BMesh *bm, BMOperator *op) fac *= verts_relfac[BM_elem_index_get(l_pair[i]->v)]; } madd_v3_v3v3fl(tvec, l_pair[i]->v->co, tvec, fac); - verts_boundary[BM_elem_index_get(l_pair[i]->v)] = BM_vert_create(bm, tvec, l_pair[i]->v, 0); + verts_boundary[BM_elem_index_get(l_pair[i]->v)] = BM_vert_create(bm, tvec, l_pair[i]->v, BM_CREATE_NOP); } } } @@ -380,16 +386,16 @@ void bmo_wireframe_exec(BMesh *bm, BMOperator *op) if (use_crease) { BMEdge *e_new; e_new = BM_edge_exists(v_pos1, v_b1); - BM_elem_float_data_set(&bm->edata, e_new, CD_CREASE, 1.0f); + BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight); e_new = BM_edge_exists(v_pos2, v_b2); - BM_elem_float_data_set(&bm->edata, e_new, CD_CREASE, 1.0f); + BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight); e_new = BM_edge_exists(v_neg1, v_b1); - BM_elem_float_data_set(&bm->edata, e_new, CD_CREASE, 1.0f); + BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight); e_new = BM_edge_exists(v_neg2, v_b2); - BM_elem_float_data_set(&bm->edata, e_new, CD_CREASE, 1.0f); + BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight); } } } @@ -397,16 +403,16 @@ void bmo_wireframe_exec(BMesh *bm, BMOperator *op) if (use_crease) { BMEdge *e_new; e_new = BM_edge_exists(v_pos1, v_l1); - BM_elem_float_data_set(&bm->edata, e_new, CD_CREASE, 1.0f); + BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight); e_new = BM_edge_exists(v_pos2, v_l2); - BM_elem_float_data_set(&bm->edata, e_new, CD_CREASE, 1.0f); + BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight); e_new = BM_edge_exists(v_neg1, v_l1); - BM_elem_float_data_set(&bm->edata, e_new, CD_CREASE, 1.0f); + BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight); e_new = BM_edge_exists(v_neg2, v_l2); - BM_elem_float_data_set(&bm->edata, e_new, CD_CREASE, 1.0f); + BM_ELEM_CD_SET_FLOAT(e_new, cd_edge_crease_offset, crease_weight); } } diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 02f0251bff2..8c3edfa23c4 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -42,6 +42,8 @@ #include "BKE_deform.h" #include "bmesh.h" +#include "bmesh_bevel.h" /* own include */ + #include "./intern/bmesh_private.h" #define BEVEL_EPSILON_D 1e-6 @@ -177,7 +179,7 @@ static NewVert *mesh_vert(VMesh *vm, int i, int j, int k) static void create_mesh_bmvert(BMesh *bm, VMesh *vm, int i, int j, int k, BMVert *eg) { NewVert *nv = mesh_vert(vm, i, j, k); - nv->v = BM_vert_create(bm, nv->co, eg, 0); + nv->v = BM_vert_create(bm, nv->co, eg, BM_CREATE_NOP); BM_elem_flag_disable(nv->v, BM_ELEM_TAG); } @@ -255,20 +257,8 @@ static BMFace *bev_create_ngon(BMesh *bm, BMVert **vert_arr, const int totv, BMFace *f, *interp_f; int i; - if (totv == 3) { - f = BM_face_create_quad_tri_v(bm, vert_arr, 3, facerep, FALSE); - } - else if (totv == 4) { - f = BM_face_create_quad_tri_v(bm, vert_arr, 4, facerep, FALSE); - } - else { - BMEdge **ee = BLI_array_alloca(ee, totv); + f = BM_face_create_verts(bm, vert_arr, totv, facerep, BM_CREATE_NOP, true); - for (i = 0; i < totv; i++) { - ee[i] = BM_edge_create(bm, vert_arr[i], vert_arr[(i + 1) % totv], NULL, BM_CREATE_NO_DOUBLE); - } - f = BM_face_create(bm, vert_arr, ee, totv, 0); - } if ((facerep || (face_arr && face_arr[0])) && f) { BM_elem_attrs_copy(bm, bm, facerep ? facerep : face_arr[0], f); if (do_interp) { @@ -428,14 +418,14 @@ static void bev_merge_uvs(BMesh *bm, BMVert *v) n = 0; zero_v2(uv); - BM_ITER_ELEM(l, &iter, v, BM_LOOPS_OF_VERT) { + BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); add_v2_v2(uv, luv->uv); n++; } if (n > 1) { mul_v2_fl(uv, 1.0f / (float)n); - BM_ITER_ELEM(l, &iter, v, BM_LOOPS_OF_VERT) { + BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); copy_v2_v2(luv->uv, uv); } @@ -744,14 +734,14 @@ static void snap_to_edge_profile(EdgeHalf *e, const float va[3], const float vb[ float co[3]) { float m[4][4], minv[4][4]; - float edir[3], va0[3], vb0[3], vmid0[3], p[3], snap[3]; + float edir[3], va0[3], vb0[3], vmid0[3], p[3], snap[3], plane[4]; sub_v3_v3v3(edir, e->e->v1->co, e->e->v2->co); - normalize_v3(edir); /* project va and vb onto plane P, with normal edir and containing co */ - closest_to_plane_v3(va0, co, edir, va); - closest_to_plane_v3(vb0, co, edir, vb); + plane_from_point_normal_v3(plane, co, edir); + closest_to_plane_v3(va0, plane, va); + closest_to_plane_v3(vb0, plane, vb); project_to_edge(e->e, va0, vb0, vmid0); if (make_unit_square_map(va0, vmid0, vb0, m)) { /* Transform co and project it onto the unit circle. @@ -910,7 +900,12 @@ static void build_boundary(BevelParams *bp, BevVert *bv) BLI_assert(vm->count >= 2); if (bp->vertex_only) { - vm->mesh_kind = bp->seg > 1 ? M_ADJ_SUBDIV : M_POLY; + if (vm->count == 2) + vm->mesh_kind = M_NONE; + else if (bp->seg > 1) + vm->mesh_kind = M_ADJ_SUBDIV; + else + vm->mesh_kind = M_POLY; } else if (vm->count == 2 && bv->edgecount == 3) { vm->mesh_kind = M_NONE; @@ -1143,7 +1138,7 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) mul_v3_fl(midco, 1.0f / nn); if (epipe) snap_to_edge_profile(epipe, va_pipe, vb_pipe, midco); - bmv = BM_vert_create(bm, midco, NULL, 0); + bmv = BM_vert_create(bm, midco, NULL, BM_CREATE_NOP); v = vm->boundstart; do { i = v->index; @@ -1212,8 +1207,12 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv) f = boundvert_rep_face(v); f2 = boundvert_rep_face(v->next); if (!v->any_seam) { - for (ring = 1; ring < ns2; ring++) - bev_merge_uvs(bm, mesh_vert(vm, i, ring, ns2)->v); + for (ring = 1; ring < ns2; ring++) { + BMVert *v_uv = mesh_vert(vm, i, ring, ns2)->v; + if (v_uv) { + bev_merge_uvs(bm, v_uv); + } + } } } while ((v = v->next) != vm->boundstart); if (!bv->any_seam) @@ -1972,7 +1971,7 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) if (!first_bme) first_bme = v->e; - if ((nsel == 0 && !bp->vertex_only) || (ntot < 3 && bp->vertex_only)) { + if ((nsel == 0 && !bp->vertex_only) || (ntot < 2 && bp->vertex_only)) { /* signal this vert isn't being beveled */ BM_elem_flag_disable(v, BM_ELEM_TAG); return; @@ -2333,14 +2332,14 @@ static float bevel_limit_offset(BMesh *bm, BevelParams *bp) bool vbeveled; limited_offset = bp->offset; - BM_ITER_MESH(v, &v_iter, bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (v, &v_iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { if (bp->vertex_only) { vbeveled = true; } else { vbeveled = false; - BM_ITER_ELEM(e, &e_iter, v, BM_EDGES_OF_VERT) { + BM_ITER_ELEM (e, &e_iter, v, BM_EDGES_OF_VERT) { if (BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG)) { vbeveled = true; break; @@ -2348,7 +2347,7 @@ static float bevel_limit_offset(BMesh *bm, BevelParams *bp) } } if (vbeveled) { - BM_ITER_ELEM(e, &e_iter, v, BM_EDGES_OF_VERT) { + BM_ITER_ELEM (e, &e_iter, v, BM_EDGES_OF_VERT) { half_elen = 0.5f * BM_edge_calc_length(e); if (half_elen < limited_offset) limited_offset = half_elen; @@ -2376,7 +2375,7 @@ void BM_mesh_bevel(BMesh *bm, const float offset, const float segments, const struct MDeformVert *dvert, const int vertex_group) { BMIter iter; - BMVert *v; + BMVert *v, *v_next; BMEdge *e; BevelParams bp = {NULL}; @@ -2419,7 +2418,7 @@ void BM_mesh_bevel(BMesh *bm, const float offset, const float segments, } } - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG)) { BLI_assert(find_bevvert(&bp, v) != NULL); BM_vert_kill(bm, v); diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c new file mode 100644 index 00000000000..9cfe17d6413 --- /dev/null +++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c @@ -0,0 +1,408 @@ +/* + * ***** 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. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/tools/bmesh_bisect_plane.c + * \ingroup bmesh + * + * Cut the geometry in half using a plane. + * + * \par Implementation + * This simply works by splitting tagged edges whos verts span either side of + * the plane, then splitting faces along their dividing verts. + * The only complex case is when a ngon spans the axis multiple times, + * in this case we need to do some extra checks to correctly bisect the ngon. + * see: #bm_face_bisect_verts + */ + +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_alloca.h" +#include "BLI_linklist.h" +#include "BLI_linklist_stack.h" +#include "BLI_math.h" + +#include "bmesh.h" +#include "bmesh_bisect_plane.h" /* own include */ + +#include "BLI_strict_flags.h" /* keep last */ + + +/* -------------------------------------------------------------------- */ +/* Math utils */ + +static int plane_point_test_v3(const float plane[4], const float co[3], const float eps, float *r_depth) +{ + const float f = plane_point_side_v3(plane, co); + *r_depth = f; + + if (f <= -eps) return -1; + else if (f >= eps) return 1; + else return 0; +} + + +/* -------------------------------------------------------------------- */ +/* Wrappers to hide internal data-structure abuse, + * later we may want to move this into some hash lookup + * to a separate struct, but for now we can store in BMesh data */ + +#define BM_VERT_DIR(v) ((v)->head.index) /* Direction -1/0/1 */ +#define BM_VERT_DIST(v) ((v)->no[0]) /* Distance from the plane. */ +#define BM_VERT_SORTVAL(v) ((v)->no[1]) /* Temp value for sorting. */ +#define BM_VERT_LOOPINDEX(v) /* The verts index within a face (temp var) */ \ + (*((unsigned int *)(&(v)->no[2]))) + +/** + * Hide flag access + * (for more readable code since same flag is used differently for vert/edgeface)... + */ + +/* enable when vertex is in the center and its faces have been added to the stack */ +BLI_INLINE void vert_is_center_enable(BMVert *v) { BM_elem_flag_enable(v, BM_ELEM_TAG); } +BLI_INLINE void vert_is_center_disable(BMVert *v) { BM_elem_flag_disable(v, BM_ELEM_TAG); } +BLI_INLINE bool vert_is_center_test(BMVert *v) { return (BM_elem_flag_test(v, BM_ELEM_TAG) != 0); } + +/* enable when the edge can be cut */ +BLI_INLINE void edge_is_cut_enable(BMEdge *e) { BM_elem_flag_enable(e, BM_ELEM_TAG); } +BLI_INLINE void edge_is_cut_disable(BMEdge *e) { BM_elem_flag_disable(e, BM_ELEM_TAG); } +BLI_INLINE bool edge_is_cut_test(BMEdge *e) { return (BM_elem_flag_test(e, BM_ELEM_TAG) != 0); } + +/* enable when the faces are added to the stack */ +BLI_INLINE void face_in_stack_enable(BMFace *f) { BM_elem_flag_disable(f, BM_ELEM_TAG); } +BLI_INLINE void face_in_stack_disable(BMFace *f) { BM_elem_flag_enable(f, BM_ELEM_TAG); } +BLI_INLINE bool face_in_stack_test(BMFace *f) { return (BM_elem_flag_test(f, BM_ELEM_TAG) == 0); } + +/* -------------------------------------------------------------------- */ +/* BMesh utils */ + +static int bm_vert_sortval_cb(const void *v_a_v, const void *v_b_v) +{ + const float val_a = BM_VERT_SORTVAL(*((BMVert **)v_a_v)); + const float val_b = BM_VERT_SORTVAL(*((BMVert **)v_b_v)); + + if (val_a > val_b) return 1; + else if (val_a < val_b) return -1; + return 0; +} + + +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 */ + 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); + BMLoop *l_iter, *l_first; + bool use_dirs[3] = {false, false, false}; + + STACK_INIT(vert_split_arr); + + l_first = BM_FACE_FIRST_LOOP(f); + + /* add plane-aligned verts to the stack + * and check we have verts from both sides in this face, + * ... that the face doesn't only have boundry verts on the plane for eg. */ + l_iter = l_first; + do { + if (vert_is_center_test(l_iter->v)) { + BLI_assert(BM_VERT_DIR(l_iter->v) == 0); + STACK_PUSH(vert_split_arr, l_iter->v); + } + use_dirs[BM_VERT_DIR(l_iter->v) + 1] = true; + } while ((l_iter = l_iter->next) != l_first); + + if ((STACK_SIZE(vert_split_arr) > 1) && + (use_dirs[0] && use_dirs[2])) + { + BMLoop *l_new; + + if (LIKELY(STACK_SIZE(vert_split_arr) == 2)) { + /* common case, just cut the face once */ + l_new = NULL; + BM_face_split(bm, f, vert_split_arr[0], vert_split_arr[1], &l_new, NULL, true); + if (l_new) { + if (oflag_center) { + BMO_elem_flag_enable(bm, l_new->e, oflag_center); + BMO_elem_flag_enable(bm, l_new->f, oflag_center); + BMO_elem_flag_enable(bm, f, oflag_center); + } + } + } + else { + /* less common case, _complicated_ we need to calculate how to do multiple cuts */ + float (*face_verts_proj_2d)[2] = BLI_array_alloca(face_verts_proj_2d, f_len_orig); + float axis_mat[3][3]; + + BMFace **face_split_arr = BLI_array_alloca(face_split_arr, STACK_SIZE(vert_split_arr)); + STACK_DECLARE(face_split_arr); + + float sort_dir[3]; + unsigned int i; + + + /* ---- */ + /* Calculate the direction to sort verts in the face intersecting the plane */ + + /* exact dir isn't so important, + * just need a dir for sorting verts across face, + * 'sort_dir' could be flipped either way, it not important, we only need to order the array + */ + cross_v3_v3v3(sort_dir, f->no, plane); + if (UNLIKELY(normalize_v3(sort_dir) == 0.0f)) { + /* find any 2 verts and get their direction */ + for (i = 0; i < STACK_SIZE(vert_split_arr); i++) { + if (!equals_v3v3(vert_split_arr[0]->co, vert_split_arr[i]->co)) { + sub_v3_v3v3(sort_dir, vert_split_arr[0]->co, vert_split_arr[i]->co); + normalize_v3(sort_dir); + } + } + if (UNLIKELY(i == STACK_SIZE(vert_split_arr))) { + /* ok, we can't do anything useful here, + * face has no area or so, bail out, this is highly unlikely but not impossible */ + goto finally; + } + } + + + /* ---- */ + /* Calculate 2d coords to use for intersection checks */ + + /* get the faces 2d coords */ + BLI_assert(BM_face_is_normal_valid(f)); + axis_dominant_v3_to_m3(axis_mat, f->no); + + l_iter = l_first; + i = 0; + do { + BM_VERT_LOOPINDEX(l_iter->v) = i; + mul_v2_m3v3(face_verts_proj_2d[i], axis_mat, l_iter->v->co); + i++; + } while ((l_iter = l_iter->next) != l_first); + + + /* ---- */ + /* Sort the verts across the face from one side to another */ + for (i = 0; i < STACK_SIZE(vert_split_arr); i++) { + BMVert *v = vert_split_arr[i]; + BM_VERT_SORTVAL(v) = dot_v3v3(sort_dir, v->co); + } + + qsort(vert_split_arr, STACK_SIZE(vert_split_arr), sizeof(*vert_split_arr), bm_vert_sortval_cb); + + + /* ---- */ + /* Split the face across sorted splits */ + + /* note: we don't know which face gets which splits, + * so at the moment we have to search all faces for the vert pair, + * while not all that nice, typically there are < 5 resulting faces, + * so its not _that_ bad. */ + + STACK_INIT(face_split_arr); + STACK_PUSH(face_split_arr, f); + + for (i = 0; i < STACK_SIZE(vert_split_arr) - 1; i++) { + BMVert *v_a = vert_split_arr[i]; + BMVert *v_b = vert_split_arr[i + 1]; + float co_mid[2]; + + /* geometric test before doing face lookups, + * find if the split spans a filled region of the polygon. */ + mid_v2_v2v2(co_mid, + face_verts_proj_2d[BM_VERT_LOOPINDEX(v_a)], + face_verts_proj_2d[BM_VERT_LOOPINDEX(v_b)]); + + if (isect_point_poly_v2(co_mid, (const float (*)[2])face_verts_proj_2d, f_len_orig, false)) { + BMLoop *l_a, *l_b; + bool found = false; + unsigned int j; + + for (j = 0; j < STACK_SIZE(face_split_arr); j++) { + /* would be nice to avoid loop lookup here, + * but we need to know which face the verts are in */ + if ((l_a = BM_face_vert_share_loop(face_split_arr[j], v_a)) && + (l_b = BM_face_vert_share_loop(face_split_arr[j], v_b))) + { + found = true; + break; + } + } + + BLI_assert(found == true); + + /* in fact this simple test is good enough, + * test if the loops are adjacent */ + if (found && (l_a->next != l_b && l_a->prev != l_b)) { + BMFace *f_tmp; + f_tmp = BM_face_split(bm, face_split_arr[j], l_a->v, l_b->v, NULL, NULL, true); + if (f_tmp) { + if (f_tmp != face_split_arr[j]) { + STACK_PUSH(face_split_arr, f_tmp); + BLI_assert(STACK_SIZE(face_split_arr) <= STACK_SIZE(vert_split_arr)); + } + } + } + } + else { + // printf("no intersect\n"); + } + } + } + } + +finally: + STACK_FREE(vert_split_arr); + +} + +/* -------------------------------------------------------------------- */ +/* Main logic */ + +/** + * \param use_tag Only bisect tagged edges and faces. + * \param use_snap Snap verts onto the plane. + * \param oflag_center Operator flag, enabled for geometry on the axis (existing and created) + */ +void BM_mesh_bisect_plane(BMesh *bm, float plane[4], + const bool use_snap_center, const bool use_tag, + const short oflag_center, const float eps) +{ + unsigned int einput_len; + unsigned int i; + BMEdge **edges_arr = MEM_mallocN(sizeof(*edges_arr) * (size_t)bm->totedge, __func__); + + BLI_LINKSTACK_DECLARE(face_stack, BMFace *); + + BMVert *v; + BMFace *f; + + BMIter iter; + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + vert_is_center_disable(v); + + BM_VERT_DIR(v) = plane_point_test_v3(plane, v->co, eps, &(BM_VERT_DIST(v))); + if (BM_VERT_DIR(v) == 0) { + if (oflag_center) { + BMO_elem_flag_enable(bm, v, oflag_center); + } + if (use_snap_center) { + closest_to_plane_v3(v->co, plane, v->co); + } + } + } + + if (use_tag) { + /* build tagged edge array */ + BMEdge *e; + einput_len = 0; + /* keep face tags as is */ + BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) { + if (edge_is_cut_test(e)) { + edges_arr[einput_len++] = e; + } + } + + } + else { + BMEdge *e; + einput_len = (unsigned int)bm->totedge; + BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) { + edge_is_cut_enable(e); + edges_arr[i] = e; + } + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + face_in_stack_disable(f); + } + } + + /* store a stack of faces to be evaluated for splitting */ + BLI_LINKSTACK_INIT(face_stack); + + for (i = 0; i < einput_len; i++) { + /* we could check edge_is_cut_test(e) but there is no point */ + BMEdge *e = edges_arr[i]; + const int side[2] = {BM_VERT_DIR(e->v1), BM_VERT_DIR(e->v2)}; + const float dist[2] = {BM_VERT_DIST(e->v1), BM_VERT_DIST(e->v2)}; + + if (side[0] && side[1] && (side[0] != side[1])) { + const float e_fac = fabsf(dist[0]) / fabsf(dist[0] - dist[1]); + BMVert *v_new; + + if (e->l) { + BMLoop *l_iter, *l_first; + l_iter = l_first = e->l; + do { + if (!face_in_stack_test(l_iter->f)) { + face_in_stack_enable(l_iter->f); + BLI_LINKSTACK_PUSH(face_stack, l_iter->f); + } + } while ((l_iter = l_iter->radial_next) != l_first); + } + + v_new = BM_edge_split(bm, e, e->v1, NULL, e_fac); + vert_is_center_enable(v_new); + if (oflag_center) { + BMO_elem_flag_enable(bm, v_new, oflag_center); + } + + BM_VERT_DIR(v_new) = 0; + BM_VERT_DIST(v_new) = 0.0f; + } + else { + /* check if either edge verts are aligned, + * if so - tag and push all faces that use it into the stack */ + unsigned int j; + BM_ITER_ELEM_INDEX (v, &iter, e, BM_VERTS_OF_EDGE, j) { + if (side[j] == 0) { + if (vert_is_center_test(v) == 0) { + BMIter itersub; + BMLoop *l_iter; + + vert_is_center_enable(v); + + BM_ITER_ELEM (l_iter, &itersub, v, BM_LOOPS_OF_VERT) { + if (!face_in_stack_test(l_iter->f)) { + face_in_stack_enable(l_iter->f); + BLI_LINKSTACK_PUSH(face_stack, l_iter->f); + } + } + + } + } + } + } + } + + MEM_freeN(edges_arr); + + while ((f = BLI_LINKSTACK_POP(face_stack))) { + bm_face_bisect_verts(bm, f, plane, oflag_center); + } + + /* now we have all faces to split in the stack */ + BLI_LINKSTACK_FREE(face_stack); +} diff --git a/source/blender/compositor/operations/COM_RenderLayersAlphaProg.h b/source/blender/bmesh/tools/bmesh_bisect_plane.h index 36668bc9338..15f902642c8 100644 --- a/source/blender/compositor/operations/COM_RenderLayersAlphaProg.h +++ b/source/blender/bmesh/tools/bmesh_bisect_plane.h @@ -1,5 +1,5 @@ /* - * Copyright 2011, Blender Foundation. + * ***** 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 @@ -15,21 +15,20 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** */ -#ifndef _COM_RenderLayersAlphaProg_h -#define _COM_RenderLayersAlphaProg_h - -#include "COM_RenderLayersBaseProg.h" +#ifndef __BMESH_BISECT_PLANE_H__ +#define __BMESH_BISECT_PLANE_H__ -class RenderLayersAlphaProg : public RenderLayersBaseProg { -public: - RenderLayersAlphaProg(); - void executePixel(float output[4], float x, float y, PixelSampler sampler); +/** \file blender/bmesh/tools/bmesh_bisect_plane.h + * \ingroup bmesh + */ -}; +void BM_mesh_bisect_plane(BMesh *bm, float plane[4], + const bool use_snap_center, const bool use_tag, + const short oflag_center, const float eps); -#endif +#endif /* __BMESH_BISECT_PLANE_H__ */ diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c index 310357453a3..96af37f4400 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c +++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c @@ -293,7 +293,7 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool } /* re-calculate costs */ - BM_ITER_ELEM(v_iter, &iter, e_new, BM_VERTS_OF_EDGE) { + BM_ITER_ELEM (v_iter, &iter, e_new, BM_VERTS_OF_EDGE) { const int j = BM_elem_index_get(v_iter); if (j != -1 && vheap_table[j]) { const float cost = bm_vert_edge_face_angle(v_iter); diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c index 0667d560615..868caa49ec7 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c +++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c @@ -32,8 +32,7 @@ #include "BLI_math.h" #include "bmesh.h" - -#include "intern/bmesh_operators_private.h" /* own include */ +#include "bmesh_decimate.h" /* own include */ static bool bm_vert_dissolve_fan_test(BMVert *v) @@ -198,7 +197,7 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool } for (iter_step = 0; iter_step < iterations; iter_step++) { - BMVert *v; + BMVert *v, *v_next; bool iter_done; BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { @@ -319,7 +318,7 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool /* now we tagged all verts -1 for removal, lets loop over and rebuild faces */ iter_done = false; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_index_get(v) == VERT_INDEX_DO_COLLAPSE) { if (bm_vert_dissolve_fan(bm, v)) { iter_done = true; diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c new file mode 100644 index 00000000000..14d474fed61 --- /dev/null +++ b/source/blender/bmesh/tools/bmesh_edgenet.c @@ -0,0 +1,508 @@ +/* + * ***** 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. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/tools/bmesh_edgenet.c + * \ingroup bmesh + * + * Edgenet Fill. + * + */ + +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_alloca.h" +#include "BLI_mempool.h" +#include "BLI_linklist.h" + +#include "bmesh.h" +#include "bmesh_edgenet.h" /* own include */ + +#include "BLI_strict_flags.h" /* keep last */ + + +/* Data for one end of an edge involved in a bevel */ +typedef struct VertNetInfo { + BMVert *prev; /* previous vertex */ + int pass; /* path scanning pass value, for internal calculation */ + int face; /* face index connected to the edge between this and the previous vert */ + int flag; /* flag */ +} VertNetInfo; + +enum { + VNINFO_FLAG_IS_MIXFACE = (1 << 0), +}; + +/** + * Check if this edge can be used in a path. + */ +static bool bm_edge_step_ok(BMEdge *e) +{ + return BM_elem_flag_test(e, BM_ELEM_TAG) && ((e->l == NULL) || (e->l->radial_next == e->l)); +} + +static int bm_edge_face(BMEdge *e) +{ + return e->l ? BM_elem_index_get(e->l->f) : -1; +} + +/** + * Get the next available edge we can use to attempt tp calculate a path from. + */ +static BMEdge *bm_edgenet_edge_get_next( + BMesh *bm, + LinkNode **edge_queue, BLI_mempool *edge_queue_pool) +{ + BMEdge *e; + BMIter iter; + + while (*edge_queue) { + e = BLI_linklist_pop_pool(edge_queue, edge_queue_pool); + if (bm_edge_step_ok(e)) { + return e; + } + } + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (bm_edge_step_ok(e)) { + return e; + } + } + + return NULL; +} + + +/** + * Edge loops are built up using links to the 'prev' member. + * with each side of the loop having its own pass (negated from the other). + * + * This function returns half a loop, the caller needs to run twice to get both sides. + */ +static unsigned int bm_edgenet_path_from_pass( + BMVert *v, LinkNode **v_ls, + VertNetInfo *vnet_info, BLI_mempool *path_pool) +{ + VertNetInfo *vn = &vnet_info[BM_elem_index_get(v)]; + const int pass = vn->pass; + unsigned int v_ls_tot = 0; + + do { + BLI_linklist_prepend_pool(v_ls, v, path_pool); + v_ls_tot += 1; + v = vn->prev; + vn = &vnet_info[BM_elem_index_get(v)]; + } while (vn->pass == pass); + + return v_ls_tot; +} + +/** + * Specialized wrapper for #BM_face_exists_overlap_subset + * that gets the verts from a path before we allocate it in the correct order. + */ +static bool bm_edgenet_path_check_overlap( + BMVert *v1, BMVert *v2, + VertNetInfo *vnet_info) +{ + /* vert order doesn't matter */ + unsigned int v_ls_tot = 0; + LinkNode *v_ls = NULL; + BMVert *v_pair[2] = {v1, v2}; + unsigned int i; + + for (i = 0; i < 2; i++) { + BMVert *v = v_pair[i]; + VertNetInfo *vn = &vnet_info[BM_elem_index_get(v)]; + const int pass = vn->pass; + do { + BLI_linklist_prepend_alloca(&v_ls, v); + v_ls_tot += 1; + v = vn->prev; + vn = &vnet_info[BM_elem_index_get(v)]; + } while (vn->pass == pass); + } + + if (v_ls_tot) { + BMVert **vert_arr = BLI_array_alloca(vert_arr, v_ls_tot); + LinkNode *v_lnk; + for (i = 0, v_lnk = v_ls; i < v_ls_tot; v_lnk = v_lnk->next, i++) { + vert_arr[i] = v_lnk->link; + } + + return BM_face_exists_overlap_subset(vert_arr, (int)v_ls_tot); + } + else { + return false; + } +} + +/** + * Create a face from the path. + */ +static BMFace *bm_edgenet_face_from_path( + BMesh *bm, LinkNode *path, const unsigned int path_len) +{ + BMFace *f; + LinkNode *v_lnk; + unsigned int i; + unsigned int i_prev; + + BMVert **vert_arr = BLI_array_alloca(vert_arr, path_len); + BMEdge **edge_arr = BLI_array_alloca(edge_arr, path_len); + + for (v_lnk = path, i = 0; v_lnk; v_lnk = v_lnk->next, i++) { + vert_arr[i] = v_lnk->link; + } + + i_prev = path_len - 1; + for (i = 0; i < path_len; i++) { + edge_arr[i_prev] = BM_edge_exists(vert_arr[i], vert_arr[i_prev]); + i_prev = i; + } + + /* no need for this, we do overlap checks before allowing the path to be used */ +#if 0 + if (BM_face_exists_multi(vert_arr, edge_arr, path_len)) { + return NULL; + } +#endif + + f = BM_face_create(bm, vert_arr, edge_arr, (int)path_len, NULL, BM_CREATE_NOP); + + return f; +} + +/** + * Step along the path from \a v_curr to any vert not already in the path. + * + * \return The connecting edge if the path is found, otherwise NULL. + */ +static BMEdge *bm_edgenet_path_step( + BMVert *v_curr, LinkNode **v_ls, + VertNetInfo *vnet_info, BLI_mempool *path_pool) +{ + const VertNetInfo *vn_curr = &vnet_info[BM_elem_index_get(v_curr)]; + + BMEdge *e; + BMIter iter; + unsigned int tot = 0; + unsigned int v_ls_tot = 0; + + BM_ITER_ELEM (e, &iter, v_curr, BM_EDGES_OF_VERT) { + BMVert *v_next = BM_edge_other_vert(e, v_curr); + if (v_next != vn_curr->prev) { + if (bm_edge_step_ok(e)) { + VertNetInfo *vn_next = &vnet_info[BM_elem_index_get(v_next)]; + + /* check we're not looping back on ourselves */ + if (vn_curr->pass != vn_next->pass) { + + if (vn_curr->pass == -vn_next->pass) { + if ((vn_curr->flag & VNINFO_FLAG_IS_MIXFACE) || + (vn_next->flag & VNINFO_FLAG_IS_MIXFACE)) + { + /* found connecting edge */ + if (bm_edgenet_path_check_overlap(v_curr, v_next, vnet_info) == false) { + return e; + } + } + } + else { + vn_next->face = bm_edge_face(e); + vn_next->pass = vn_curr->pass; + vn_next->prev = v_curr; + + /* flush flag down the path */ + vn_next->flag &= ~VNINFO_FLAG_IS_MIXFACE; + if ((vn_curr->flag & VNINFO_FLAG_IS_MIXFACE) || + (vn_next->face == -1) || + (vn_next->face != vn_curr->face)) + { + vn_next->flag |= VNINFO_FLAG_IS_MIXFACE; + } + + /* add to the list! */ + BLI_linklist_prepend_pool(v_ls, v_next, path_pool); + v_ls_tot += 1; + } + } + } + tot += 1; + } + } + + /* trick to walk along wire-edge paths */ + if (v_ls_tot == 1 && tot == 1) { + v_curr = BLI_linklist_pop_pool(v_ls, path_pool); + bm_edgenet_path_step(v_curr, v_ls, vnet_info, path_pool); + } + + return NULL; +} + +/** + * Given an edge, find the first path that can form a face. + * + * \return A linked list of verts. + */ +static LinkNode *bm_edgenet_path_calc( + BMEdge *e, const int pass_nr, const unsigned int path_cost_max, + unsigned int *r_path_len, unsigned int *r_path_cost, + VertNetInfo *vnet_info, BLI_mempool *path_pool) +{ + VertNetInfo *vn_1, *vn_2; + const int f_index = bm_edge_face(e); + bool found; + + LinkNode *v_ls_prev = NULL; + LinkNode *v_ls_next = NULL; + + unsigned int path_cost_accum = 0; + + BLI_assert(bm_edge_step_ok(e)); + + *r_path_len = 0; + *r_path_cost = 0; + + vn_1 = &vnet_info[BM_elem_index_get(e->v1)]; + vn_2 = &vnet_info[BM_elem_index_get(e->v2)]; + + vn_1->pass = pass_nr; + vn_2->pass = -pass_nr; + + vn_1->prev = e->v2; + vn_2->prev = e->v1; + + vn_1->face = + vn_2->face = f_index; + + vn_1->flag = + vn_2->flag = (f_index == -1) ? VNINFO_FLAG_IS_MIXFACE : 0; + + /* prime the searchlist */ + BLI_linklist_prepend_pool(&v_ls_prev, e->v1, path_pool); + BLI_linklist_prepend_pool(&v_ls_prev, e->v2, path_pool); + + do { + found = false; + + /* no point to continue, we're over budget */ + if (path_cost_accum >= path_cost_max) { + BLI_linklist_free_pool(v_ls_next, NULL, path_pool); + BLI_linklist_free_pool(v_ls_prev, NULL, path_pool); + return NULL; + } + + while (v_ls_prev) { + const LinkNode *v_ls_next_old = v_ls_next; + BMVert *v = BLI_linklist_pop_pool(&v_ls_prev, path_pool); + BMEdge *e_found = bm_edgenet_path_step(v, &v_ls_next, vnet_info, path_pool); + + if (e_found) { + LinkNode *path = NULL; + unsigned int path_len; + BLI_linklist_free_pool(v_ls_next, NULL, path_pool); + BLI_linklist_free_pool(v_ls_prev, NULL, path_pool); + + // BLI_assert(BLI_mempool_count(path_pool) == 0); + + path_len = bm_edgenet_path_from_pass(e_found->v1, &path, vnet_info, path_pool); + BLI_linklist_reverse(&path); + path_len += bm_edgenet_path_from_pass(e_found->v2, &path, vnet_info, path_pool); + *r_path_len = path_len; + *r_path_cost = path_cost_accum; + return path; + } + else { + /* check if a change was made */ + if (v_ls_next_old != v_ls_next) { + found = true; + } + } + + } + BLI_assert(v_ls_prev == NULL); + + path_cost_accum++; + + /* swap */ + v_ls_prev = v_ls_next; + v_ls_next = NULL; + + } while (found); + + BLI_assert(v_ls_prev == NULL); + BLI_assert(v_ls_next == NULL); + + /* tag not to search again */ + BM_elem_flag_disable(e, BM_ELEM_TAG); + + return NULL; +} + +/** + * Wrapper for #bm_edgenet_path_calc which ensures all included edges + * _don't_ have a better option. + */ +static LinkNode *bm_edgenet_path_calc_best( + BMEdge *e, int *pass_nr, unsigned int path_cost_max, + unsigned int *r_path_len, unsigned int *r_path_cost, + VertNetInfo *vnet_info, BLI_mempool *path_pool) +{ + LinkNode *path; + unsigned int path_cost; + + path = bm_edgenet_path_calc(e, *pass_nr, path_cost_max, + r_path_len, &path_cost, + vnet_info, path_pool); + (*pass_nr)++; + + if (path == NULL) { + return NULL; + } + else if (path_cost <= 1) { + /* any face that takes 1-2 iterations to find we consider valid */ + return path; + } + else { + /* Check every edge to see if any can give a better path. + * This avoids very strange/long paths from being created. */ + + const unsigned int path_len = *r_path_len; + unsigned int i, i_prev; + BMVert **vert_arr = BLI_array_alloca(vert_arr, path_len); + LinkNode *v_lnk; + + for (v_lnk = path, i = 0; v_lnk; v_lnk = v_lnk->next, i++) { + vert_arr[i] = v_lnk->link; + } + + i_prev = path_len - 1; + for (i = 0; i < path_len; i++) { + BMEdge *e_other = BM_edge_exists(vert_arr[i], vert_arr[i_prev]); + if (e_other != e) { + LinkNode *path_test; + unsigned int path_len_test; + unsigned int path_cost_test; + + path_test = bm_edgenet_path_calc(e_other, *pass_nr, path_cost, + &path_len_test, &path_cost_test, + vnet_info, path_pool); + (*pass_nr)++; + + if (path_test) { + BLI_assert(path_cost_test < path_cost); + + BLI_linklist_free_pool(path, NULL, path_pool); + path = path_test; + *r_path_len = path_len_test; + *r_path_cost = path_cost_test; + path_cost = path_cost_test; + } + } + + i_prev = i; + } + } + return path; +} + +/** + * Fill in faces from an edgenet made up of boundary and wire edges. + * + * \note New faces currently don't have their normals calculated and are flipped randomly. + * The caller needs to flip faces correctly. + * + * \param bm The mesh to operate on. + * \param use_edge_tag Only fill tagged edges. + * \param face_oflag if nonzero, apply all new faces with this bmo flag. + */ +void BM_mesh_edgenet(BMesh *bm, + const bool use_edge_tag, const bool use_new_face_tag) +{ + VertNetInfo *vnet_info = MEM_callocN(sizeof(*vnet_info) * (size_t)bm->totvert, __func__); + BLI_mempool *edge_queue_pool = BLI_mempool_create(sizeof(LinkNode), 1, 512, 0); + BLI_mempool *path_pool = BLI_mempool_create(sizeof(LinkNode), 1, 512, 0); + LinkNode *edge_queue = NULL; + + BMEdge *e; + BMIter iter; + + int pass_nr = 1; + + if (use_edge_tag == false) { + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + BM_elem_flag_set(e, BM_ELEM_TAG, bm_edge_step_ok(e)); + } + } + + BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE); + + while (true) { + LinkNode *path = NULL; + unsigned int path_len; + unsigned int path_cost; + + e = bm_edgenet_edge_get_next(bm, &edge_queue, edge_queue_pool); + if (e == NULL) { + break; + } + + BLI_assert(bm_edge_step_ok(e) == true); + + path = bm_edgenet_path_calc_best(e, &pass_nr, UINT_MAX, + &path_len, &path_cost, + vnet_info, path_pool); + + if (path) { + BMFace *f = bm_edgenet_face_from_path(bm, path, path_len); + /* queue edges to operate on */ + BMLoop *l_first, *l_iter; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (bm_edge_step_ok(l_iter->e)) { + BLI_linklist_prepend_pool(&edge_queue, l_iter->e, edge_queue_pool); + } + } while ((l_iter = l_iter->next) != l_first); + + if (use_new_face_tag) { + BM_elem_flag_enable(f, BM_ELEM_TAG); + } + + /* the face index only needs to be unique, not kept valid */ + BM_elem_index_set(f, bm->totface - 1); /* set_dirty */ + } + + BLI_linklist_free_pool(path, NULL, path_pool); + BLI_assert(BLI_mempool_count(path_pool) == 0); + } + + bm->elem_index_dirty |= BM_FACE; + + BLI_mempool_destroy(edge_queue_pool); + BLI_mempool_destroy(path_pool); + MEM_freeN(vnet_info); +} diff --git a/source/blender/compositor/operations/COM_RenderLayersColorOperation.h b/source/blender/bmesh/tools/bmesh_edgenet.h index 4f4dfbfb6f3..327a7f5aa23 100644 --- a/source/blender/compositor/operations/COM_RenderLayersColorOperation.h +++ b/source/blender/bmesh/tools/bmesh_edgenet.h @@ -1,5 +1,5 @@ /* - * Copyright 2011, Blender Foundation. + * ***** 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 @@ -15,19 +15,19 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** */ -#ifndef _COM_RenderLayersColorOperation_h -#define _COM_RenderLayersColorOperation_h +#ifndef __BMESH_EDGENET_H__ +#define __BMESH_EDGENET_H__ -#include "COM_RenderLayersBaseProg.h" +/** \file blender/bmesh/tools/bmesh_edgenet.h + * \ingroup bmesh + */ -class RenderLayersColorOperation : public RenderLayersBaseProg { -public: - RenderLayersColorOperation(); -}; +void BM_mesh_edgenet(BMesh *bm, + const bool use_edge_tag, const bool use_new_face_tag); -#endif +#endif /* __BMESH_EDGENET_H__ */ diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.c b/source/blender/bmesh/tools/bmesh_edgesplit.c index aad600d13fa..412253aafe9 100644 --- a/source/blender/bmesh/tools/bmesh_edgesplit.c +++ b/source/blender/bmesh/tools/bmesh_edgesplit.c @@ -193,11 +193,13 @@ void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, con bmesh_vert_separate(bm, v, &vtar, &vtar_len, copy_select); - if (vtar_len) { + /* first value is always in 'v' */ + if (vtar_len > 1) { BMEditSelection *ese = BLI_ghash_lookup(ese_gh, v); + BLI_assert(v == vtar[0]); if (UNLIKELY(ese)) { int j; - for (j = 0; j < vtar_len; j++) { + for (j = 1; j < vtar_len; j++) { BLI_assert(v != vtar[j]); BM_select_history_store_after_notest(bm, ese, vtar[j]); } diff --git a/source/blender/bmesh/tools/bmesh_triangulate.h b/source/blender/bmesh/tools/bmesh_triangulate.h index 936a90d3a16..141aa2f82b4 100644 --- a/source/blender/bmesh/tools/bmesh_triangulate.h +++ b/source/blender/bmesh/tools/bmesh_triangulate.h @@ -27,10 +27,10 @@ * */ -#ifndef __BMESH_TRIAMGULATE_H__ -#define __BMESH_TRIAMGULATE_H__ +#ifndef __BMESH_TRIANGULATE_H__ +#define __BMESH_TRIANGULATE_H__ void BM_mesh_triangulate(BMesh *bm, const bool use_beauty, const bool tag_only, BMOperator *op, BMOpSlot *slot_facemap_out); -#endif /* __BMESH_TRIAMGULATE_H__ */ +#endif /* __BMESH_TRIANGULATE_H__ */ diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp index bcbcdd42752..c1b6dc83139 100644 --- a/source/blender/collada/AnimationExporter.cpp +++ b/source/blender/collada/AnimationExporter.cpp @@ -963,10 +963,10 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj else copy_m4_m4(mat, pchan->pose_mat); - // SECOND_LIFE_COMPATIBILITY + // OPEN_SIM_COMPATIBILITY // AFAIK animation to second life is via BVH, but no // reason to not have the collada-animation be correct - if (export_settings->second_life) { + if (export_settings->open_sim) { float temp[4][4]; copy_m4_m4(temp, bone->arm_mat); temp[3][0] = temp[3][1] = temp[3][2] = 0.0f; diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp index 438421ccd14..174331c4644 100644 --- a/source/blender/collada/ArmatureExporter.cpp +++ b/source/blender/collada/ArmatureExporter.cpp @@ -193,11 +193,11 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce, // and not it's head, seems arbitrary. (*i)->parentinv[3][1] += bone->length; - // SECOND_LIFE_COMPATIBILITY + // OPEN_SIM_COMPATIBILITY // TODO: when such objects are animated as // single matrix the tweak must be applied // to the result. - if (export_settings->second_life) { + if (export_settings->open_sim) { // tweak objects parentinverse to match compatibility float temp[4][4]; @@ -272,8 +272,8 @@ void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW: copy_m4_m4(mat, bone->arm_mat); } - // SECOND_LIFE_COMPATIBILITY - if (export_settings->second_life) { + // OPEN_SIM_COMPATIBILITY + if (export_settings->open_sim) { // Remove rotations vs armature from transform // parent_rest_rot * mat * irest_rot float temp[4][4]; diff --git a/source/blender/collada/CameraExporter.cpp b/source/blender/collada/CameraExporter.cpp index fc56ff8c63c..649288c2db4 100644 --- a/source/blender/collada/CameraExporter.cpp +++ b/source/blender/collada/CameraExporter.cpp @@ -63,7 +63,6 @@ void CamerasExporter::exportCameras(Scene *sce) } void CamerasExporter::operator()(Object *ob, Scene *sce) { - // TODO: shiftx, shifty, YF_dofdist Camera *cam = (Camera *)ob->data; std::string cam_id(get_camera_id(ob)); std::string cam_name(id_name(cam)); @@ -78,7 +77,9 @@ void CamerasExporter::operator()(Object *ob, Scene *sce) persp.setZFar(cam->clipend, false, "zfar"); persp.setZNear(cam->clipsta, false, "znear"); COLLADASW::Camera ccam(mSW, &persp, cam_id, cam_name); + exportBlenderProfile(ccam, cam); addCamera(ccam); + break; } case CAM_ORTHO: @@ -90,8 +91,17 @@ void CamerasExporter::operator()(Object *ob, Scene *sce) ortho.setZFar(cam->clipend, false, "zfar"); ortho.setZNear(cam->clipsta, false, "znear"); COLLADASW::Camera ccam(mSW, &ortho, cam_id, cam_name); + exportBlenderProfile(ccam, cam); addCamera(ccam); break; } } } +bool CamerasExporter::exportBlenderProfile(COLLADASW::Camera &cm,Camera *cam) +{ + cm.addExtraTechniqueParameter("blender","shiftx",cam->shiftx); + cm.addExtraTechniqueParameter("blender","shifty",cam->shifty); + cm.addExtraTechniqueParameter("blender","YF_dofdist",cam->YF_dofdist); + return true; + +} diff --git a/source/blender/collada/CameraExporter.h b/source/blender/collada/CameraExporter.h index 5405df8ab9e..a0c2d5790c8 100644 --- a/source/blender/collada/CameraExporter.h +++ b/source/blender/collada/CameraExporter.h @@ -37,6 +37,7 @@ extern "C" { } #include "ExportSettings.h" +#include "DNA_camera_types.h" class CamerasExporter: COLLADASW::LibraryCameras { @@ -45,6 +46,7 @@ public: void exportCameras(Scene *sce); void operator()(Object *ob, Scene *sce); private: + bool exportBlenderProfile(COLLADASW::Camera &cla,Camera *cam); const ExportSettings *export_settings; }; diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp index d04ed8d6fa1..948a3dc5ae1 100644 --- a/source/blender/collada/ControllerExporter.cpp +++ b/source/blender/collada/ControllerExporter.cpp @@ -507,8 +507,8 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas float world[4][4]; float inv_bind_mat[4][4]; - // SECOND_LIFE_COMPATIBILITY - if (export_settings->second_life) { + // OPEN_SIM_COMPATIBILITY + if (export_settings->open_sim) { // Only translations, no rotation vs armature float temp[4][4]; unit_m4(temp); diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index c6337e27218..79c725166f6 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -933,6 +933,7 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera) Camera *cam = NULL; std::string cam_id, cam_name; + ExtraTags *et=getExtraTags(camera->getUniqueId()); cam_id = camera->getOriginalId(); cam_name = camera->getName(); if (cam_name.size()) cam = (Camera *)BKE_camera_add(G.main, (char *)cam_name.c_str()); @@ -942,6 +943,12 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera) fprintf(stderr, "Cannot create camera.\n"); return true; } + + if (et && et->isProfile("blender")) { + et->setData("shiftx",&(cam->shiftx)); + et->setData("shifty",&(cam->shifty)); + et->setData("YF_dofdist",&(cam->YF_dofdist)); + } cam->clipsta = camera->getNearClippingPlane().getValue(); cam->clipend = camera->getFarClippingPlane().getValue(); diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h index f9eb4cbc26f..3dc7e74379e 100644 --- a/source/blender/collada/ExportSettings.h +++ b/source/blender/collada/ExportSettings.h @@ -50,7 +50,7 @@ public: bool use_object_instantiation; bool sort_by_name; BC_export_transformation_type export_transformation_type; - bool second_life; + bool open_sim; char *filepath; LinkNode *export_set; diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index 8aa68ed9d04..c7652bd7ae7 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -665,7 +665,12 @@ void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i, v[0] = (*values)[i++]; v[1] = (*values)[i++]; - v[2] = (*values)[i]; + if (stride>=3) { + v[2] = (*values)[i]; + } + else { + v[2] = 0.0f; + } } break; @@ -676,13 +681,19 @@ void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i, v[0] = (float)(*values)[i++]; v[1] = (float)(*values)[i++]; - v[2] = (float)(*values)[i]; + if (stride >= 3) { + v[2] = (float)(*values)[i]; + } + else { + v[2] = 0.0f; + } } break; default: break; } } + bool MeshImporter::is_flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count) { float a[3], b[3]; @@ -857,7 +868,7 @@ std::vector<Object *> MeshImporter::get_all_users_of(Mesh *reference_mesh) * * During import all materials have been assigned to Object. * Now we iterate over the imported objects and optimize - * the assignements as follows: + * the assignments as follows: * * for each imported geometry: * if number of users is 1: diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp index 1eb5ac6ca4d..223ab3eca2a 100644 --- a/source/blender/collada/collada.cpp +++ b/source/blender/collada/collada.cpp @@ -79,20 +79,10 @@ int collada_export(Scene *sce, int use_object_instantiation, int sort_by_name, BC_export_transformation_type export_transformation_type, - int second_life) + int open_sim) { ExportSettings export_settings; - /* annoying, collada crashes if file cant be created! [#27162] */ - if (!BLI_exists(filepath)) { - BLI_make_existing_file(filepath); /* makes the dir if its not there */ - if (!BLI_file_touch(filepath)) { - fprintf(stdout, "Collada export: Can not create: %s\n", filepath); - return 0; - } - } - /* end! */ - export_settings.filepath = (char *)filepath; export_settings.apply_modifiers = apply_modifiers != 0; @@ -112,7 +102,7 @@ int collada_export(Scene *sce, export_settings.use_object_instantiation = use_object_instantiation != 0; export_settings.sort_by_name = sort_by_name != 0; export_settings.export_transformation_type = export_transformation_type; - export_settings.second_life = second_life != 0; + export_settings.open_sim = open_sim != 0; int includeFilter = OB_REL_NONE; diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h index b3a8156b6fe..e96bc2ea8a4 100644 --- a/source/blender/collada/collada.h +++ b/source/blender/collada/collada.h @@ -77,7 +77,7 @@ int collada_export(Scene *sce, int use_object_instantiation, int sort_by_name, BC_export_transformation_type export_transformation_type, - int second_life); + int open_sim); diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index 3e17472e9c2..146aff5ca5b 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -56,7 +56,9 @@ extern "C" { #include "WM_api.h" // XXX hrm, see if we can do without this #include "WM_types.h" + #include "bmesh.h" +#include "bmesh_tools.h" } float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index) diff --git a/source/blender/collada/version.conf b/source/blender/collada/version.conf new file mode 100644 index 00000000000..d39af7a53df --- /dev/null +++ b/source/blender/collada/version.conf @@ -0,0 +1 @@ +463ba8a2ef5a021ce21df614dde29e0ee800e10b diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index c1b99274bed..e6a3c33ea5d 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -101,6 +101,8 @@ set(SRC intern/COM_ChannelInfo.h intern/COM_SingleThreadedNodeOperation.cpp intern/COM_SingleThreadedNodeOperation.h + intern/COM_Debug.cpp + intern/COM_Debug.h operations/COM_QualityStepHelper.h operations/COM_QualityStepHelper.cpp @@ -184,6 +186,9 @@ set(SRC nodes/COM_GlareNode.cpp nodes/COM_GlareNode.h + nodes/COM_PlaneTrackDeformNode.cpp + nodes/COM_PlaneTrackDeformNode.h + nodes/COM_CropNode.cpp nodes/COM_CropNode.h operations/COM_CropOperation.cpp @@ -365,48 +370,8 @@ set(SRC operations/COM_ColorSpillOperation.cpp operations/COM_ColorSpillOperation.h - operations/COM_RenderLayersBaseProg.cpp - operations/COM_RenderLayersBaseProg.h - operations/COM_RenderLayersImageProg.cpp - operations/COM_RenderLayersImageProg.h - operations/COM_RenderLayersAlphaProg.cpp - operations/COM_RenderLayersAlphaProg.h - operations/COM_RenderLayersDepthProg.cpp - operations/COM_RenderLayersDepthProg.h - operations/COM_RenderLayersNormalOperation.cpp - operations/COM_RenderLayersNormalOperation.h - operations/COM_RenderLayersSpeedOperation.cpp - operations/COM_RenderLayersSpeedOperation.h - operations/COM_RenderLayersColorOperation.cpp - operations/COM_RenderLayersColorOperation.h - operations/COM_RenderLayersUVOperation.cpp - operations/COM_RenderLayersUVOperation.h - operations/COM_RenderLayersMistOperation.cpp - operations/COM_RenderLayersMistOperation.h - operations/COM_RenderLayersObjectIndexOperation.cpp - operations/COM_RenderLayersObjectIndexOperation.h - operations/COM_RenderLayersMaterialIndexOperation.cpp - operations/COM_RenderLayersMaterialIndexOperation.h - operations/COM_RenderLayersDiffuseOperation.cpp - operations/COM_RenderLayersDiffuseOperation.h - operations/COM_RenderLayersSpecularOperation.cpp - operations/COM_RenderLayersSpecularOperation.h - operations/COM_RenderLayersShadowOperation.cpp - operations/COM_RenderLayersShadowOperation.h - operations/COM_RenderLayersAOOperation.cpp - operations/COM_RenderLayersAOOperation.h - operations/COM_RenderLayersEmitOperation.cpp - operations/COM_RenderLayersEmitOperation.h - operations/COM_RenderLayersReflectionOperation.cpp - operations/COM_RenderLayersReflectionOperation.h - operations/COM_RenderLayersRefractionOperation.cpp - operations/COM_RenderLayersRefractionOperation.h - operations/COM_RenderLayersEnvironmentOperation.cpp - operations/COM_RenderLayersEnvironmentOperation.h - operations/COM_RenderLayersIndirectOperation.cpp - operations/COM_RenderLayersIndirectOperation.h - operations/COM_RenderLayersCyclesOperation.cpp - operations/COM_RenderLayersCyclesOperation.h + operations/COM_RenderLayersProg.cpp + operations/COM_RenderLayersProg.h operations/COM_ImageOperation.cpp operations/COM_ImageOperation.h @@ -431,37 +396,11 @@ set(SRC operations/COM_PreviewOperation.cpp operations/COM_SplitOperation.h operations/COM_SplitOperation.cpp - operations/COM_ConvertValueToColorProg.h - operations/COM_ConvertValueToColorProg.cpp - operations/COM_ConvertColorToValueProg.h - operations/COM_ConvertColorToValueProg.cpp - operations/COM_ConvertColorToBWOperation.h - operations/COM_ConvertColorToBWOperation.cpp - operations/COM_ConvertColorToVectorOperation.h - operations/COM_ConvertColorToVectorOperation.cpp - operations/COM_ConvertValueToVectorOperation.h - operations/COM_ConvertValueToVectorOperation.cpp - operations/COM_ConvertVectorToColorOperation.h - operations/COM_ConvertVectorToColorOperation.cpp - operations/COM_ConvertVectorToValueOperation.h - operations/COM_ConvertVectorToValueOperation.cpp operations/COM_ConvertDepthToRadiusOperation.h operations/COM_ConvertDepthToRadiusOperation.cpp operations/COM_ZCombineOperation.cpp operations/COM_ZCombineOperation.h - operations/COM_ConvertRGBToYCCOperation.h - operations/COM_ConvertRGBToYCCOperation.cpp - operations/COM_ConvertYCCToRGBOperation.h - operations/COM_ConvertYCCToRGBOperation.cpp - operations/COM_ConvertRGBToYUVOperation.h - operations/COM_ConvertRGBToYUVOperation.cpp - operations/COM_ConvertYUVToRGBOperation.h - operations/COM_ConvertYUVToRGBOperation.cpp - operations/COM_ConvertRGBToHSVOperation.h - operations/COM_ConvertRGBToHSVOperation.cpp - operations/COM_ConvertHSVToRGBOperation.h - operations/COM_ConvertHSVToRGBOperation.cpp operations/COM_ChangeHSVOperation.h operations/COM_ChangeHSVOperation.cpp operations/COM_ColorCurveOperation.h @@ -488,25 +427,13 @@ set(SRC operations/COM_ColorMatteOperation.h operations/COM_ChannelMatteOperation.cpp operations/COM_ChannelMatteOperation.h - operations/COM_ConvertPremulToStraightOperation.cpp - operations/COM_ConvertPremulToStraightOperation.h - operations/COM_ConvertStraightToPremulOperation.cpp - operations/COM_ConvertStraightToPremulOperation.h operations/COM_ReadBufferOperation.cpp operations/COM_ReadBufferOperation.h operations/COM_WriteBufferOperation.cpp operations/COM_WriteBufferOperation.h - operations/COM_MixBaseOperation.h - operations/COM_MixBaseOperation.cpp - operations/COM_MixBlendOperation.cpp - operations/COM_MixBlendOperation.h - operations/COM_MixGlareOperation.cpp - operations/COM_MixGlareOperation.h - operations/COM_MixAddOperation.h - operations/COM_MixAddOperation.cpp - operations/COM_MixMultiplyOperation.h - operations/COM_MixMultiplyOperation.cpp + operations/COM_MixOperation.h + operations/COM_MixOperation.cpp operations/COM_BrightnessOperation.cpp operations/COM_BrightnessOperation.h operations/COM_GammaOperation.cpp @@ -520,37 +447,6 @@ set(SRC operations/COM_SetVectorOperation.h operations/COM_SetVectorOperation.cpp - operations/COM_MixBurnOperation.h - operations/COM_MixBurnOperation.cpp - operations/COM_MixColorOperation.h - operations/COM_MixColorOperation.cpp - operations/COM_MixDarkenOperation.h - operations/COM_MixDarkenOperation.cpp - operations/COM_MixDodgeOperation.h - operations/COM_MixDodgeOperation.cpp - operations/COM_MixDifferenceOperation.h - operations/COM_MixDifferenceOperation.cpp - operations/COM_MixDivideOperation.h - operations/COM_MixDivideOperation.cpp - operations/COM_MixHueOperation.h - operations/COM_MixHueOperation.cpp - operations/COM_MixLightenOperation.h - operations/COM_MixLightenOperation.cpp - operations/COM_MixLinearLightOperation.h - operations/COM_MixLinearLightOperation.cpp - operations/COM_MixOverlayOperation.h - operations/COM_MixOverlayOperation.cpp - operations/COM_MixSaturationOperation.h - operations/COM_MixSaturationOperation.cpp - operations/COM_MixScreenOperation.h - operations/COM_MixScreenOperation.cpp - operations/COM_MixSoftLightOperation.h - operations/COM_MixSoftLightOperation.cpp - operations/COM_MixValueOperation.h - operations/COM_MixValueOperation.cpp - operations/COM_MixSubtractOperation.h - operations/COM_MixSubtractOperation.cpp - operations/COM_MathBaseOperation.h operations/COM_MathBaseOperation.cpp @@ -595,6 +491,12 @@ set(SRC operations/COM_ProjectorLensDistortionOperation.h operations/COM_ScreenLensDistortionOperation.cpp operations/COM_ScreenLensDistortionOperation.h + operations/COM_PlaneTrackCommonOperation.cpp + operations/COM_PlaneTrackCommonOperation.h + operations/COM_PlaneTrackMaskOperation.cpp + operations/COM_PlaneTrackMaskOperation.h + operations/COM_PlaneTrackWarpImageOperation.cpp + operations/COM_PlaneTrackWarpImageOperation.h #Filter operations operations/COM_ConvolutionFilterOperation.h @@ -626,11 +528,8 @@ set(SRC #Convert operations operations/COM_IDMaskOperation.cpp operations/COM_IDMaskOperation.h - - operations/COM_SeparateChannelOperation.cpp - operations/COM_SeparateChannelOperation.h - operations/COM_CombineChannelsOperation.cpp - operations/COM_CombineChannelsOperation.h + operations/COM_ConvertOperation.cpp + operations/COM_ConvertOperation.h operations/COM_DotproductOperation.cpp operations/COM_DotproductOperation.h diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h index 204c3237e65..1936909b004 100644 --- a/source/blender/compositor/COM_compositor.h +++ b/source/blender/compositor/COM_compositor.h @@ -20,6 +20,9 @@ * Monique Dewanchand */ +#ifndef __COM_COMPOSITOR_H__ +#define __COM_COMPOSITOR_H__ + #ifdef __cplusplus extern "C" { #endif @@ -343,3 +346,5 @@ int COM_isHighlightedbNode(bNode *bnode); #ifdef __cplusplus } #endif + +#endif /* __COM_COMPOSITOR_H__ */ diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h index 3cc161a5877..3b0e9f239bb 100644 --- a/source/blender/compositor/COM_defines.h +++ b/source/blender/compositor/COM_defines.h @@ -20,8 +20,8 @@ * Monique Dewanchand */ -#ifndef _COM_defines_h_ -#define _COM_defines_h_ +#ifndef __COM_DEFINES_H__ +#define __COM_DEFINES_H__ /** * @brief possible data types for SocketConnection @@ -109,4 +109,4 @@ typedef enum OrderOfChunks { #define COM_BLUR_BOKEH_PIXELS 512 -#endif +#endif /* __COM_DEFINES_H__ */ diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp index 80ae952b87f..384cfbe47fa 100644 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ b/source/blender/compositor/intern/COM_Converter.cpp @@ -47,12 +47,7 @@ #include "COM_CombineYUVANode.h" #include "COM_CompositorNode.h" #include "COM_ConvertAlphaNode.h" -#include "COM_ConvertColorToVectorOperation.h" -#include "COM_ConvertColorToValueProg.h" -#include "COM_ConvertValueToColorProg.h" -#include "COM_ConvertValueToVectorOperation.h" -#include "COM_ConvertVectorToColorOperation.h" -#include "COM_ConvertVectorToValueOperation.h" +#include "COM_ConvertOperation.h" #include "COM_Converter.h" #include "COM_CropNode.h" #include "COM_DefocusNode.h" @@ -121,6 +116,7 @@ #include "COM_ViewerNode.h" #include "COM_ZCombineNode.h" #include "COM_PixelateNode.h" +#include "COM_PlaneTrackDeformNode.h" Node *Converter::convert(bNode *b_node, bool fast) { @@ -402,6 +398,9 @@ Node *Converter::convert(bNode *b_node, bool fast) case CMP_NODE_PIXELATE: node = new PixelateNode(b_node); break; + case CMP_NODE_PLANETRACKDEFORM: + node = new PlaneTrackDeformNode(b_node); + break; default: node = new MuteNode(b_node); break; @@ -416,13 +415,13 @@ void Converter::convertDataType(SocketConnection *connection, ExecutionSystem *s DataType toDatatype = inputSocket->getDataType(); NodeOperation *converter = NULL; if (fromDatatype == COM_DT_VALUE && toDatatype == COM_DT_COLOR) { - converter = new ConvertValueToColorProg(); + converter = new ConvertValueToColorOperation(); } else if (fromDatatype == COM_DT_VALUE && toDatatype == COM_DT_VECTOR) { converter = new ConvertValueToVectorOperation(); } else if (fromDatatype == COM_DT_COLOR && toDatatype == COM_DT_VALUE) { - converter = new ConvertColorToValueProg(); + converter = new ConvertColorToValueOperation(); } else if (fromDatatype == COM_DT_COLOR && toDatatype == COM_DT_VECTOR) { converter = new ConvertColorToVectorOperation(); diff --git a/source/blender/compositor/intern/COM_Debug.cpp b/source/blender/compositor/intern/COM_Debug.cpp new file mode 100644 index 00000000000..b57de38522a --- /dev/null +++ b/source/blender/compositor/intern/COM_Debug.cpp @@ -0,0 +1,413 @@ +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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. + * + * Contributor: + * Lukas Toenne + */ + +#include "COM_Debug.h" + +#ifdef COM_DEBUG + +#include <typeinfo> +#include <map> +#include <vector> + +extern "C" { +#include "BLI_fileops.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "DNA_node_types.h" +#include "BKE_node.h" +} + +#include "COM_Node.h" +#include "COM_ExecutionSystem.h" +#include "COM_ExecutionGroup.h" + +#include "COM_ReadBufferOperation.h" +#include "COM_ViewerOperation.h" +#include "COM_WriteBufferOperation.h" + + +int DebugInfo::m_file_index = 0; +DebugInfo::NodeNameMap DebugInfo::m_node_names; +std::string DebugInfo::m_current_node_name; +DebugInfo::GroupStateMap DebugInfo::m_group_states; + +std::string DebugInfo::node_name(NodeBase *node) +{ + NodeNameMap::const_iterator it = m_node_names.find(node); + if (it != m_node_names.end()) + return it->second; + else + return ""; +} + +void DebugInfo::convert_started() +{ + m_node_names.clear(); +} + +void DebugInfo::execute_started(ExecutionSystem *system) +{ + m_file_index = 1; + m_group_states.clear(); + for (int i = 0; i < system->getExecutionGroups().size(); ++i) + m_group_states[system->getExecutionGroups()[i]] = EG_WAIT; +} + +void DebugInfo::node_added(Node *node) +{ + m_node_names[node] = std::string(node->getbNode() ? node->getbNode()->name : ""); +} + +void DebugInfo::node_to_operations(Node *node) +{ + m_current_node_name = m_node_names[node]; +} + +void DebugInfo::operation_added(NodeOperation *operation) +{ + m_node_names[operation] = m_current_node_name; +} + +void DebugInfo::operation_read_write_buffer(NodeOperation *operation) +{ + m_current_node_name = m_node_names[operation]; +} + +void DebugInfo::execution_group_started(ExecutionGroup *group) +{ + m_group_states[group] = EG_RUNNING; +} + +void DebugInfo::execution_group_finished(ExecutionGroup *group) +{ + m_group_states[group] = EG_FINISHED; +} + +int DebugInfo::graphviz_operation(ExecutionSystem *system, NodeOperation *operation, ExecutionGroup *group, char *str, int maxlen) +{ + int len = 0; + + std::string fillcolor = "gainsboro"; + if (operation->isViewerOperation()) { + ViewerOperation *viewer = (ViewerOperation *)operation; + if (viewer->isActiveViewerOutput()) { + fillcolor = "lightskyblue1"; + } + else { + fillcolor = "lightskyblue3"; + } + } + else if (operation->isOutputOperation(system->getContext().isRendering())) { + fillcolor = "dodgerblue1"; + } + else if (operation->isSetOperation()) { + fillcolor = "khaki1"; + } + else if (operation->isReadBufferOperation()) { + fillcolor = "darkolivegreen3"; + } + else if (operation->isWriteBufferOperation()) { + fillcolor = "darkorange"; + } + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "// OPERATION: %p\r\n", operation); + if (group) + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\"O_%p_%p\"", operation, group); + else + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\"O_%p\"", operation); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, " [fillcolor=%s,style=filled,shape=record,label=\"{", fillcolor.c_str()); + + int totinputs = operation->getNumberOfInputSockets(); + if (totinputs != 0) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "{"); + for (int k = 0; k < totinputs; k++) { + InputSocket *socket = operation->getInputSocket(k); + if (k != 0) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|"); + } + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<IN_%p>", socket); + switch (socket->getDataType()) { + case COM_DT_VALUE: + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Value"); + break; + case COM_DT_VECTOR: + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Vector"); + break; + case COM_DT_COLOR: + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Color"); + break; + } + } + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|"); + } + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "%s\\n(%s)", m_node_names[operation].c_str(), typeid(*operation).name()); + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, " (%d,%d)", operation->getWidth(), operation->getHeight()); + + int totoutputs = operation->getNumberOfOutputSockets(); + if (totoutputs != 0) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "{"); + for (int k = 0; k < totoutputs; k++) { + OutputSocket *socket = operation->getOutputSocket(k); + if (k != 0) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "|"); + } + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<OUT_%p>", socket); + switch (socket->getDataType()) { + case COM_DT_VALUE: + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Value"); + break; + case COM_DT_VECTOR: + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Vector"); + break; + case COM_DT_COLOR: + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Color"); + break; + } + } + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}"); + } + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\"]"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\r\n"); + + return len; +} + +int DebugInfo::graphviz_legend_color(const char *name, const char *color, char *str, int maxlen) +{ + int len = 0; + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<TR><TD>%s</TD><TD BGCOLOR=\"%s\"></TD></TR>\r\n", name, color); + return len; +} + +int DebugInfo::graphviz_legend_line(const char *name, const char *color, const char *style, char *str, int maxlen) +{ + /* XXX TODO */ + int len = 0; + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\r\n"); + return len; +} + +int DebugInfo::graphviz_legend_group(const char *name, const char *color, const char *style, char *str, int maxlen) +{ + int len = 0; + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<TR><TD>%s</TD><TD CELLPADDING=\"4\"><TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\"><TR><TD BGCOLOR=\"%s\"></TD></TR></TABLE></TD></TR>\r\n", name, color); + return len; +} + +int DebugInfo::graphviz_legend(char *str, int maxlen) +{ + int len = 0; + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "{\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "rank = sink;\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "Legend [shape=none, margin=0, label=<\r\n"); + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, " <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<TR><TD COLSPAN=\"2\"><B>Legend</B></TD></TR>\r\n"); + + len += graphviz_legend_color("Operation", "gainsboro", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_color("Output", "dodgerblue1", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_color("Viewer", "lightskyblue3", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_color("Active Viewer", "lightskyblue1", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_color("Write Buffer", "darkorange", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_color("Read Buffer", "darkolivegreen3", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_color("Input Value", "khaki1", str + len, maxlen > len ? maxlen - len : 0); + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "<TR><TD></TD></TR>\r\n"); + + len += graphviz_legend_group("Group Waiting", "white", "dashed", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_group("Group Running", "firebrick1", "solid", str + len, maxlen > len ? maxlen - len : 0); + len += graphviz_legend_group("Group Finished", "chartreuse4", "solid", str + len, maxlen > len ? maxlen - len : 0); + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "</TABLE>\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, ">];\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\r\n"); + + return len; +} + +bool DebugInfo::graphviz_system(ExecutionSystem *system, char *str, int maxlen) +{ + char strbuf[64]; + int len = 0; + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "digraph compositorexecution {\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "ranksep=1.5\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "splines=false\r\n"); + + int totnodes = system->getNodes().size(); + for (int i = 0; i < totnodes; i++) { + Node *node = system->getNodes()[i]; + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "// NODE: %s\r\n", node->getbNode()->typeinfo->ui_name); + } + + int totgroups = system->getExecutionGroups().size(); + int totops = system->getOperations().size(); + std::map<NodeOperation *, std::vector<std::string> > op_groups; + for (int i = 0; i < totgroups; ++i) { + ExecutionGroup *group = system->getExecutionGroups()[i]; + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "// GROUP: %d\r\n", i); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "subgraph cluster_%d{\r\n", i); + /* used as a check for executing group */ + if (m_group_states[group] == EG_WAIT) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "style=dashed\r\n"); + } + else if (m_group_states[group] == EG_RUNNING) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "style=filled\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "color=black\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "fillcolor=firebrick1\r\n"); + } + else if (m_group_states[group] == EG_FINISHED) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "style=filled\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "color=black\r\n"); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "fillcolor=chartreuse4\r\n"); + } + + for (int j = 0; j < totops; ++j) { + NodeOperation *operation = system->getOperations()[j]; + if (!group->containsOperation(operation)) + continue; + + sprintf(strbuf, "_%p", group); + op_groups[operation].push_back(std::string(strbuf)); + + len += graphviz_operation(system, operation, group, str + len, maxlen > len ? maxlen - len : 0); + } + +// len += snprintf(str+len, maxlen>len ? maxlen-len : 0, "// OUTPUTOPERATION: %p\r\n", group->getOutputNodeOperation()); +// len += snprintf(str+len, maxlen>len ? maxlen-len : 0, " O_%p\r\n", group->getOutputNodeOperation()); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\r\n"); + } + + /* operations not included in any group */ + for (int j = 0; j < totops; ++j) { + NodeOperation *operation = system->getOperations()[j]; + if (op_groups.find(operation) != op_groups.end()) + continue; + + op_groups[operation].push_back(std::string("")); + + len += graphviz_operation(system, operation, 0, str + len, maxlen > len ? maxlen - len : 0); + } + + for (int i = 0; i < totops; i++) { + NodeOperation *operation = system->getOperations()[i]; + + if (operation->isReadBufferOperation()) { + ReadBufferOperation *read = (ReadBufferOperation *)operation; + WriteBufferOperation *write = read->getMemoryProxy()->getWriteBufferOperation(); + std::vector<std::string> &read_groups = op_groups[read]; + std::vector<std::string> &write_groups = op_groups[write]; + + for (int k = 0; k < write_groups.size(); ++k) { + for (int l = 0; l < read_groups.size(); ++l) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\"O_%p%s\" -> \"O_%p%s\" [style=dotted]\r\n", write, write_groups[k].c_str(), read, read_groups[l].c_str()); + } + } + } + } + + int totcon = system->getConnections().size(); + for (int i = 0; i < totcon; i++) { + SocketConnection *connection = system->getConnections()[i]; + + std::string color; + if (!connection->isValid()) { + color = "red"; + } + else { + switch (connection->getFromSocket()->getDataType()) { + case COM_DT_VALUE: + color = "grey"; + break; + case COM_DT_VECTOR: + color = "blue"; + break; + case COM_DT_COLOR: + color = "orange"; + break; + } + } + + NodeBase *from_node = connection->getFromNode(); + NodeBase *to_node = connection->getToNode(); + OutputSocket *from_sock = connection->getFromSocket(); + InputSocket *to_sock = connection->getToSocket(); + if (from_node->isOperation() && to_node->isOperation()) { + NodeOperation *from_op = (NodeOperation *)from_node; + NodeOperation *to_op = (NodeOperation *)to_node; + std::vector<std::string> &from_groups = op_groups[from_op]; + std::vector<std::string> &to_groups = op_groups[to_op]; + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "// CONNECTION: %p.%p -> %p.%p\r\n", from_op, from_sock, to_op, to_sock); + for (int k = 0; k < from_groups.size(); ++k) { + for (int l = 0; l < to_groups.size(); ++l) { + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\"O_%p%s\":\"OUT_%p\":s -> \"O_%p%s\":\"IN_%p\":n", from_op, from_groups[k].c_str(), from_sock, to_op, to_groups[l].c_str(), to_sock); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, " [color=%s]", color.c_str()); + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\r\n"); + } + } + } + } + + len += graphviz_legend(str + len, maxlen > len ? maxlen - len : 0); + + len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "}\r\n"); + + return (len < maxlen); +} + +void DebugInfo::graphviz(ExecutionSystem *system) +{ + char str[1000000]; + if (graphviz_system(system, str, sizeof(str) - 1)) { + char basename[FILE_MAX]; + char filename[FILE_MAX]; + + BLI_snprintf(basename, sizeof(basename), "compositor_%d.dot", m_file_index); + BLI_join_dirfile(filename, sizeof(filename), BLI_temporary_dir(), basename); + ++m_file_index; + + FILE *fp = BLI_fopen(filename, "wb"); + fputs(str, fp); + fclose(fp); + } +} + +#else + +std::string DebugInfo::node_name(NodeBase */*node*/) { return ""; } +void DebugInfo::convert_started() {} +void DebugInfo::execute_started(ExecutionSystem */*system*/) {} +void DebugInfo::node_added(Node */*node*/) {} +void DebugInfo::node_to_operations(Node */*node*/) {} +void DebugInfo::operation_added(NodeOperation */*operation*/) {} +void DebugInfo::operation_read_write_buffer(NodeOperation */*operation*/) {} +void DebugInfo::execution_group_started(ExecutionGroup */*group*/) {} +void DebugInfo::execution_group_finished(ExecutionGroup */*group*/) {} +void DebugInfo::graphviz(ExecutionSystem */*system*/) {} + +#endif diff --git a/source/blender/compositor/intern/COM_Debug.h b/source/blender/compositor/intern/COM_Debug.h new file mode 100644 index 00000000000..cc108157769 --- /dev/null +++ b/source/blender/compositor/intern/COM_Debug.h @@ -0,0 +1,79 @@ +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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. + * + * Contributor: + * Lukas Toenne + */ + +#ifndef _COM_Debug_h +#define _COM_Debug_h + +#include <map> +#include <string> + +#include "COM_defines.h" + +class NodeBase; +class Node; +class NodeOperation; +class ExecutionSystem; +class ExecutionGroup; + +class DebugInfo { +public: + typedef enum { + EG_WAIT, + EG_RUNNING, + EG_FINISHED + } GroupState; + + typedef std::map<NodeBase *, std::string> NodeNameMap; + typedef std::map<ExecutionGroup *, GroupState> GroupStateMap; + + static std::string node_name(NodeBase *node); + + static void convert_started(); + static void execute_started(ExecutionSystem *system); + + static void node_added(Node *node); + static void node_to_operations(Node *node); + static void operation_added(NodeOperation *operation); + static void operation_read_write_buffer(NodeOperation *operation); + + static void execution_group_started(ExecutionGroup *group); + static void execution_group_finished(ExecutionGroup *group); + + static void graphviz(ExecutionSystem *system); + +#ifdef COM_DEBUG +protected: + static int graphviz_operation(ExecutionSystem *system, NodeOperation *operation, ExecutionGroup *group, char *str, int maxlen); + static int graphviz_legend_color(const char *name, const char *color, char *str, int maxlen); + static int graphviz_legend_line(const char *name, const char *color, const char *style, char *str, int maxlen); + static int graphviz_legend_group(const char *name, const char *color, const char *style, char *str, int maxlen); + static int graphviz_legend(char *str, int maxlen); + static bool graphviz_system(ExecutionSystem *system, char *str, int maxlen); + +private: + static int m_file_index; + static NodeNameMap m_node_names; /**< map nodes to usable names for debug output */ + static std::string m_current_node_name; /**< base name for all operations added by a node */ + static GroupStateMap m_group_states; /**< for visualizing group states */ +#endif +}; + +#endif diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp index 827b93c350e..a4ff1ce7a19 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp @@ -37,6 +37,7 @@ #include "COM_ViewerOperation.h" #include "COM_ChunkOrder.h" #include "COM_ExecutionSystemHelper.h" +#include "COM_Debug.h" #include "MEM_guardedalloc.h" #include "BLI_math.h" @@ -343,6 +344,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph) break; } + DebugInfo::execution_group_started(this); + DebugInfo::graphviz(graph); + bool breaked = false; bool finished = false; unsigned int startIndex = 0; @@ -383,6 +387,8 @@ void ExecutionGroup::execute(ExecutionSystem *graph) breaked = true; } } + DebugInfo::execution_group_finished(this); + DebugInfo::graphviz(graph); MEM_freeN(chunkOrder); } @@ -518,17 +524,19 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area // find all chunks inside the rect // determine minxchunk, minychunk, maxxchunk, maxychunk where x and y are chunknumbers - float chunkSizef = this->m_chunkSize; - int indexx, indexy; - int minxchunk = floor((area->xmin - this->m_viewerBorder.xmin) / chunkSizef); - int maxxchunk = ceil((area->xmax - 1) / chunkSizef); - int minychunk = floor((area->ymin - this->m_viewerBorder.ymin) / chunkSizef); - int maxychunk = ceil((area->ymax - 1) / chunkSizef); - minxchunk = max(minxchunk, 0); - minychunk = max(minychunk, 0); - maxxchunk = min(maxxchunk, (int)this->m_numberOfXChunks); - maxychunk = min(maxychunk, (int)this->m_numberOfYChunks); + int minx = max_ii(area->xmin - m_viewerBorder.xmin, 0); + int maxx = min_ii(area->xmax - m_viewerBorder.xmin, m_viewerBorder.xmax - m_viewerBorder.xmin); + int miny = max_ii(area->ymin - m_viewerBorder.ymin, 0); + int maxy = min_ii(area->ymax - m_viewerBorder.ymin, m_viewerBorder.ymax - m_viewerBorder.ymin); + int minxchunk = minx / (int)m_chunkSize; + int maxxchunk = (maxx + (int)m_chunkSize - 1) / (int)m_chunkSize; + int minychunk = miny / (int)m_chunkSize; + int maxychunk = (maxy + (int)m_chunkSize - 1) / (int)m_chunkSize; + minxchunk = max_ii(minxchunk, 0); + minychunk = max_ii(minychunk, 0); + maxxchunk = min_ii(maxxchunk, (int)m_numberOfXChunks); + maxychunk = min_ii(maxychunk, (int)m_numberOfYChunks); bool result = true; for (indexx = minxchunk; indexx < maxxchunk; indexx++) { diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h index 537dcb5974a..47f8447015d 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.h +++ b/source/blender/compositor/intern/COM_ExecutionGroup.h @@ -422,6 +422,9 @@ public: #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("COM:ExecutionGroup") #endif + + /* allow the DebugInfo class to peek inside without having to add getters for everything */ + friend class DebugInfo; }; #endif diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp index ad29405d2e9..716e99a0fa3 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp @@ -22,8 +22,6 @@ #include "COM_ExecutionSystem.h" -#include <sstream> - #include "PIL_time.h" #include "BLI_utildefines.h" extern "C" { @@ -40,6 +38,7 @@ extern "C" { #include "COM_WriteBufferOperation.h" #include "COM_ReadBufferOperation.h" #include "COM_ExecutionSystemHelper.h" +#include "COM_Debug.h" #include "BKE_global.h" @@ -101,9 +100,7 @@ ExecutionSystem::ExecutionSystem(RenderData *rd, bNodeTree *editingtree, bool re } } -#ifdef COM_DEBUG - ExecutionSystemHelper::debugDump(this); -#endif +// DebugInfo::graphviz(this); } ExecutionSystem::~ExecutionSystem() @@ -133,6 +130,8 @@ ExecutionSystem::~ExecutionSystem() void ExecutionSystem::execute() { + DebugInfo::execute_started(this); + unsigned int order = 0; for (vector<NodeOperation *>::iterator iter = this->m_operations.begin(); iter != this->m_operations.end(); ++iter) { NodeBase *node = *iter; @@ -199,11 +198,13 @@ void ExecutionSystem::executeGroups(CompositorPriority priority) void ExecutionSystem::addOperation(NodeOperation *operation) { ExecutionSystemHelper::addOperation(this->m_operations, operation); -// operation->setBTree + DebugInfo::operation_added(operation); } void ExecutionSystem::addReadWriteBufferOperations(NodeOperation *operation) { + DebugInfo::operation_read_write_buffer(operation); + // for every input add write and read operation if input is not a read operation // only add read operation to other links when they are attached to buffered operations. unsigned int index; @@ -283,8 +284,10 @@ static void debug_check_node_connections(Node *node) void ExecutionSystem::convertToOperations() { unsigned int index; + for (index = 0; index < this->m_nodes.size(); index++) { Node *node = (Node *)this->m_nodes[index]; + DebugInfo::node_to_operations(node); node->convertToOperations(this, &this->m_context); debug_check_node_connections(node); diff --git a/source/blender/compositor/intern/COM_ExecutionSystemHelper.cpp b/source/blender/compositor/intern/COM_ExecutionSystemHelper.cpp index 9024cd33745..9516deee7e3 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystemHelper.cpp +++ b/source/blender/compositor/intern/COM_ExecutionSystemHelper.cpp @@ -22,9 +22,6 @@ #include "COM_ExecutionSystemHelper.h" -#include <sstream> -#include <stdio.h> - #include "PIL_time.h" #include "COM_Converter.h" @@ -37,6 +34,7 @@ #include "COM_WriteBufferOperation.h" #include "COM_ReadBufferOperation.h" #include "COM_ViewerOperation.h" +#include "COM_Debug.h" extern "C" { #include "BKE_node.h" @@ -93,6 +91,8 @@ Node *ExecutionSystemHelper::addNode(vector<Node *>& nodes, bNode *b_node, bool if (node) { node->setIsInActiveGroup(inActiveGroup); addNode(nodes, node); + + DebugInfo::node_added(node); } return node; } @@ -166,144 +166,3 @@ SocketConnection *ExecutionSystemHelper::addLink(vector<SocketConnection *>& lin links.push_back(newconnection); return newconnection; } - -void ExecutionSystemHelper::debugDump(ExecutionSystem *system) -{ - Node *node; - NodeOperation *operation; - ExecutionGroup *group; - SocketConnection *connection; - int tot, tot2; - printf("-- BEGIN COMPOSITOR DUMP --\r\n"); - printf("digraph compositorexecution {\r\n"); - tot = system->getNodes().size(); - for (int i = 0; i < tot; i++) { - node = system->getNodes()[i]; - printf("// NODE: %s\r\n", node->getbNode()->typeinfo->ui_name); - } - tot = system->getOperations().size(); - for (int i = 0; i < tot; i++) { - operation = system->getOperations()[i]; - printf("// OPERATION: %p\r\n", operation); - printf("\t\"O_%p\"", operation); - printf(" [shape=record,label=\"{"); - tot2 = operation->getNumberOfInputSockets(); - if (tot2 != 0) { - printf("{"); - for (int j = 0; j < tot2; j++) { - InputSocket *socket = operation->getInputSocket(j); - if (j != 0) { - printf("|"); - } - printf("<IN_%p>", socket); - switch (socket->getDataType()) { - case COM_DT_VALUE: - printf("Value"); - break; - case COM_DT_VECTOR: - printf("Vector"); - break; - case COM_DT_COLOR: - printf("Color"); - break; - } - } - printf("}"); - printf("|"); - } - if (operation->isViewerOperation()) { - ViewerOperation *viewer = (ViewerOperation *)operation; - if (viewer->isActiveViewerOutput()) { - printf("Active viewer"); - } - else { - printf("Viewer"); - } - } - else if (operation->isOutputOperation(system->getContext().isRendering())) { - printf("Output"); - } - else if (operation->isSetOperation()) { - printf("Set"); - } - else if (operation->isReadBufferOperation()) { - printf("ReadBuffer"); - } - else if (operation->isWriteBufferOperation()) { - printf("WriteBuffer"); - } - else { - printf("O_%p", operation); - } - printf(" (%d,%d)", operation->getWidth(), operation->getHeight()); - tot2 = operation->getNumberOfOutputSockets(); - if (tot2 != 0) { - printf("|"); - printf("{"); - for (int j = 0; j < tot2; j++) { - OutputSocket *socket = operation->getOutputSocket(j); - if (j != 0) { - printf("|"); - } - printf("<OUT_%p>", socket); - switch (socket->getDataType()) { - case COM_DT_VALUE: - printf("Value"); - break; - case COM_DT_VECTOR: - printf("Vector"); - break; - case COM_DT_COLOR: - printf("Color"); - break; - } - } - printf("}"); - } - printf("}\"]"); - printf("\r\n"); - } - tot = system->getExecutionGroups().size(); - for (int i = 0; i < tot; i++) { - group = system->getExecutionGroups()[i]; - printf("// GROUP: %d\r\n", i); - printf("subgraph {\r\n"); - printf("// OUTPUTOPERATION: %p\r\n", group->getOutputNodeOperation()); - printf(" O_%p\r\n", group->getOutputNodeOperation()); - printf("}\r\n"); - } - tot = system->getOperations().size(); - for (int i = 0; i < tot; i++) { - operation = system->getOperations()[i]; - if (operation->isReadBufferOperation()) { - ReadBufferOperation *read = (ReadBufferOperation *)operation; - WriteBufferOperation *write = read->getMemoryProxy()->getWriteBufferOperation(); - printf("\t\"O_%p\" -> \"O_%p\" [style=dotted]\r\n", write, read); - } - } - tot = system->getConnections().size(); - for (int i = 0; i < tot; i++) { - connection = system->getConnections()[i]; - printf("// CONNECTION: %p.%p -> %p.%p\r\n", connection->getFromNode(), connection->getFromSocket(), connection->getToNode(), connection->getToSocket()); - printf("\t\"O_%p\":\"OUT_%p\" -> \"O_%p\":\"IN_%p\"", connection->getFromNode(), connection->getFromSocket(), connection->getToNode(), connection->getToSocket()); - if (!connection->isValid()) { - printf(" [color=red]"); - } - else { - switch (connection->getFromSocket()->getDataType()) { - case COM_DT_VALUE: - printf(" [color=grey]"); - break; - case COM_DT_VECTOR: - printf(" [color=blue]"); - break; - case COM_DT_COLOR: - printf(" [color=orange]"); - break; - } - } - printf("\r\n"); - } - printf("}\r\n"); - printf("-- END COMPOSITOR DUMP --\r\n"); -} diff --git a/source/blender/compositor/intern/COM_ExecutionSystemHelper.h b/source/blender/compositor/intern/COM_ExecutionSystemHelper.h index e05796b9127..002423c195c 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystemHelper.h +++ b/source/blender/compositor/intern/COM_ExecutionSystemHelper.h @@ -118,12 +118,6 @@ public: */ static SocketConnection *addLink(vector<SocketConnection *>& links, OutputSocket *fromSocket, InputSocket *toSocket); - /** - * @brief dumps the content of the execution system to standard out - * @param system the execution system to dump - */ - static void debugDump(ExecutionSystem *system); - #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("COM:ExecutionSystemHelper") #endif diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cpp b/source/blender/compositor/intern/COM_MemoryBuffer.cpp index 357a4c1d4c0..4bebf004a89 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.cpp +++ b/source/blender/compositor/intern/COM_MemoryBuffer.cpp @@ -335,8 +335,7 @@ void MemoryBuffer::readEWA(float result[4], float fx, float fy, float dx, float float tc[4]; const float wt = EWA_WTS[(Q < 0.f) ? 0 : (unsigned int)Q]; read(tc, clipuv(u, width), clipuv(v, height)); - madd_v3_v3fl(result, tc, wt); - result[3] += result[3] ? tc[3] * wt : 0.f; + madd_v4_v4fl(result, tc, wt); d += wt; } Q += DQ; @@ -346,9 +345,5 @@ void MemoryBuffer::readEWA(float result[4], float fx, float fy, float dx, float // d should hopefully never be zero anymore d = 1.f / d; - result[0] *= d; - result[1] *= d; - result[2] *= d; - // clipping can be ignored if alpha used, texr->ta already includes filtered edge - result[3] = result[3] ? result[3] * d : 1.f; + mul_v4_fl(result, d); } diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h index d176298578f..548744f6660 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.h +++ b/source/blender/compositor/intern/COM_MemoryBuffer.h @@ -46,6 +46,12 @@ typedef enum MemoryBufferState { COM_MB_TEMPORARILY = 6 } MemoryBufferState; +typedef enum MemoryBufferExtend { + COM_MB_CLIP, + COM_MB_EXTEND, + COM_MB_REPEAT +} MemoryBufferExtend; + class MemoryProxy; /** @@ -125,31 +131,66 @@ public: this->m_state = COM_MB_AVAILABLE; } - inline void read(float result[4], int x, int y) + inline void wrap_pixel(int &x, int &y, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y) { - if (x >= this->m_rect.xmin && x < this->m_rect.xmax && - y >= this->m_rect.ymin && y < this->m_rect.ymax) - { - const int dx = x - this->m_rect.xmin; - const int dy = y - this->m_rect.ymin; - const int offset = (this->m_chunkWidth * dy + dx) * COM_NUMBER_OF_CHANNELS; - copy_v4_v4(result, &this->m_buffer[offset]); + int w = m_rect.xmax - m_rect.xmin; + int h = m_rect.ymax - m_rect.ymin; + x = x - m_rect.xmin; + y = y - m_rect.ymin; + + switch (extend_x) { + case COM_MB_CLIP: + break; + case COM_MB_EXTEND: + if (x < 0) x = 0; + if (x >= w) x = w; + break; + case COM_MB_REPEAT: + x = (x >= 0.0f ? (x % w) : (x % w) + w); + break; } - else { + + switch (extend_y) { + case COM_MB_CLIP: + break; + case COM_MB_EXTEND: + if (y < 0) y = 0; + if (y >= h) y = h; + break; + case COM_MB_REPEAT: + y = (y >= 0.0f ? (y % h) : (y % h) + h); + break; + } + } + + inline void read(float result[4], int x, int y, + MemoryBufferExtend extend_x = COM_MB_CLIP, + MemoryBufferExtend extend_y = COM_MB_CLIP) + { + bool clip_x = (extend_x == COM_MB_CLIP && (x < m_rect.xmin || x >= m_rect.xmax)); + bool clip_y = (extend_y == COM_MB_CLIP && (y < m_rect.ymin || y >= m_rect.ymax)); + if (clip_x || clip_y) { + /* clip result outside rect is zero */ zero_v4(result); } + else { + wrap_pixel(x, y, extend_x, extend_y); + const int offset = (this->m_chunkWidth * y + x) * COM_NUMBER_OF_CHANNELS; + copy_v4_v4(result, &this->m_buffer[offset]); + } } - inline void readNoCheck(float result[4], int x, int y) + inline void readNoCheck(float result[4], int x, int y, + MemoryBufferExtend extend_x = COM_MB_CLIP, + MemoryBufferExtend extend_y = COM_MB_CLIP) { - const int dx = x - this->m_rect.xmin; - const int dy = y - this->m_rect.ymin; - const int offset = (this->m_chunkWidth * dy + dx) * COM_NUMBER_OF_CHANNELS; + wrap_pixel(x, y, extend_x, extend_y); + const int offset = (this->m_chunkWidth * y + x) * COM_NUMBER_OF_CHANNELS; BLI_assert(offset >= 0); BLI_assert(offset < this->determineBufferSize() * COM_NUMBER_OF_CHANNELS); - BLI_assert(x >= this->m_rect.xmin && x < this->m_rect.xmax && - y >= this->m_rect.ymin && y < this->m_rect.ymax); + BLI_assert(!(extend_x == COM_MB_CLIP && (x < m_rect.xmin || x >= m_rect.xmax)) && + !(extend_y == COM_MB_CLIP && (y < m_rect.ymin || y >= m_rect.ymax))); #if 0 /* always true */ @@ -162,12 +203,16 @@ public: void writePixel(int x, int y, const float color[4]); void addPixel(int x, int y, const float color[4]); - inline void readCubic(float result[4], float x, float y) + inline void readBilinear(float result[4], float x, float y, + MemoryBufferExtend extend_x = COM_MB_CLIP, + MemoryBufferExtend extend_y = COM_MB_CLIP) { int x1 = floor(x); - int x2 = x1 + 1; int y1 = floor(y); + int x2 = x1 + 1; int y2 = y1 + 1; + wrap_pixel(x1, y1, extend_x, extend_y); + wrap_pixel(x2, y2, extend_x, extend_y); float valuex = x - x1; float valuey = y - y1; @@ -199,8 +244,6 @@ public: result[2] = color1[2] * mvaluex + color3[2] * valuex; result[3] = color1[3] * mvaluex + color3[3] * valuex; } - - void readEWA(float result[4], float fx, float fy, float dx, float dy, PixelSampler sampler); diff --git a/source/blender/compositor/intern/COM_NodeBase.h b/source/blender/compositor/intern/COM_NodeBase.h index 41b6ab70bf9..e2072575509 100644 --- a/source/blender/compositor/intern/COM_NodeBase.h +++ b/source/blender/compositor/intern/COM_NodeBase.h @@ -153,9 +153,9 @@ public: */ InputSocket *getInputSocket(const unsigned int index); - virtual bool isStatic() const { return false; } void getStaticValues(float *result) const { } + protected: NodeBase(); diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h index 114a00b9e8d..160e493073e 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.h +++ b/source/blender/compositor/intern/COM_NodeOperation.h @@ -199,7 +199,8 @@ public: * Mostly Filter types (Blurs, Convolution, Defocus etc) need this to be set to true. */ const bool isComplex() const { return this->m_complex; } - virtual const bool isSetOperation() const { return false; } + + virtual bool isSetOperation() const { return false; } /** * @brief is this operation of type ReadBufferOperation diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp index 1bac06fc4ab..330e61e7fea 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.cpp +++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp @@ -313,7 +313,8 @@ void WorkScheduler::initialize(bool use_opencl) cl_uint numberOfPlatforms = 0; cl_int error; error = clGetPlatformIDs(0, 0, &numberOfPlatforms); - if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); } + if (error == -1001) { } /* GPU not supported */ + else if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); } if (G.f & G_DEBUG) printf("%d number of platforms\n", numberOfPlatforms); cl_platform_id *platforms = (cl_platform_id *)MEM_mallocN(sizeof(cl_platform_id) * numberOfPlatforms, __func__); error = clGetPlatformIDs(numberOfPlatforms, platforms, 0); diff --git a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp b/source/blender/compositor/nodes/COM_AlphaOverNode.cpp index 4f3ed36aadb..bf081cae097 100644 --- a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp +++ b/source/blender/compositor/nodes/COM_AlphaOverNode.cpp @@ -22,7 +22,7 @@ #include "COM_AlphaOverNode.h" -#include "COM_MixBaseOperation.h" +#include "COM_MixOperation.h" #include "COM_AlphaOverKeyOperation.h" #include "COM_AlphaOverMixedOperation.h" #include "COM_AlphaOverPremultiplyOperation.h" diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp b/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp index c1511ee611b..4c136583936 100644 --- a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp @@ -22,9 +22,7 @@ #include "COM_ChannelMatteNode.h" #include "BKE_node.h" #include "COM_ChannelMatteOperation.h" -#include "COM_ConvertRGBToHSVOperation.h" -#include "COM_ConvertRGBToYCCOperation.h" -#include "COM_ConvertRGBToYUVOperation.h" +#include "COM_ConvertOperation.h" #include "COM_SetAlphaOperation.h" ChannelMatteNode::ChannelMatteNode(bNode *editorNode) : Node(editorNode) diff --git a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp b/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp index d2598e661a9..c23f242ca5c 100644 --- a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp @@ -22,7 +22,7 @@ #include "COM_ChromaMatteNode.h" #include "BKE_node.h" #include "COM_ChromaMatteOperation.h" -#include "COM_ConvertRGBToYCCOperation.h" +#include "COM_ConvertOperation.h" #include "COM_SetAlphaOperation.h" ChromaMatteNode::ChromaMatteNode(bNode *editorNode) : Node(editorNode) diff --git a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp b/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp index aeed859b350..5578fdae54e 100644 --- a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp @@ -25,7 +25,7 @@ #include "COM_ColorBalanceASCCDLOperation.h" #include "COM_ExecutionSystem.h" #include "BKE_node.h" -#include "COM_MixBlendOperation.h" +#include "COM_MixOperation.h" ColorBalanceNode::ColorBalanceNode(bNode *editorNode) : Node(editorNode) { diff --git a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp b/source/blender/compositor/nodes/COM_ColorMatteNode.cpp index 54e6762961b..8ab93a58a1d 100644 --- a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorMatteNode.cpp @@ -22,7 +22,7 @@ #include "COM_ColorMatteNode.h" #include "BKE_node.h" #include "COM_ColorMatteOperation.h" -#include "COM_ConvertRGBToHSVOperation.h" +#include "COM_ConvertOperation.h" #include "COM_SetAlphaOperation.h" ColorMatteNode::ColorMatteNode(bNode *editorNode) : Node(editorNode) diff --git a/source/blender/compositor/nodes/COM_ColorRampNode.cpp b/source/blender/compositor/nodes/COM_ColorRampNode.cpp index a79c7885ae4..6f715a8f278 100644 --- a/source/blender/compositor/nodes/COM_ColorRampNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorRampNode.cpp @@ -24,7 +24,7 @@ #include "COM_ExecutionSystem.h" #include "BKE_node.h" #include "COM_ColorRampOperation.h" -#include "COM_SeparateChannelOperation.h" +#include "COM_ConvertOperation.h" #include "DNA_texture_types.h" ColorRampNode::ColorRampNode(bNode *editorNode) : Node(editorNode) diff --git a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp b/source/blender/compositor/nodes/COM_ColorToBWNode.cpp index 511fdf09f41..07be93dab86 100644 --- a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorToBWNode.cpp @@ -22,7 +22,7 @@ #include "COM_ColorToBWNode.h" -#include "COM_ConvertColorToBWOperation.h" +#include "COM_ConvertOperation.h" #include "COM_ExecutionSystem.h" ColorToBWNode::ColorToBWNode(bNode *editorNode) : Node(editorNode) diff --git a/source/blender/compositor/nodes/COM_CombineHSVANode.cpp b/source/blender/compositor/nodes/COM_CombineHSVANode.cpp index beba41fade9..9f6614ed8c3 100644 --- a/source/blender/compositor/nodes/COM_CombineHSVANode.cpp +++ b/source/blender/compositor/nodes/COM_CombineHSVANode.cpp @@ -22,11 +22,11 @@ #include "COM_CombineHSVANode.h" -#include "COM_CombineChannelsOperation.h" +#include "COM_ConvertOperation.h" #include "COM_ExecutionSystem.h" #include "COM_SetValueOperation.h" -#include "COM_ConvertHSVToRGBOperation.h" +#include "COM_ConvertOperation.h" CombineHSVANode::CombineHSVANode(bNode *editorNode) : CombineRGBANode(editorNode) { diff --git a/source/blender/compositor/nodes/COM_CombineRGBANode.cpp b/source/blender/compositor/nodes/COM_CombineRGBANode.cpp index a8cdd8c2950..8dfded049e5 100644 --- a/source/blender/compositor/nodes/COM_CombineRGBANode.cpp +++ b/source/blender/compositor/nodes/COM_CombineRGBANode.cpp @@ -22,7 +22,7 @@ #include "COM_CombineRGBANode.h" -#include "COM_CombineChannelsOperation.h" +#include "COM_ConvertOperation.h" #include "COM_ExecutionSystem.h" #include "COM_SetValueOperation.h" diff --git a/source/blender/compositor/nodes/COM_CombineYCCANode.cpp b/source/blender/compositor/nodes/COM_CombineYCCANode.cpp index 5319eb84184..ee787a4f9c1 100644 --- a/source/blender/compositor/nodes/COM_CombineYCCANode.cpp +++ b/source/blender/compositor/nodes/COM_CombineYCCANode.cpp @@ -20,7 +20,7 @@ */ #include "COM_CombineYCCANode.h" -#include "COM_ConvertYCCToRGBOperation.h" +#include "COM_ConvertOperation.h" CombineYCCANode::CombineYCCANode(bNode *editorNode) : CombineRGBANode(editorNode) { diff --git a/source/blender/compositor/nodes/COM_CombineYUVANode.cpp b/source/blender/compositor/nodes/COM_CombineYUVANode.cpp index 48c2c6ca649..feee443cf05 100644 --- a/source/blender/compositor/nodes/COM_CombineYUVANode.cpp +++ b/source/blender/compositor/nodes/COM_CombineYUVANode.cpp @@ -20,7 +20,7 @@ */ #include "COM_CombineYUVANode.h" -#include "COM_ConvertYUVToRGBOperation.h" +#include "COM_ConvertOperation.h" CombineYUVANode::CombineYUVANode(bNode *editorNode) : CombineRGBANode(editorNode) { diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp index a7149cc63b2..72f3ed07fd5 100644 --- a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp +++ b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp @@ -20,8 +20,7 @@ */ #include "COM_ConvertAlphaNode.h" -#include "COM_ConvertPremulToStraightOperation.h" -#include "COM_ConvertStraightToPremulOperation.h" +#include "COM_ConvertOperation.h" #include "COM_ExecutionSystem.h" void ConvertAlphaNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context) diff --git a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp b/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp index 782c897f6fb..3c532fe0b1d 100644 --- a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp @@ -24,7 +24,7 @@ #include "COM_DistanceRGBMatteOperation.h" #include "COM_DistanceYCCMatteOperation.h" #include "COM_SetAlphaOperation.h" -#include "COM_ConvertRGBToYCCOperation.h" +#include "COM_ConvertOperation.h" DistanceMatteNode::DistanceMatteNode(bNode *editorNode) : Node(editorNode) { diff --git a/source/blender/compositor/nodes/COM_FilterNode.cpp b/source/blender/compositor/nodes/COM_FilterNode.cpp index 990cdb480ca..3b75e3e0a1a 100644 --- a/source/blender/compositor/nodes/COM_FilterNode.cpp +++ b/source/blender/compositor/nodes/COM_FilterNode.cpp @@ -25,7 +25,7 @@ #include "COM_ConvolutionEdgeFilterOperation.h" #include "COM_ExecutionSystem.h" #include "BKE_node.h" -#include "COM_MixBlendOperation.h" +#include "COM_MixOperation.h" FilterNode::FilterNode(bNode *editorNode) : Node(editorNode) { diff --git a/source/blender/compositor/nodes/COM_GlareNode.cpp b/source/blender/compositor/nodes/COM_GlareNode.cpp index 8782e6bb6d9..a6a83846623 100644 --- a/source/blender/compositor/nodes/COM_GlareNode.cpp +++ b/source/blender/compositor/nodes/COM_GlareNode.cpp @@ -26,7 +26,7 @@ #include "COM_GlareSimpleStarOperation.h" #include "COM_GlareStreaksOperation.h" #include "COM_SetValueOperation.h" -#include "COM_MixGlareOperation.h" +#include "COM_MixOperation.h" #include "COM_FastGaussianBlurOperation.h" #include "COM_GlareGhostOperation.h" #include "COM_GlareFogGlowOperation.h" diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp index fd961030ebf..66b98b29d5e 100644 --- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp +++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp @@ -22,11 +22,9 @@ #include "COM_HueSaturationValueCorrectNode.h" -#include "COM_ConvertColorToValueProg.h" +#include "COM_ConvertOperation.h" #include "COM_ExecutionSystem.h" -#include "COM_ConvertRGBToHSVOperation.h" -#include "COM_ConvertHSVToRGBOperation.h" -#include "COM_MixBlendOperation.h" +#include "COM_MixOperation.h" #include "COM_SetColorOperation.h" #include "COM_SetValueOperation.h" #include "COM_ChangeHSVOperation.h" diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp index 29e10db0758..5001433513c 100644 --- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp +++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp @@ -22,11 +22,9 @@ #include "COM_HueSaturationValueNode.h" -#include "COM_ConvertColorToValueProg.h" +#include "COM_ConvertOperation.h" #include "COM_ExecutionSystem.h" -#include "COM_ConvertRGBToHSVOperation.h" -#include "COM_ConvertHSVToRGBOperation.h" -#include "COM_MixBlendOperation.h" +#include "COM_MixOperation.h" #include "COM_SetColorOperation.h" #include "COM_SetValueOperation.h" #include "COM_ChangeHSVOperation.h" diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp index b8d9841c92a..6e4bff460d1 100644 --- a/source/blender/compositor/nodes/COM_ImageNode.cpp +++ b/source/blender/compositor/nodes/COM_ImageNode.cpp @@ -25,7 +25,7 @@ #include "COM_ExecutionSystem.h" #include "COM_ImageOperation.h" #include "COM_MultilayerImageOperation.h" -#include "COM_ConvertPremulToStraightOperation.h" +#include "COM_ConvertOperation.h" #include "BKE_node.h" #include "BLI_utildefines.h" @@ -38,19 +38,19 @@ ImageNode::ImageNode(bNode *editorNode) : Node(editorNode) /* pass */ } -NodeOperation *ImageNode::doMultilayerCheck(ExecutionSystem *system, RenderLayer *rl, Image *image, ImageUser *user, int framenumber, int outputsocketIndex, int pass, DataType datatype) +NodeOperation *ImageNode::doMultilayerCheck(ExecutionSystem *system, RenderLayer *rl, Image *image, ImageUser *user, int framenumber, int outputsocketIndex, int passindex, DataType datatype) { OutputSocket *outputSocket = this->getOutputSocket(outputsocketIndex); MultilayerBaseOperation *operation = NULL; switch (datatype) { case COM_DT_VALUE: - operation = new MultilayerValueOperation(pass); + operation = new MultilayerValueOperation(passindex); break; case COM_DT_VECTOR: - operation = new MultilayerVectorOperation(pass); + operation = new MultilayerVectorOperation(passindex); break; case COM_DT_COLOR: - operation = new MultilayerColorOperation(pass); + operation = new MultilayerColorOperation(passindex); break; default: break; @@ -93,10 +93,19 @@ void ImageNode::convertToOperations(ExecutionSystem *graph, CompositorContext *c socket = this->getOutputSocket(index); if (socket->isConnected() || index == 0) { bNodeSocket *bnodeSocket = socket->getbNodeSocket(); - NodeImageLayer *storage = (NodeImageLayer *)bnodeSocket->storage; - int passindex = storage->pass_index; - + /* Passes in the file can differ from passes stored in sockets (#36755). + * Look up the correct file pass using the socket identifier instead. + */ + #if 0 + NodeImageLayer *storage = (NodeImageLayer *)bnodeSocket->storage;*/ + int passindex = storage->pass_index;*/ RenderPass *rpass = (RenderPass *)BLI_findlink(&rl->passes, passindex); + #endif + int passindex; + RenderPass *rpass; + for (rpass = (RenderPass *)rl->passes.first, passindex = 0; rpass; rpass = rpass->next, ++passindex) + if (STREQ(rpass->name, bnodeSocket->identifier)) + break; if (rpass) { imageuser->pass = passindex; switch (rpass->channels) { diff --git a/source/blender/compositor/nodes/COM_ImageNode.h b/source/blender/compositor/nodes/COM_ImageNode.h index 49006efbed5..12b4da6c8b3 100644 --- a/source/blender/compositor/nodes/COM_ImageNode.h +++ b/source/blender/compositor/nodes/COM_ImageNode.h @@ -35,7 +35,7 @@ extern "C" { */ class ImageNode : public Node { private: - NodeOperation *doMultilayerCheck(ExecutionSystem *system, RenderLayer *rl, Image *image, ImageUser *user, int framenumber, int outputsocketIndex, int pass, DataType datatype); + NodeOperation *doMultilayerCheck(ExecutionSystem *system, RenderLayer *rl, Image *image, ImageUser *user, int framenumber, int outputsocketIndex, int passindex, DataType datatype); public: ImageNode(bNode *editorNode); void convertToOperations(ExecutionSystem *graph, CompositorContext *context); diff --git a/source/blender/compositor/nodes/COM_KeyingNode.cpp b/source/blender/compositor/nodes/COM_KeyingNode.cpp index 51ea2913e65..786530bd3c4 100644 --- a/source/blender/compositor/nodes/COM_KeyingNode.cpp +++ b/source/blender/compositor/nodes/COM_KeyingNode.cpp @@ -32,10 +32,7 @@ #include "COM_MathBaseOperation.h" -#include "COM_SeparateChannelOperation.h" -#include "COM_CombineChannelsOperation.h" -#include "COM_ConvertRGBToYCCOperation.h" -#include "COM_ConvertYCCToRGBOperation.h" +#include "COM_ConvertOperation.h" #include "COM_SetValueOperation.h" #include "COM_DilateErodeOperation.h" diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp index 4656e00b006..b1e6967ba42 100644 --- a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp @@ -22,7 +22,7 @@ #include "COM_LuminanceMatteNode.h" #include "BKE_node.h" #include "COM_LuminanceMatteOperation.h" -#include "COM_ConvertRGBToYUVOperation.h" +#include "COM_ConvertOperation.h" #include "COM_SetAlphaOperation.h" LuminanceMatteNode::LuminanceMatteNode(bNode *editorNode) : Node(editorNode) diff --git a/source/blender/compositor/nodes/COM_MixNode.cpp b/source/blender/compositor/nodes/COM_MixNode.cpp index ab4e464327d..42217243fdf 100644 --- a/source/blender/compositor/nodes/COM_MixNode.cpp +++ b/source/blender/compositor/nodes/COM_MixNode.cpp @@ -22,24 +22,7 @@ #include "COM_MixNode.h" -#include "COM_MixBlendOperation.h" -#include "COM_MixAddOperation.h" -#include "COM_MixMultiplyOperation.h" -#include "COM_MixBurnOperation.h" -#include "COM_MixColorOperation.h" -#include "COM_MixDarkenOperation.h" -#include "COM_MixDifferenceOperation.h" -#include "COM_MixDivideOperation.h" -#include "COM_MixHueOperation.h" -#include "COM_MixLightenOperation.h" -#include "COM_MixLinearLightOperation.h" -#include "COM_MixOverlayOperation.h" -#include "COM_MixSaturationOperation.h" -#include "COM_MixScreenOperation.h" -#include "COM_MixSoftLightOperation.h" -#include "COM_MixSubtractOperation.h" -#include "COM_MixValueOperation.h" -#include "COM_MixDodgeOperation.h" +#include "COM_MixOperation.h" #include "COM_ExecutionSystem.h" #include "COM_SetValueOperation.h" diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cpp b/source/blender/compositor/nodes/COM_OutputFileNode.cpp index 3b1871b307b..94e5efe77e0 100644 --- a/source/blender/compositor/nodes/COM_OutputFileNode.cpp +++ b/source/blender/compositor/nodes/COM_OutputFileNode.cpp @@ -59,12 +59,12 @@ void OutputFileNode::convertToOperations(ExecutionSystem *graph, CompositorConte bool hasConnections = false; for (int i = 0; i < num_inputs; ++i) { InputSocket *input = getInputSocket(i); + NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)input->getbNodeSocket()->storage; + + outputOperation->add_layer(sockdata->layer, input->getDataType()); + if (input->isConnected()) { hasConnections = true; - NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)input->getbNodeSocket()->storage; - - outputOperation->add_layer(sockdata->layer, input->getDataType()); - input->relinkConnections(outputOperation->getInputSocket(i)); } } diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp new file mode 100644 index 00000000000..d6434c26c7d --- /dev/null +++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp @@ -0,0 +1,81 @@ +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin + */ + +#include "COM_PlaneTrackDeformNode.h" +#include "COM_ExecutionSystem.h" + +#include "COM_PlaneTrackMaskOperation.h" +#include "COM_PlaneTrackWarpImageOperation.h" + +extern "C" { + #include "BKE_node.h" + #include "BKE_movieclip.h" + #include "BKE_tracking.h" +} + +PlaneTrackDeformNode::PlaneTrackDeformNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void PlaneTrackDeformNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context) +{ + InputSocket *input_image = this->getInputSocket(0); + + OutputSocket *output_warped_image = this->getOutputSocket(0); + OutputSocket *output_plane = this->getOutputSocket(1); + + bNode *editorNode = this->getbNode(); + MovieClip *clip = (MovieClip *) editorNode->id; + + NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *) editorNode->storage; + + int frame_number = context->getFramenumber(); + + if (output_warped_image->isConnected()) { + PlaneTrackWarpImageOperation *warp_image_operation = new PlaneTrackWarpImageOperation(); + + warp_image_operation->setMovieClip(clip); + warp_image_operation->setTrackingObject(data->tracking_object); + warp_image_operation->setPlaneTrackName(data->plane_track_name); + warp_image_operation->setFramenumber(frame_number); + + input_image->relinkConnections(warp_image_operation->getInputSocket(0), 0, graph); + output_warped_image->relinkConnections(warp_image_operation->getOutputSocket()); + + graph->addOperation(warp_image_operation); + } + + if (output_plane->isConnected()) { + PlaneTrackMaskOperation *plane_mask_operation = new PlaneTrackMaskOperation(); + + plane_mask_operation->setMovieClip(clip); + plane_mask_operation->setTrackingObject(data->tracking_object); + plane_mask_operation->setPlaneTrackName(data->plane_track_name); + plane_mask_operation->setFramenumber(frame_number); + + output_plane->relinkConnections(plane_mask_operation->getOutputSocket()); + + graph->addOperation(plane_mask_operation); + } +} diff --git a/source/blender/compositor/operations/COM_RenderLayersMistOperation.h b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h index ad838c9e340..cf173cd19f9 100644 --- a/source/blender/compositor/operations/COM_RenderLayersMistOperation.h +++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h @@ -1,5 +1,5 @@ /* - * Copyright 2011, Blender Foundation. + * Copyright 2013, Blender Foundation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -16,18 +16,23 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Contributor: - * Jeroen Bakker - * Monique Dewanchand + * Sergey Sharybin */ -#ifndef _COM_RenderLayersMistOperation_h -#define _COM_RenderLayersMistOperation_h +#include "COM_Node.h" +#include "DNA_node_types.h" -#include "COM_RenderLayersBaseProg.h" +extern "C" { + #include "DNA_movieclip_types.h" + #include "DNA_node_types.h" +} -class RenderLayersMistOperation : public RenderLayersBaseProg { +/** + * @brief PlaneTrackDeformNode + * @ingroup Node + */ +class PlaneTrackDeformNode : public Node { public: - RenderLayersMistOperation(); + PlaneTrackDeformNode(bNode *editorNode); + void convertToOperations(ExecutionSystem *graph, CompositorContext *context); }; - -#endif diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp index 74e557c77ce..512f8eec90f 100644 --- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp +++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp @@ -22,26 +22,7 @@ #include "COM_RenderLayersNode.h" #include "COM_ExecutionSystem.h" -#include "COM_RenderLayersImageProg.h" -#include "COM_RenderLayersAlphaProg.h" -#include "COM_RenderLayersDepthProg.h" -#include "COM_RenderLayersNormalOperation.h" -#include "COM_RenderLayersSpeedOperation.h" -#include "COM_RenderLayersColorOperation.h" -#include "COM_RenderLayersUVOperation.h" -#include "COM_RenderLayersMistOperation.h" -#include "COM_RenderLayersObjectIndexOperation.h" -#include "COM_RenderLayersDiffuseOperation.h" -#include "COM_RenderLayersSpecularOperation.h" -#include "COM_RenderLayersShadowOperation.h" -#include "COM_RenderLayersAOOperation.h" -#include "COM_RenderLayersEmitOperation.h" -#include "COM_RenderLayersReflectionOperation.h" -#include "COM_RenderLayersRefractionOperation.h" -#include "COM_RenderLayersEnvironmentOperation.h" -#include "COM_RenderLayersIndirectOperation.h" -#include "COM_RenderLayersMaterialIndexOperation.h" -#include "COM_RenderLayersCyclesOperation.h" +#include "COM_RenderLayersProg.h" #include "COM_TranslateOperation.h" #include "COM_RotateOperation.h" #include "COM_ScaleOperation.h" diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.h b/source/blender/compositor/nodes/COM_RenderLayersNode.h index 9bd74624b0c..0c769d32aea 100644 --- a/source/blender/compositor/nodes/COM_RenderLayersNode.h +++ b/source/blender/compositor/nodes/COM_RenderLayersNode.h @@ -22,7 +22,7 @@ #include "COM_Node.h" #include "DNA_node_types.h" -#include "COM_RenderLayersBaseProg.h" +#include "COM_RenderLayersProg.h" /** * @brief RenderLayersNode diff --git a/source/blender/compositor/nodes/COM_SeparateHSVANode.cpp b/source/blender/compositor/nodes/COM_SeparateHSVANode.cpp index 4f93b226fa1..4cd77d4bae6 100644 --- a/source/blender/compositor/nodes/COM_SeparateHSVANode.cpp +++ b/source/blender/compositor/nodes/COM_SeparateHSVANode.cpp @@ -22,10 +22,9 @@ #include "COM_SeparateHSVANode.h" -#include "COM_SeparateChannelOperation.h" #include "COM_ExecutionSystem.h" #include "COM_SetValueOperation.h" -#include "COM_ConvertRGBToHSVOperation.h" +#include "COM_ConvertOperation.h" SeparateHSVANode::SeparateHSVANode(bNode *editorNode) : SeparateRGBANode(editorNode) { diff --git a/source/blender/compositor/nodes/COM_SeparateRGBANode.cpp b/source/blender/compositor/nodes/COM_SeparateRGBANode.cpp index 7fcdebadb46..7d9bff30a93 100644 --- a/source/blender/compositor/nodes/COM_SeparateRGBANode.cpp +++ b/source/blender/compositor/nodes/COM_SeparateRGBANode.cpp @@ -22,7 +22,7 @@ #include "COM_SeparateRGBANode.h" -#include "COM_SeparateChannelOperation.h" +#include "COM_ConvertOperation.h" #include "COM_ExecutionSystem.h" #include "COM_SetValueOperation.h" #include "DNA_material_types.h" // the ramp types diff --git a/source/blender/compositor/nodes/COM_SeparateYCCANode.cpp b/source/blender/compositor/nodes/COM_SeparateYCCANode.cpp index 154e2bcd550..797cd49316a 100644 --- a/source/blender/compositor/nodes/COM_SeparateYCCANode.cpp +++ b/source/blender/compositor/nodes/COM_SeparateYCCANode.cpp @@ -20,10 +20,9 @@ */ #include "COM_SeparateYCCANode.h" -#include "COM_SeparateChannelOperation.h" #include "COM_ExecutionSystem.h" #include "COM_SetValueOperation.h" -#include "COM_ConvertRGBToYCCOperation.h" +#include "COM_ConvertOperation.h" SeparateYCCANode::SeparateYCCANode(bNode *editorNode) : SeparateRGBANode(editorNode) { diff --git a/source/blender/compositor/nodes/COM_SeparateYUVANode.cpp b/source/blender/compositor/nodes/COM_SeparateYUVANode.cpp index 8a647b7f849..9a6ec20fa80 100644 --- a/source/blender/compositor/nodes/COM_SeparateYUVANode.cpp +++ b/source/blender/compositor/nodes/COM_SeparateYUVANode.cpp @@ -20,10 +20,9 @@ */ #include "COM_SeparateYUVANode.h" -#include "COM_SeparateChannelOperation.h" #include "COM_ExecutionSystem.h" #include "COM_SetValueOperation.h" -#include "COM_ConvertRGBToYUVOperation.h" +#include "COM_ConvertOperation.h" SeparateYUVANode::SeparateYUVANode(bNode *editorNode) : SeparateRGBANode(editorNode) { diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp b/source/blender/compositor/nodes/COM_SplitViewerNode.cpp index 81c0744564f..6fb8467674b 100644 --- a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp +++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cpp @@ -35,9 +35,8 @@ SplitViewerNode::SplitViewerNode(bNode *editorNode) : Node(editorNode) void SplitViewerNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context) { bNode *editorNode = this->getbNode(); - bool is_active = ((editorNode->flag & NODE_DO_OUTPUT_RECALC) && - (editorNode->flag & NODE_DO_OUTPUT) && this->isInActiveGroup()) || - context->isRendering(); + bool is_active = ((editorNode->flag & NODE_DO_OUTPUT_RECALC || context->isRendering()) && + (editorNode->flag & NODE_DO_OUTPUT) && this->isInActiveGroup()); InputSocket *image1Socket = this->getInputSocket(0); InputSocket *image2Socket = this->getInputSocket(1); diff --git a/source/blender/compositor/nodes/COM_TranslateNode.cpp b/source/blender/compositor/nodes/COM_TranslateNode.cpp index 44d796c2911..d2cd009449c 100644 --- a/source/blender/compositor/nodes/COM_TranslateNode.cpp +++ b/source/blender/compositor/nodes/COM_TranslateNode.cpp @@ -24,6 +24,7 @@ #include "COM_TranslateOperation.h" #include "COM_WrapOperation.h" +#include "COM_WriteBufferOperation.h" #include "COM_ExecutionSystem.h" TranslateNode::TranslateNode(bNode *editorNode) : Node(editorNode) @@ -43,10 +44,15 @@ void TranslateNode::convertToOperations(ExecutionSystem *graph, CompositorContex NodeTranslateData *data = (NodeTranslateData *)bnode->storage; if (data->wrap_axis) { + WriteBufferOperation *writeOperation = new WriteBufferOperation(); WrapOperation *wrapOperation = new WrapOperation(); + wrapOperation->setMemoryProxy(writeOperation->getMemoryProxy()); wrapOperation->setWrapping(data->wrap_axis); - inputSocket->relinkConnections(wrapOperation->getInputSocket(0), 0, graph); + + inputSocket->relinkConnections(writeOperation->getInputSocket(0), 0, graph); addLink(graph, wrapOperation->getOutputSocket(), operation->getInputSocket(0)); + + graph->addOperation(writeOperation); graph->addOperation(wrapOperation); } else { diff --git a/source/blender/compositor/nodes/COM_ZCombineNode.cpp b/source/blender/compositor/nodes/COM_ZCombineNode.cpp index b48d974e893..b5fe4882f57 100644 --- a/source/blender/compositor/nodes/COM_ZCombineNode.cpp +++ b/source/blender/compositor/nodes/COM_ZCombineNode.cpp @@ -28,7 +28,7 @@ #include "COM_SetValueOperation.h" #include "COM_MathBaseOperation.h" #include "COM_AntiAliasOperation.h" -#include "COM_MixBlendOperation.h" +#include "COM_MixOperation.h" #include "DNA_material_types.h" // the ramp types diff --git a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h index fa884bacf49..31b0422918a 100644 --- a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h +++ b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h @@ -22,7 +22,7 @@ #ifndef _COM_AlphaOverKeyOperation_h #define _COM_AlphaOverKeyOperation_h -#include "COM_MixBaseOperation.h" +#include "COM_MixOperation.h" /** diff --git a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h index 91128454783..14e7325ec1d 100644 --- a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h +++ b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h @@ -22,7 +22,7 @@ #ifndef _COM_AlphaOverMixedOperation_h_ #define _COM_AlphaOverMixedOperation_h_ -#include "COM_MixBaseOperation.h" +#include "COM_MixOperation.h" /** diff --git a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h index d6e9e31c35f..16bd2aeaeed 100644 --- a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h +++ b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h @@ -22,7 +22,7 @@ #ifndef _COM_AlphaOverPremultiplyOperation_h #define _COM_AlphaOverPremultiplyOperation_h -#include "COM_MixBaseOperation.h" +#include "COM_MixOperation.h" /** diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.h b/source/blender/compositor/operations/COM_ChangeHSVOperation.h index 57e5dc991e9..01852084e41 100644 --- a/source/blender/compositor/operations/COM_ChangeHSVOperation.h +++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.h @@ -22,7 +22,7 @@ #ifndef _COM_ChangeHSVOperation_h #define _COM_ChangeHSVOperation_h -#include "COM_MixBaseOperation.h" +#include "COM_MixOperation.h" /** diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.h b/source/blender/compositor/operations/COM_ChannelMatteOperation.h index 17f84965f63..efb4f7427ca 100644 --- a/source/blender/compositor/operations/COM_ChannelMatteOperation.h +++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.h @@ -21,7 +21,7 @@ #ifndef _COM_ChannelMatteOperation_h #define _COM_ChannelMatteOperation_h -#include "COM_MixBaseOperation.h" +#include "COM_MixOperation.h" /** diff --git a/source/blender/compositor/operations/COM_ChromaMatteOperation.h b/source/blender/compositor/operations/COM_ChromaMatteOperation.h index adebb7a30c2..9557faec855 100644 --- a/source/blender/compositor/operations/COM_ChromaMatteOperation.h +++ b/source/blender/compositor/operations/COM_ChromaMatteOperation.h @@ -21,7 +21,7 @@ #ifndef _COM_ChromaMatteOperation_h #define _COM_ChromaMatteOperation_h -#include "COM_MixBaseOperation.h" +#include "COM_MixOperation.h" /** diff --git a/source/blender/compositor/operations/COM_ColorMatteOperation.h b/source/blender/compositor/operations/COM_ColorMatteOperation.h index 582a94e1873..f065a5f7e89 100644 --- a/source/blender/compositor/operations/COM_ColorMatteOperation.h +++ b/source/blender/compositor/operations/COM_ColorMatteOperation.h @@ -21,7 +21,7 @@ #ifndef _COM_ColorMatteOperation_h #define _COM_ColorMatteOperation_h -#include "COM_MixBaseOperation.h" +#include "COM_MixOperation.h" /** diff --git a/source/blender/compositor/operations/COM_CombineChannelsOperation.cpp b/source/blender/compositor/operations/COM_CombineChannelsOperation.cpp deleted file mode 100644 index 3ced0548bb8..00000000000 --- a/source/blender/compositor/operations/COM_CombineChannelsOperation.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_CombineChannelsOperation.h" -#include "BLI_utildefines.h" - -CombineChannelsOperation::CombineChannelsOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->setResolutionInputSocketIndex(0); - this->m_inputChannel1Operation = NULL; - this->m_inputChannel2Operation = NULL; - this->m_inputChannel3Operation = NULL; - this->m_inputChannel4Operation = NULL; -} - -void CombineChannelsOperation::initExecution() -{ - this->m_inputChannel1Operation = this->getInputSocketReader(0); - this->m_inputChannel2Operation = this->getInputSocketReader(1); - this->m_inputChannel3Operation = this->getInputSocketReader(2); - this->m_inputChannel4Operation = this->getInputSocketReader(3); -} - -void CombineChannelsOperation::deinitExecution() -{ - this->m_inputChannel1Operation = NULL; - this->m_inputChannel2Operation = NULL; - this->m_inputChannel3Operation = NULL; - this->m_inputChannel4Operation = NULL; -} - - -void CombineChannelsOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float input[4]; - if (this->m_inputChannel1Operation) { - this->m_inputChannel1Operation->read(input, x, y, sampler); - output[0] = input[0]; - } - if (this->m_inputChannel2Operation) { - this->m_inputChannel2Operation->read(input, x, y, sampler); - output[1] = input[0]; - } - if (this->m_inputChannel3Operation) { - this->m_inputChannel3Operation->read(input, x, y, sampler); - output[2] = input[0]; - } - if (this->m_inputChannel4Operation) { - this->m_inputChannel4Operation->read(input, x, y, sampler); - output[3] = input[0]; - } -} diff --git a/source/blender/compositor/operations/COM_CombineChannelsOperation.h b/source/blender/compositor/operations/COM_CombineChannelsOperation.h deleted file mode 100644 index 7c8742b1557..00000000000 --- a/source/blender/compositor/operations/COM_CombineChannelsOperation.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_CombineChannelsOperation_h_ -#define _COM_CombineChannelsOperation_h_ - -#include "COM_NodeOperation.h" - -class CombineChannelsOperation : public NodeOperation { -private: - SocketReader *m_inputChannel1Operation; - SocketReader *m_inputChannel2Operation; - SocketReader *m_inputChannel3Operation; - SocketReader *m_inputChannel4Operation; -public: - CombineChannelsOperation(); - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - void initExecution(); - void deinitExecution(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_ConvertColorToBWOperation.cpp b/source/blender/compositor/operations/COM_ConvertColorToBWOperation.cpp deleted file mode 100644 index 3b5aa8cd755..00000000000 --- a/source/blender/compositor/operations/COM_ConvertColorToBWOperation.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_ConvertColorToBWOperation.h" - -ConvertColorToBWOperation::ConvertColorToBWOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_VALUE); - this->m_inputOperation = NULL; -} - -void ConvertColorToBWOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertColorToBWOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->read(inputColor, x, y, sampler); - output[0] = rgb_to_bw(inputColor); -} - -void ConvertColorToBWOperation::deinitExecution() -{ - this->m_inputOperation = NULL; -} diff --git a/source/blender/compositor/operations/COM_ConvertColorToBWOperation.h b/source/blender/compositor/operations/COM_ConvertColorToBWOperation.h deleted file mode 100644 index 963bd32a2f6..00000000000 --- a/source/blender/compositor/operations/COM_ConvertColorToBWOperation.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_ConvertColorToBWOperation_h -#define _COM_ConvertColorToBWOperation_h -#include "COM_NodeOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class ConvertColorToBWOperation : public NodeOperation { -private: - /** - * Cached reference to the inputProgram - */ - SocketReader *m_inputOperation; -public: - /** - * Default constructor - */ - ConvertColorToBWOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_ConvertColorToValueProg.cpp b/source/blender/compositor/operations/COM_ConvertColorToValueProg.cpp deleted file mode 100644 index 44e751d1cae..00000000000 --- a/source/blender/compositor/operations/COM_ConvertColorToValueProg.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_ConvertColorToValueProg.h" - -ConvertColorToValueProg::ConvertColorToValueProg() : NodeOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_VALUE); - this->m_inputOperation = NULL; -} - -void ConvertColorToValueProg::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertColorToValueProg::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->read(inputColor, x, y, sampler); - output[0] = (inputColor[0] + inputColor[1] + inputColor[2]) / 3.0f; -} - -void ConvertColorToValueProg::deinitExecution() -{ - this->m_inputOperation = NULL; -} diff --git a/source/blender/compositor/operations/COM_ConvertColorToValueProg.h b/source/blender/compositor/operations/COM_ConvertColorToValueProg.h deleted file mode 100644 index 5c25d5d0540..00000000000 --- a/source/blender/compositor/operations/COM_ConvertColorToValueProg.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_ConvertColorToValueProg_h -#define _COM_ConvertColorToValueProg_h -#include "COM_NodeOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class ConvertColorToValueProg : public NodeOperation { -private: - /** - * Cached reference to the inputProgram - */ - SocketReader *m_inputOperation; -public: - /** - * Default constructor - */ - ConvertColorToValueProg(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); -}; -#endif diff --git a/source/blender/compositor/operations/COM_ConvertColorToVectorOperation.cpp b/source/blender/compositor/operations/COM_ConvertColorToVectorOperation.cpp deleted file mode 100644 index a9b8cbb4272..00000000000 --- a/source/blender/compositor/operations/COM_ConvertColorToVectorOperation.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_ConvertColorToVectorOperation.h" - -ConvertColorToVectorOperation::ConvertColorToVectorOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_VECTOR); - this->m_inputOperation = NULL; -} - -void ConvertColorToVectorOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertColorToVectorOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - this->m_inputOperation->read(output, x, y, sampler); -} - -void ConvertColorToVectorOperation::deinitExecution() -{ - this->m_inputOperation = NULL; -} diff --git a/source/blender/compositor/operations/COM_ConvertColorToVectorOperation.h b/source/blender/compositor/operations/COM_ConvertColorToVectorOperation.h deleted file mode 100644 index 93644cb5d1c..00000000000 --- a/source/blender/compositor/operations/COM_ConvertColorToVectorOperation.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_ConvertColorToVectorOperation_h -#define _COM_ConvertColorToVectorOperation_h -#include "COM_NodeOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class ConvertColorToVectorOperation : public NodeOperation { -private: - /** - * Cached reference to the inputProgram - */ - SocketReader *m_inputOperation; -public: - /** - * Default constructor - */ - ConvertColorToVectorOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); -}; -#endif diff --git a/source/blender/compositor/operations/COM_ConvertHSVToRGBOperation.cpp b/source/blender/compositor/operations/COM_ConvertHSVToRGBOperation.cpp deleted file mode 100644 index 65907a8e537..00000000000 --- a/source/blender/compositor/operations/COM_ConvertHSVToRGBOperation.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_ConvertHSVToRGBOperation.h" -#include "BLI_math_color.h" - -ConvertHSVToRGBOperation::ConvertHSVToRGBOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputOperation = NULL; -} - -void ConvertHSVToRGBOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertHSVToRGBOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->read(inputColor, x, y, sampler); - hsv_to_rgb_v(inputColor, output); - output[3] = inputColor[3]; -} - -void ConvertHSVToRGBOperation::deinitExecution() -{ - this->m_inputOperation = NULL; -} - diff --git a/source/blender/compositor/operations/COM_ConvertHSVToRGBOperation.h b/source/blender/compositor/operations/COM_ConvertHSVToRGBOperation.h deleted file mode 100644 index 17419ca2a05..00000000000 --- a/source/blender/compositor/operations/COM_ConvertHSVToRGBOperation.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_ConvertHSVToRGBOperation_h -#define _COM_ConvertHSVToRGBOperation_h -#include "COM_NodeOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class ConvertHSVToRGBOperation : public NodeOperation { -private: - /** - * Cached reference to the inputProgram - */ - SocketReader *m_inputOperation; -public: - /** - * Default constructor - */ - ConvertHSVToRGBOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); -}; -#endif diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cpp b/source/blender/compositor/operations/COM_ConvertOperation.cpp new file mode 100644 index 00000000000..d72aabb078e --- /dev/null +++ b/source/blender/compositor/operations/COM_ConvertOperation.cpp @@ -0,0 +1,429 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + */ + +#include "COM_ConvertOperation.h" + + +ConvertBaseOperation::ConvertBaseOperation() +{ + this->m_inputOperation = NULL; +} + +void ConvertBaseOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); +} + +void ConvertBaseOperation::deinitExecution() +{ + this->m_inputOperation = NULL; +} + + +/* ******** Value to Color ******** */ + +ConvertValueToColorOperation::ConvertValueToColorOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertValueToColorOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputValue[4]; + this->m_inputOperation->read(inputValue, x, y, sampler); + output[0] = output[1] = output[2] = inputValue[0]; + output[3] = 1.0f; +} + + +/* ******** Color to Value ******** */ + +ConvertColorToValueOperation::ConvertColorToValueOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_VALUE); +} + +void ConvertColorToValueOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->read(inputColor, x, y, sampler); + output[0] = (inputColor[0] + inputColor[1] + inputColor[2]) / 3.0f; +} + + +/* ******** Color to BW ******** */ + +ConvertColorToBWOperation::ConvertColorToBWOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_VALUE); +} + +void ConvertColorToBWOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->read(inputColor, x, y, sampler); + output[0] = rgb_to_bw(inputColor); +} + + +/* ******** Color to Vector ******** */ + +ConvertColorToVectorOperation::ConvertColorToVectorOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_VECTOR); +} + +void ConvertColorToVectorOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + this->m_inputOperation->read(output, x, y, sampler); +} + + +/* ******** Value to Vector ******** */ + +ConvertValueToVectorOperation::ConvertValueToVectorOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VECTOR); +} + +void ConvertValueToVectorOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float input[4]; + this->m_inputOperation->read(input, x, y, sampler); + output[0] = input[0]; + output[1] = input[0]; + output[2] = input[0]; + output[3] = 0.0f; +} + + +/* ******** Vector to Color ******** */ + +ConvertVectorToColorOperation::ConvertVectorToColorOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_VECTOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertVectorToColorOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + this->m_inputOperation->read(output, x, y, sampler); + output[3] = 1.0f; +} + + +/* ******** Vector to Value ******** */ + +ConvertVectorToValueOperation::ConvertVectorToValueOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_VECTOR); + this->addOutputSocket(COM_DT_VALUE); +} + +void ConvertVectorToValueOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float input[4]; + this->m_inputOperation->read(input, x, y, sampler); + output[0] = (input[0] + input[1] + input[2]) / 3.0f; +} + + +/* ******** RGB to YCC ******** */ + +ConvertRGBToYCCOperation::ConvertRGBToYCCOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertRGBToYCCOperation::setMode(int mode) +{ + switch (mode) { + case 1: + this->m_mode = BLI_YCC_ITU_BT709; + break; + case 2: + this->m_mode = BLI_YCC_JFIF_0_255; + break; + case 0: + default: + this->m_mode = BLI_YCC_ITU_BT601; + break; + } +} + +void ConvertRGBToYCCOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor[4]; + float color[3]; + + this->m_inputOperation->read(inputColor, x, y, sampler); + rgb_to_ycc(inputColor[0], inputColor[1], inputColor[2], &color[0], &color[1], &color[2], this->m_mode); + + /* divided by 255 to normalize for viewing in */ + /* R,G,B --> Y,Cb,Cr */ + mul_v3_v3fl(output, color, 1.0f / 255.0f); + output[3] = inputColor[3]; +} + +/* ******** YCC to RGB ******** */ + +ConvertYCCToRGBOperation::ConvertYCCToRGBOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertYCCToRGBOperation::setMode(int mode) +{ + switch (mode) { + case 1: + this->m_mode = BLI_YCC_ITU_BT709; + break; + case 2: + this->m_mode = BLI_YCC_JFIF_0_255; + break; + case 0: + default: + this->m_mode = BLI_YCC_ITU_BT601; + break; + } +} + +void ConvertYCCToRGBOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->read(inputColor, x, y, sampler); + + /* need to un-normalize the data */ + /* R,G,B --> Y,Cb,Cr */ + mul_v3_fl(inputColor, 255.0f); + + ycc_to_rgb(inputColor[0], inputColor[1], inputColor[2], &output[0], &output[1], &output[2], this->m_mode); + output[3] = inputColor[3]; +} + + +/* ******** RGB to YUV ******** */ + +ConvertRGBToYUVOperation::ConvertRGBToYUVOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertRGBToYUVOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->read(inputColor, x, y, sampler); + rgb_to_yuv(inputColor[0], inputColor[1], inputColor[2], &output[0], &output[1], &output[2]); + output[3] = inputColor[3]; +} + + +/* ******** YUV to RGB ******** */ + +ConvertYUVToRGBOperation::ConvertYUVToRGBOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertYUVToRGBOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->read(inputColor, x, y, sampler); + yuv_to_rgb(inputColor[0], inputColor[1], inputColor[2], &output[0], &output[1], &output[2]); + output[3] = inputColor[3]; +} + + +/* ******** RGB to HSV ******** */ + +ConvertRGBToHSVOperation::ConvertRGBToHSVOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertRGBToHSVOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->read(inputColor, x, y, sampler); + rgb_to_hsv_v(inputColor, output); + output[3] = inputColor[3]; +} + + +/* ******** HSV to RGB ******** */ + +ConvertHSVToRGBOperation::ConvertHSVToRGBOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertHSVToRGBOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor[4]; + this->m_inputOperation->read(inputColor, x, y, sampler); + hsv_to_rgb_v(inputColor, output); + output[3] = inputColor[3]; +} + + +/* ******** Premul to Straight ******** */ + +ConvertPremulToStraightOperation::ConvertPremulToStraightOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertPremulToStraightOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputValue[4]; + float alpha; + + this->m_inputOperation->read(inputValue, x, y, sampler); + alpha = inputValue[3]; + + if (fabsf(alpha) < 1e-5f) { + zero_v3(output); + } + else { + mul_v3_v3fl(output, inputValue, 1.0f / alpha); + } + + /* never touches the alpha */ + output[3] = alpha; +} + + +/* ******** Straight to Premul ******** */ + +ConvertStraightToPremulOperation::ConvertStraightToPremulOperation() : ConvertBaseOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); +} + +void ConvertStraightToPremulOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputValue[4]; + float alpha; + + this->m_inputOperation->read(inputValue, x, y, sampler); + alpha = inputValue[3]; + + mul_v3_v3fl(output, inputValue, alpha); + + /* never touches the alpha */ + output[3] = alpha; +} + + +/* ******** Separate Channels ******** */ + +SeparateChannelOperation::SeparateChannelOperation() : NodeOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_VALUE); + this->m_inputOperation = NULL; +} +void SeparateChannelOperation::initExecution() +{ + this->m_inputOperation = this->getInputSocketReader(0); +} + +void SeparateChannelOperation::deinitExecution() +{ + this->m_inputOperation = NULL; +} + + +void SeparateChannelOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float input[4]; + this->m_inputOperation->read(input, x, y, sampler); + output[0] = input[this->m_channel]; +} + + +/* ******** Combine Channels ******** */ + +CombineChannelsOperation::CombineChannelsOperation() : NodeOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + this->m_inputChannel1Operation = NULL; + this->m_inputChannel2Operation = NULL; + this->m_inputChannel3Operation = NULL; + this->m_inputChannel4Operation = NULL; +} + +void CombineChannelsOperation::initExecution() +{ + this->m_inputChannel1Operation = this->getInputSocketReader(0); + this->m_inputChannel2Operation = this->getInputSocketReader(1); + this->m_inputChannel3Operation = this->getInputSocketReader(2); + this->m_inputChannel4Operation = this->getInputSocketReader(3); +} + +void CombineChannelsOperation::deinitExecution() +{ + this->m_inputChannel1Operation = NULL; + this->m_inputChannel2Operation = NULL; + this->m_inputChannel3Operation = NULL; + this->m_inputChannel4Operation = NULL; +} + + +void CombineChannelsOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float input[4]; + if (this->m_inputChannel1Operation) { + this->m_inputChannel1Operation->read(input, x, y, sampler); + output[0] = input[0]; + } + if (this->m_inputChannel2Operation) { + this->m_inputChannel2Operation->read(input, x, y, sampler); + output[1] = input[0]; + } + if (this->m_inputChannel3Operation) { + this->m_inputChannel3Operation->read(input, x, y, sampler); + output[2] = input[0]; + } + if (this->m_inputChannel4Operation) { + this->m_inputChannel4Operation->read(input, x, y, sampler); + output[3] = input[0]; + } +} diff --git a/source/blender/compositor/operations/COM_ConvertOperation.h b/source/blender/compositor/operations/COM_ConvertOperation.h new file mode 100644 index 00000000000..06aeb2e52d7 --- /dev/null +++ b/source/blender/compositor/operations/COM_ConvertOperation.h @@ -0,0 +1,202 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + */ + +#ifndef _COM_ConvertOperation_h +#define _COM_ConvertOperation_h + +#include "COM_NodeOperation.h" + + +class ConvertBaseOperation : public NodeOperation { +protected: + SocketReader *m_inputOperation; + +public: + ConvertBaseOperation(); + + void initExecution(); + void deinitExecution(); +}; + + +class ConvertValueToColorOperation : public ConvertBaseOperation { +public: + ConvertValueToColorOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + + +class ConvertColorToValueOperation : public ConvertBaseOperation { +public: + ConvertColorToValueOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + + +class ConvertColorToBWOperation : public ConvertBaseOperation { +public: + ConvertColorToBWOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + + +class ConvertColorToVectorOperation : public ConvertBaseOperation { +public: + ConvertColorToVectorOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + + +class ConvertValueToVectorOperation : public ConvertBaseOperation { +public: + ConvertValueToVectorOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + + +class ConvertVectorToColorOperation : public ConvertBaseOperation { +public: + ConvertVectorToColorOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + + +class ConvertVectorToValueOperation : public ConvertBaseOperation { +public: + ConvertVectorToValueOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + + +class ConvertRGBToYCCOperation : public ConvertBaseOperation { +private: + /** YCbCr mode (Jpeg, ITU601, ITU709) */ + int m_mode; +public: + ConvertRGBToYCCOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); + + /** Set the YCC mode */ + void setMode(int mode); +}; + + +class ConvertYCCToRGBOperation : public ConvertBaseOperation { +private: + /** YCbCr mode (Jpeg, ITU601, ITU709) */ + int m_mode; +public: + ConvertYCCToRGBOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); + + /** Set the YCC mode */ + void setMode(int mode); +}; + + +class ConvertRGBToYUVOperation : public ConvertBaseOperation { +public: + ConvertRGBToYUVOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + + +class ConvertYUVToRGBOperation : public ConvertBaseOperation { +public: + ConvertYUVToRGBOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + + +class ConvertRGBToHSVOperation : public ConvertBaseOperation { +public: + ConvertRGBToHSVOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + + +class ConvertHSVToRGBOperation : public ConvertBaseOperation { +public: + ConvertHSVToRGBOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + + +class ConvertPremulToStraightOperation : public ConvertBaseOperation { +public: + ConvertPremulToStraightOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + + +class ConvertStraightToPremulOperation : public ConvertBaseOperation { +public: + ConvertStraightToPremulOperation(); + + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + + +class SeparateChannelOperation : public NodeOperation { +private: + SocketReader *m_inputOperation; + int m_channel; +public: + SeparateChannelOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); + + void initExecution(); + void deinitExecution(); + + void setChannel(int channel) { this->m_channel = channel; } +}; + + +class CombineChannelsOperation : public NodeOperation { +private: + SocketReader *m_inputChannel1Operation; + SocketReader *m_inputChannel2Operation; + SocketReader *m_inputChannel3Operation; + SocketReader *m_inputChannel4Operation; +public: + CombineChannelsOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); + + void initExecution(); + void deinitExecution(); +}; + +#endif diff --git a/source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.cpp b/source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.cpp deleted file mode 100644 index 2af4b55de1a..00000000000 --- a/source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2012, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Dalai Felinto - */ - -#include "COM_ConvertPremulToStraightOperation.h" -#include "BLI_math.h" - -ConvertPremulToStraightOperation::ConvertPremulToStraightOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - - this->m_inputColor = NULL; -} - -void ConvertPremulToStraightOperation::initExecution() -{ - this->m_inputColor = getInputSocketReader(0); -} - -void ConvertPremulToStraightOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputValue[4]; - float alpha; - - this->m_inputColor->read(inputValue, x, y, sampler); - alpha = inputValue[3]; - - if (fabsf(alpha) < 1e-5f) { - zero_v3(output); - } - else { - mul_v3_v3fl(output, inputValue, 1.0f / alpha); - } - - /* never touches the alpha */ - output[3] = alpha; -} - -void ConvertPremulToStraightOperation::deinitExecution() -{ - this->m_inputColor = NULL; -} diff --git a/source/blender/compositor/operations/COM_ConvertRGBToHSVOperation.cpp b/source/blender/compositor/operations/COM_ConvertRGBToHSVOperation.cpp deleted file mode 100644 index 3c7a9d5fd50..00000000000 --- a/source/blender/compositor/operations/COM_ConvertRGBToHSVOperation.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_ConvertRGBToHSVOperation.h" -#include "BLI_math_color.h" - -ConvertRGBToHSVOperation::ConvertRGBToHSVOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputOperation = NULL; -} - -void ConvertRGBToHSVOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertRGBToHSVOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->read(inputColor, x, y, sampler); - rgb_to_hsv_v(inputColor, output); - output[3] = inputColor[3]; -} - -void ConvertRGBToHSVOperation::deinitExecution() -{ - this->m_inputOperation = NULL; -} diff --git a/source/blender/compositor/operations/COM_ConvertRGBToHSVOperation.h b/source/blender/compositor/operations/COM_ConvertRGBToHSVOperation.h deleted file mode 100644 index fdc8dfed31b..00000000000 --- a/source/blender/compositor/operations/COM_ConvertRGBToHSVOperation.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_ConvertRGBToHSVOperation_h -#define _COM_ConvertRGBToHSVOperation_h -#include "COM_NodeOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class ConvertRGBToHSVOperation : public NodeOperation { -private: - /** - * Cached reference to the inputProgram - */ - SocketReader *m_inputOperation; -public: - /** - * Default constructor - */ - ConvertRGBToHSVOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_ConvertRGBToYCCOperation.cpp b/source/blender/compositor/operations/COM_ConvertRGBToYCCOperation.cpp deleted file mode 100644 index 6f6dffdc72b..00000000000 --- a/source/blender/compositor/operations/COM_ConvertRGBToYCCOperation.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Dalai Felinto - */ - -#include "COM_ConvertRGBToYCCOperation.h" -#include "BLI_math_color.h" - -ConvertRGBToYCCOperation::ConvertRGBToYCCOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputOperation = NULL; -} - -void ConvertRGBToYCCOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertRGBToYCCOperation::setMode(int mode) -{ - switch (mode) { - case 1: - this->m_mode = BLI_YCC_ITU_BT709; - break; - case 2: - this->m_mode = BLI_YCC_JFIF_0_255; - break; - case 0: - default: - this->m_mode = BLI_YCC_ITU_BT601; - break; - } -} - -void ConvertRGBToYCCOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor[4]; - float color[3]; - - this->m_inputOperation->read(inputColor, x, y, sampler); - rgb_to_ycc(inputColor[0], inputColor[1], inputColor[2], &color[0], &color[1], &color[2], this->m_mode); - - /* divided by 255 to normalize for viewing in */ - /* R,G,B --> Y,Cb,Cr */ - mul_v3_v3fl(output, color, 1.0f / 255.0f); - output[3] = inputColor[3]; -} - -void ConvertRGBToYCCOperation::deinitExecution() -{ - this->m_inputOperation = NULL; -} diff --git a/source/blender/compositor/operations/COM_ConvertRGBToYCCOperation.h b/source/blender/compositor/operations/COM_ConvertRGBToYCCOperation.h deleted file mode 100644 index 3f85555f3bb..00000000000 --- a/source/blender/compositor/operations/COM_ConvertRGBToYCCOperation.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Dalai Felinto - */ - -#ifndef _COM_ConvertRGBToYCCOperation_h -#define _COM_ConvertRGBToYCCOperation_h -#include "COM_NodeOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class ConvertRGBToYCCOperation : public NodeOperation { -private: - /** - * Cached reference to the inputProgram - */ - SocketReader *m_inputOperation; - - /** - * YCbCr mode (Jpeg, ITU601, ITU709) - */ - int m_mode; -public: - /** - * Default constructor - */ - ConvertRGBToYCCOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); - - /** - * Set the YCC mode - */ - void setMode(int mode); -}; -#endif diff --git a/source/blender/compositor/operations/COM_ConvertRGBToYUVOperation.cpp b/source/blender/compositor/operations/COM_ConvertRGBToYUVOperation.cpp deleted file mode 100644 index 8ce9e150080..00000000000 --- a/source/blender/compositor/operations/COM_ConvertRGBToYUVOperation.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Dalai Felinto - */ - -#include "COM_ConvertRGBToYUVOperation.h" -#include "BLI_math_color.h" - -ConvertRGBToYUVOperation::ConvertRGBToYUVOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputOperation = NULL; -} - -void ConvertRGBToYUVOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertRGBToYUVOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->read(inputColor, x, y, sampler); - rgb_to_yuv(inputColor[0], inputColor[1], inputColor[2], &output[0], &output[1], &output[2]); - output[3] = inputColor[3]; -} - -void ConvertRGBToYUVOperation::deinitExecution() -{ - this->m_inputOperation = NULL; -} diff --git a/source/blender/compositor/operations/COM_ConvertRGBToYUVOperation.h b/source/blender/compositor/operations/COM_ConvertRGBToYUVOperation.h deleted file mode 100644 index 97d57f657ec..00000000000 --- a/source/blender/compositor/operations/COM_ConvertRGBToYUVOperation.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Dalai Felinto - */ - -#ifndef _COM_ConvertRGBToYUVOperation_h -#define _COM_ConvertRGBToYUVOperation_h -#include "COM_NodeOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class ConvertRGBToYUVOperation : public NodeOperation { -private: - /** - * Cached reference to the inputProgram - */ - SocketReader *m_inputOperation; -public: - /** - * Default constructor - */ - ConvertRGBToYUVOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.cpp b/source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.cpp deleted file mode 100644 index ae55d949ff2..00000000000 --- a/source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2012, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Dalai Felinto - */ - -#include "COM_ConvertStraightToPremulOperation.h" -#include "BLI_math.h" - -ConvertStraightToPremulOperation::ConvertStraightToPremulOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - - this->m_inputColor = NULL; -} - -void ConvertStraightToPremulOperation::initExecution() -{ - this->m_inputColor = getInputSocketReader(0); -} - -void ConvertStraightToPremulOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputValue[4]; - float alpha; - - this->m_inputColor->read(inputValue, x, y, sampler); - alpha = inputValue[3]; - - mul_v3_v3fl(output, inputValue, alpha); - - /* never touches the alpha */ - output[3] = alpha; -} - -void ConvertStraightToPremulOperation::deinitExecution() -{ - this->m_inputColor = NULL; -} diff --git a/source/blender/compositor/operations/COM_ConvertValueToColorProg.cpp b/source/blender/compositor/operations/COM_ConvertValueToColorProg.cpp deleted file mode 100644 index 98e7650aa56..00000000000 --- a/source/blender/compositor/operations/COM_ConvertValueToColorProg.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_ConvertValueToColorProg.h" - -ConvertValueToColorProg::ConvertValueToColorProg() : NodeOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputProgram = NULL; -} -void ConvertValueToColorProg::initExecution() -{ - this->m_inputProgram = this->getInputSocketReader(0); -} - -void ConvertValueToColorProg::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputValue[4]; - this->m_inputProgram->read(inputValue, x, y, sampler); - output[0] = output[1] = output[2] = inputValue[0]; - output[3] = 1.0f; -} - -void ConvertValueToColorProg::deinitExecution() -{ - this->m_inputProgram = NULL; -} diff --git a/source/blender/compositor/operations/COM_ConvertValueToColorProg.h b/source/blender/compositor/operations/COM_ConvertValueToColorProg.h deleted file mode 100644 index f0f6cfb8fd2..00000000000 --- a/source/blender/compositor/operations/COM_ConvertValueToColorProg.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_ConvertValueToColorProg_h -#define _COM_ConvertValueToColorProg_h -#include "COM_NodeOperation.h" - - -class ConvertValueToColorProg : public NodeOperation { -private: - /** - * Cached reference to the inputProgram - */ - SocketReader *m_inputProgram; -public: - ConvertValueToColorProg(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_ConvertValueToVectorOperation.cpp b/source/blender/compositor/operations/COM_ConvertValueToVectorOperation.cpp deleted file mode 100644 index 411409d263c..00000000000 --- a/source/blender/compositor/operations/COM_ConvertValueToVectorOperation.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_ConvertValueToVectorOperation.h" - -ConvertValueToVectorOperation::ConvertValueToVectorOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addOutputSocket(COM_DT_VECTOR); - this->m_inputOperation = NULL; -} - -void ConvertValueToVectorOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertValueToVectorOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float input[4]; - this->m_inputOperation->read(input, x, y, sampler); - output[0] = input[0]; - output[1] = input[0]; - output[2] = input[0]; - output[3] = 0.0f; -} - -void ConvertValueToVectorOperation::deinitExecution() -{ - this->m_inputOperation = NULL; -} diff --git a/source/blender/compositor/operations/COM_ConvertValueToVectorOperation.h b/source/blender/compositor/operations/COM_ConvertValueToVectorOperation.h deleted file mode 100644 index da45848ca34..00000000000 --- a/source/blender/compositor/operations/COM_ConvertValueToVectorOperation.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_ConvertValueToVectorOperation_h -#define _COM_ConvertValueToVectorOperation_h -#include "COM_NodeOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class ConvertValueToVectorOperation : public NodeOperation { -private: - /** - * Cached reference to the inputProgram - */ - SocketReader *m_inputOperation; -public: - /** - * Default constructor - */ - ConvertValueToVectorOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); -}; -#endif diff --git a/source/blender/compositor/operations/COM_ConvertVectorToColorOperation.cpp b/source/blender/compositor/operations/COM_ConvertVectorToColorOperation.cpp deleted file mode 100644 index 78cb706c32d..00000000000 --- a/source/blender/compositor/operations/COM_ConvertVectorToColorOperation.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_ConvertVectorToColorOperation.h" - -ConvertVectorToColorOperation::ConvertVectorToColorOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_VECTOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputOperation = NULL; -} - -void ConvertVectorToColorOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertVectorToColorOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - this->m_inputOperation->read(output, x, y, sampler); - output[3] = 1.0f; -} - -void ConvertVectorToColorOperation::deinitExecution() -{ - this->m_inputOperation = NULL; -} diff --git a/source/blender/compositor/operations/COM_ConvertVectorToColorOperation.h b/source/blender/compositor/operations/COM_ConvertVectorToColorOperation.h deleted file mode 100644 index 9ef5f8fece3..00000000000 --- a/source/blender/compositor/operations/COM_ConvertVectorToColorOperation.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_ConvertVectorToColorOperation_h -#define _COM_ConvertVectorToColorOperation_h -#include "COM_NodeOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class ConvertVectorToColorOperation : public NodeOperation { -private: - /** - * Cached reference to the inputProgram - */ - SocketReader *m_inputOperation; -public: - /** - * Default constructor - */ - ConvertVectorToColorOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); -}; -#endif diff --git a/source/blender/compositor/operations/COM_ConvertVectorToValueOperation.cpp b/source/blender/compositor/operations/COM_ConvertVectorToValueOperation.cpp deleted file mode 100644 index a3612414029..00000000000 --- a/source/blender/compositor/operations/COM_ConvertVectorToValueOperation.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_ConvertVectorToValueOperation.h" - -ConvertVectorToValueOperation::ConvertVectorToValueOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_VECTOR); - this->addOutputSocket(COM_DT_VALUE); - this->m_inputOperation = NULL; -} - -void ConvertVectorToValueOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertVectorToValueOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float input[4]; - this->m_inputOperation->read(input, x, y, sampler); - output[0] = (input[0] + input[1] + input[2]) / 3.0f; -} - -void ConvertVectorToValueOperation::deinitExecution() -{ - this->m_inputOperation = NULL; -} diff --git a/source/blender/compositor/operations/COM_ConvertVectorToValueOperation.h b/source/blender/compositor/operations/COM_ConvertVectorToValueOperation.h deleted file mode 100644 index e42f235a12b..00000000000 --- a/source/blender/compositor/operations/COM_ConvertVectorToValueOperation.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_ConvertVectorToValueOperation_h -#define _COM_ConvertVectorToValueOperation_h -#include "COM_NodeOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class ConvertVectorToValueOperation : public NodeOperation { -private: - /** - * Cached reference to the inputProgram - */ - SocketReader *m_inputOperation; -public: - /** - * Default constructor - */ - ConvertVectorToValueOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); -}; -#endif diff --git a/source/blender/compositor/operations/COM_ConvertYCCToRGBOperation.cpp b/source/blender/compositor/operations/COM_ConvertYCCToRGBOperation.cpp deleted file mode 100644 index 8f9eaf49ea4..00000000000 --- a/source/blender/compositor/operations/COM_ConvertYCCToRGBOperation.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Dalai Felinto - */ - -#include "COM_ConvertYCCToRGBOperation.h" -#include "BLI_math_color.h" - -ConvertYCCToRGBOperation::ConvertYCCToRGBOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputOperation = NULL; -} - -void ConvertYCCToRGBOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertYCCToRGBOperation::setMode(int mode) -{ - switch (mode) { - case 1: - this->m_mode = BLI_YCC_ITU_BT709; - break; - case 2: - this->m_mode = BLI_YCC_JFIF_0_255; - break; - case 0: - default: - this->m_mode = BLI_YCC_ITU_BT601; - break; - } -} - -void ConvertYCCToRGBOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->read(inputColor, x, y, sampler); - - /* need to un-normalize the data */ - /* R,G,B --> Y,Cb,Cr */ - mul_v3_fl(inputColor, 255.0f); - - ycc_to_rgb(inputColor[0], inputColor[1], inputColor[2], &output[0], &output[1], &output[2], this->m_mode); - output[3] = inputColor[3]; -} - -void ConvertYCCToRGBOperation::deinitExecution() -{ - this->m_inputOperation = NULL; -} - diff --git a/source/blender/compositor/operations/COM_ConvertYCCToRGBOperation.h b/source/blender/compositor/operations/COM_ConvertYCCToRGBOperation.h deleted file mode 100644 index 0a8b67e0bee..00000000000 --- a/source/blender/compositor/operations/COM_ConvertYCCToRGBOperation.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Dalai Felinto - */ - -#ifndef _COM_ConvertYCCToRGBOperation_h -#define _COM_ConvertYCCToRGBOperation_h -#include "COM_NodeOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class ConvertYCCToRGBOperation : public NodeOperation { -private: - /** - * Cached reference to the inputProgram - */ - SocketReader *m_inputOperation; - - /** - * YCbCr mode (Jpeg, ITU601, ITU709) - */ - int m_mode; -public: - /** - * Default constructor - */ - ConvertYCCToRGBOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); - - /** - * Set the YCC mode - */ - void setMode(int mode); -}; -#endif diff --git a/source/blender/compositor/operations/COM_ConvertYUVToRGBOperation.cpp b/source/blender/compositor/operations/COM_ConvertYUVToRGBOperation.cpp deleted file mode 100644 index 197c7f9f043..00000000000 --- a/source/blender/compositor/operations/COM_ConvertYUVToRGBOperation.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Dalai Felinto - */ - -#include "COM_ConvertYUVToRGBOperation.h" -#include "BLI_math_color.h" - -ConvertYUVToRGBOperation::ConvertYUVToRGBOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputOperation = NULL; -} - -void ConvertYUVToRGBOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void ConvertYUVToRGBOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor[4]; - this->m_inputOperation->read(inputColor, x, y, sampler); - yuv_to_rgb(inputColor[0], inputColor[1], inputColor[2], &output[0], &output[1], &output[2]); - output[3] = inputColor[3]; -} - -void ConvertYUVToRGBOperation::deinitExecution() -{ - this->m_inputOperation = NULL; -} - diff --git a/source/blender/compositor/operations/COM_ConvertYUVToRGBOperation.h b/source/blender/compositor/operations/COM_ConvertYUVToRGBOperation.h deleted file mode 100644 index ee11ef8df60..00000000000 --- a/source/blender/compositor/operations/COM_ConvertYUVToRGBOperation.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Dalai Felinto - */ - -#ifndef _COM_ConvertYUVToRGBOperation_h -#define _COM_ConvertYUVToRGBOperation_h -#include "COM_NodeOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class ConvertYUVToRGBOperation : public NodeOperation { -private: - /** - * Cached reference to the inputProgram - */ - SocketReader *m_inputOperation; -public: - /** - * Default constructor - */ - ConvertYUVToRGBOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); -}; -#endif diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.h b/source/blender/compositor/operations/COM_DifferenceMatteOperation.h index e7d881cbbd5..e0a38f703ed 100644 --- a/source/blender/compositor/operations/COM_DifferenceMatteOperation.h +++ b/source/blender/compositor/operations/COM_DifferenceMatteOperation.h @@ -22,7 +22,7 @@ #ifndef _COM_DifferenceMatteOperation_h #define _COM_DifferenceMatteOperation_h -#include "COM_MixBaseOperation.h" +#include "COM_MixOperation.h" /** diff --git a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h index 5a34135b1a4..43299486f60 100644 --- a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h +++ b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h @@ -21,7 +21,7 @@ #ifndef _COM_DistanceRGBMatteOperation_h #define _COM_DistanceRGBMatteOperation_h -#include "COM_MixBaseOperation.h" +#include "COM_MixOperation.h" /** diff --git a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h index f4866a327f1..27025188d49 100644 --- a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h +++ b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h @@ -21,7 +21,7 @@ #ifndef _COM_DistanceYCCMatteOperation_h #define _COM_DistanceYCCMatteOperation_h -#include "COM_MixBaseOperation.h" +#include "COM_MixOperation.h" #include "COM_DistanceRGBMatteOperation.h" diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp b/source/blender/compositor/operations/COM_GlareGhostOperation.cpp index c4f8b3a0ddb..8854be52ded 100644 --- a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareGhostOperation.cpp @@ -83,11 +83,11 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No for (x = 0; x < gbuf->getWidth(); x++) { u = ((float)x + 0.5f) / (float)gbuf->getWidth(); s = (u - 0.5f) * sc + 0.5f, t = (v - 0.5f) * sc + 0.5f; - tbuf1->readCubic(c, s * gbuf->getWidth(), t * gbuf->getHeight()); + tbuf1->readBilinear(c, s * gbuf->getWidth(), t * gbuf->getHeight()); sm = smoothMask(s, t); mul_v3_fl(c, sm); s = (u - 0.5f) * isc + 0.5f, t = (v - 0.5f) * isc + 0.5f; - tbuf2->readCubic(tc, s * gbuf->getWidth() - 0.5f, t * gbuf->getHeight() - 0.5f); + tbuf2->readBilinear(tc, s * gbuf->getWidth() - 0.5f, t * gbuf->getHeight() - 0.5f); sm = smoothMask(s, t); madd_v3_v3fl(c, tc, sm); @@ -108,7 +108,7 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No np = (n << 2) + p; s = (u - 0.5f) * scalef[np] + 0.5f; t = (v - 0.5f) * scalef[np] + 0.5f; - gbuf->readCubic(c, s * gbuf->getWidth() - 0.5f, t * gbuf->getHeight() - 0.5f); + gbuf->readBilinear(c, s * gbuf->getWidth() - 0.5f, t * gbuf->getHeight() - 0.5f); mul_v3_v3(c, cm[np]); sm = smoothMask(s, t) * 0.25f; madd_v3_v3fl(tc, c, sm); diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp index 60d37fb8145..5644ff30ef3 100644 --- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp @@ -54,9 +54,9 @@ void GlareStreaksOperation::generateGlare(float *data, MemoryBuffer *inputTile, // first pass no offset, always same for every pass, exact copy, // otherwise results in uneven brightness, only need once if (n == 0) tsrc->read(c1, x, y); else c1[0] = c1[1] = c1[2] = 0; - tsrc->readCubic(c2, x + vxp, y + vyp); - tsrc->readCubic(c3, x + vxp * 2.f, y + vyp * 2.f); - tsrc->readCubic(c4, x + vxp * 3.f, y + vyp * 3.f); + tsrc->readBilinear(c2, x + vxp, y + vyp); + tsrc->readBilinear(c3, x + vxp * 2.f, y + vyp * 2.f); + tsrc->readBilinear(c4, x + vxp * 3.f, y + vyp * 3.f); // modulate color to look vaguely similar to a color spectrum c2[1] *= cmo; c2[2] *= cmo; diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp index c8e3dbf993d..cface29fdca 100644 --- a/source/blender/compositor/operations/COM_ImageOperation.cpp +++ b/source/blender/compositor/operations/COM_ImageOperation.cpp @@ -40,7 +40,8 @@ BaseImageOperation::BaseImageOperation() : NodeOperation() { this->m_image = NULL; this->m_buffer = NULL; - this->m_imageBuffer = NULL; + this->m_imageFloatBuffer = NULL; + this->m_imageByteBuffer = NULL; this->m_imageUser = NULL; this->m_imagewidth = 0; this->m_imageheight = 0; @@ -70,10 +71,6 @@ ImBuf *BaseImageOperation::getImBuf() BKE_image_release_ibuf(this->m_image, ibuf, NULL); return NULL; } - - if (ibuf->rect_float == NULL) { - IMB_float_from_rect(ibuf); - } return ibuf; } @@ -83,7 +80,8 @@ void BaseImageOperation::initExecution() ImBuf *stackbuf = getImBuf(); this->m_buffer = stackbuf; if (stackbuf) { - this->m_imageBuffer = stackbuf->rect_float; + this->m_imageFloatBuffer = stackbuf->rect_float; + this->m_imageByteBuffer = stackbuf->rect; this->m_depthBuffer = stackbuf->zbuf_float; this->m_imagewidth = stackbuf->x; this->m_imageheight = stackbuf->y; @@ -93,7 +91,8 @@ void BaseImageOperation::initExecution() void BaseImageOperation::deinitExecution() { - this->m_imageBuffer = NULL; + this->m_imageFloatBuffer = NULL; + this->m_imageByteBuffer = NULL; BKE_image_release_ibuf(this->m_image, this->m_buffer, NULL); } @@ -112,23 +111,48 @@ void BaseImageOperation::determineResolution(unsigned int resolution[2], unsigne BKE_image_release_ibuf(this->m_image, stackbuf, NULL); } -void ImageOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +static void sampleImageAtLocation(ImBuf *ibuf, float x, float y, PixelSampler sampler, bool make_linear_rgb, float color[4]) { - if (this->m_imageBuffer == NULL || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) { - zero_v4(output); + if (ibuf->rect_float) { + switch (sampler) { + case COM_PS_NEAREST: + nearest_interpolation_color(ibuf, NULL, color, x, y); + break; + case COM_PS_BILINEAR: + bilinear_interpolation_color(ibuf, NULL, color, x, y); + break; + case COM_PS_BICUBIC: + bicubic_interpolation_color(ibuf, NULL, color, x, y); + break; + } } else { + unsigned char byte_color[4]; switch (sampler) { case COM_PS_NEAREST: - nearest_interpolation_color(this->m_buffer, NULL, output, x, y); + nearest_interpolation_color(ibuf, byte_color, NULL, x, y); break; case COM_PS_BILINEAR: - bilinear_interpolation_color(this->m_buffer, NULL, output, x, y); + bilinear_interpolation_color(ibuf, byte_color, NULL, x, y); break; case COM_PS_BICUBIC: - bicubic_interpolation_color(this->m_buffer, NULL, output, x, y); + bicubic_interpolation_color(ibuf, byte_color, NULL, x, y); break; } + rgba_uchar_to_float(color, byte_color); + if (make_linear_rgb) { + IMB_colormanagement_colorspace_to_scene_linear_v4(color, false, ibuf->rect_colorspace); + } + } +} + +void ImageOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + if ((this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) { + zero_v4(output); + } + else { + sampleImageAtLocation(this->m_buffer, x, y, sampler, true, output); } } @@ -136,22 +160,12 @@ void ImageAlphaOperation::executePixel(float output[4], float x, float y, PixelS { float tempcolor[4]; - if (this->m_imageBuffer == NULL || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) { + if ((this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) || x < 0 || y < 0 || x >= this->getWidth() || y >= this->getHeight() ) { output[0] = 0.0f; } else { tempcolor[3] = 1.0f; - switch (sampler) { - case COM_PS_NEAREST: - nearest_interpolation_color(this->m_buffer, NULL, tempcolor, x, y); - break; - case COM_PS_BILINEAR: - bilinear_interpolation_color(this->m_buffer, NULL, tempcolor, x, y); - break; - case COM_PS_BICUBIC: - bicubic_interpolation_color(this->m_buffer, NULL, tempcolor, x, y); - break; - } + sampleImageAtLocation(this->m_buffer, x, y, sampler, false, tempcolor); output[0] = tempcolor[3]; } } diff --git a/source/blender/compositor/operations/COM_ImageOperation.h b/source/blender/compositor/operations/COM_ImageOperation.h index e75e7daa186..b51f11edd04 100644 --- a/source/blender/compositor/operations/COM_ImageOperation.h +++ b/source/blender/compositor/operations/COM_ImageOperation.h @@ -42,7 +42,8 @@ protected: ImBuf *m_buffer; Image *m_image; ImageUser *m_imageUser; - float *m_imageBuffer; + float *m_imageFloatBuffer; + unsigned int *m_imageByteBuffer; float *m_depthBuffer; int m_imageheight; int m_imagewidth; diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.h b/source/blender/compositor/operations/COM_LuminanceMatteOperation.h index 009a1e8825e..cb8cc01efea 100644 --- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.h +++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.h @@ -21,7 +21,7 @@ #ifndef _COM_LuminanceMatteOperation_h #define _COM_LuminanceMatteOperation_h -#include "COM_MixBaseOperation.h" +#include "COM_MixOperation.h" /** diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cpp index 1fa484ea2b6..a9b6ad3edc1 100644 --- a/source/blender/compositor/operations/COM_MapUVOperation.cpp +++ b/source/blender/compositor/operations/COM_MapUVOperation.cpp @@ -71,38 +71,12 @@ void MapUVOperation::executePixel(float output[4], float x, float y, PixelSample dy = 0.5f * (uv_u + uv_d); - /* more adaptive sampling, red and green (UV) channels */ - this->m_inputUVProgram->read(uv_a, x - 1, y - 1, COM_PS_NEAREST); - this->m_inputUVProgram->read(uv_b, x - 1, y + 1, COM_PS_NEAREST); - uv_l = uv_a[2] != 0.f ? fabsf(inputUV[0] - uv_a[0]) : 0.f; - uv_r = uv_b[2] != 0.f ? fabsf(inputUV[0] - uv_b[0]) : 0.f; - uv_u = uv_a[2] != 0.f ? fabsf(inputUV[1] - uv_a[1]) : 0.f; - uv_d = uv_b[2] != 0.f ? fabsf(inputUV[1] - uv_b[1]) : 0.f; - - dx += 0.25f * (uv_l + uv_r); - dy += 0.25f * (uv_u + uv_d); - - this->m_inputUVProgram->read(uv_a, x + 1, y - 1, COM_PS_NEAREST); - this->m_inputUVProgram->read(uv_b, x + 1, y + 1, COM_PS_NEAREST); - uv_l = uv_a[2] != 0.f ? fabsf(inputUV[0] - uv_a[0]) : 0.f; - uv_r = uv_b[2] != 0.f ? fabsf(inputUV[0] - uv_b[0]) : 0.f; - uv_u = uv_a[2] != 0.f ? fabsf(inputUV[1] - uv_a[1]) : 0.f; - uv_d = uv_b[2] != 0.f ? fabsf(inputUV[1] - uv_b[1]) : 0.f; - - dx += 0.25f * (uv_l + uv_r); - dy += 0.25f * (uv_u + uv_d); - /* UV to alpha threshold */ const float threshold = this->m_alpha * 0.05f; float alpha = 1.0f - threshold * (dx + dy); if (alpha < 0.f) alpha = 0.f; else alpha *= inputUV[2]; - /* should use mipmap */ - dx = min(dx, 0.2f); - dy = min(dy, 0.2f); - - /* EWA filtering */ u = inputUV[0] * this->m_inputColorProgram->getWidth(); v = inputUV[1] * this->m_inputColorProgram->getHeight(); diff --git a/source/blender/compositor/operations/COM_MixAddOperation.cpp b/source/blender/compositor/operations/COM_MixAddOperation.cpp deleted file mode 100644 index 4e0876439c0..00000000000 --- a/source/blender/compositor/operations/COM_MixAddOperation.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixAddOperation.h" - -MixAddOperation::MixAddOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixAddOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - output[0] = inputColor1[0] + value * inputColor2[0]; - output[1] = inputColor1[1] + value * inputColor2[1]; - output[2] = inputColor1[2] + value * inputColor2[2]; - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - diff --git a/source/blender/compositor/operations/COM_MixAddOperation.h b/source/blender/compositor/operations/COM_MixAddOperation.h deleted file mode 100644 index 5a52846e847..00000000000 --- a/source/blender/compositor/operations/COM_MixAddOperation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixAddOperation_h -#define _COM_MixAddOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixAddOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixAddOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixBaseOperation.cpp b/source/blender/compositor/operations/COM_MixBaseOperation.cpp deleted file mode 100644 index 5b455338bb0..00000000000 --- a/source/blender/compositor/operations/COM_MixBaseOperation.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixBaseOperation.h" - -MixBaseOperation::MixBaseOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_VALUE); - this->addInputSocket(COM_DT_COLOR); - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->m_inputValueOperation = NULL; - this->m_inputColor1Operation = NULL; - this->m_inputColor2Operation = NULL; - this->setUseValueAlphaMultiply(false); - this->setUseClamp(false); -} - -void MixBaseOperation::initExecution() -{ - this->m_inputValueOperation = this->getInputSocketReader(0); - this->m_inputColor1Operation = this->getInputSocketReader(1); - this->m_inputColor2Operation = this->getInputSocketReader(2); -} - -void MixBaseOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - output[0] = valuem * (inputColor1[0]) + value * (inputColor2[0]); - output[1] = valuem * (inputColor1[1]) + value * (inputColor2[1]); - output[2] = valuem * (inputColor1[2]) + value * (inputColor2[2]); - output[3] = inputColor1[3]; -} - -void MixBaseOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) -{ - InputSocket *socket; - unsigned int tempPreferredResolution[2] = {0, 0}; - unsigned int tempResolution[2]; - - socket = this->getInputSocket(1); - socket->determineResolution(tempResolution, tempPreferredResolution); - if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { - this->setResolutionInputSocketIndex(1); - } - else { - socket = this->getInputSocket(2); - socket->determineResolution(tempResolution, tempPreferredResolution); - if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { - this->setResolutionInputSocketIndex(2); - } - else { - this->setResolutionInputSocketIndex(0); - } - } - NodeOperation::determineResolution(resolution, preferredResolution); -} - -void MixBaseOperation::deinitExecution() -{ - this->m_inputValueOperation = NULL; - this->m_inputColor1Operation = NULL; - this->m_inputColor2Operation = NULL; -} diff --git a/source/blender/compositor/operations/COM_MixBaseOperation.h b/source/blender/compositor/operations/COM_MixBaseOperation.h deleted file mode 100644 index 3c0c0778190..00000000000 --- a/source/blender/compositor/operations/COM_MixBaseOperation.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixBaseOperation_h -#define _COM_MixBaseOperation_h -#include "COM_NodeOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixBaseOperation : public NodeOperation { -protected: - /** - * Prefetched reference to the inputProgram - */ - SocketReader *m_inputValueOperation; - SocketReader *m_inputColor1Operation; - SocketReader *m_inputColor2Operation; - bool m_valueAlphaMultiply; - bool m_useClamp; - - inline void clampIfNeeded(float color[4]) - { - if (m_useClamp) { - CLAMP(color[0], 0.0f, 1.0f); - CLAMP(color[1], 0.0f, 1.0f); - CLAMP(color[2], 0.0f, 1.0f); - CLAMP(color[3], 0.0f, 1.0f); - } - } - -public: - /** - * Default constructor - */ - MixBaseOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - - /** - * Initialize the execution - */ - void initExecution(); - - /** - * Deinitialize the execution - */ - void deinitExecution(); - - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); - - - void setUseValueAlphaMultiply(const bool value) { this->m_valueAlphaMultiply = value; } - bool useValueAlphaMultiply() { return this->m_valueAlphaMultiply; } - void setUseClamp(bool value) { this->m_useClamp = value; } -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixBlendOperation.cpp b/source/blender/compositor/operations/COM_MixBlendOperation.cpp deleted file mode 100644 index 0ca7d460064..00000000000 --- a/source/blender/compositor/operations/COM_MixBlendOperation.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixBlendOperation.h" - -MixBlendOperation::MixBlendOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixBlendOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - float value; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - value = inputValue[0]; - - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - output[0] = valuem * (inputColor1[0]) + value * (inputColor2[0]); - output[1] = valuem * (inputColor1[1]) + value * (inputColor2[1]); - output[2] = valuem * (inputColor1[2]) + value * (inputColor2[2]); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} diff --git a/source/blender/compositor/operations/COM_MixBurnOperation.cpp b/source/blender/compositor/operations/COM_MixBurnOperation.cpp deleted file mode 100644 index d4422c6cc6a..00000000000 --- a/source/blender/compositor/operations/COM_MixBurnOperation.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixBurnOperation.h" - -MixBurnOperation::MixBurnOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixBurnOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - float tmp; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - tmp = valuem + value * inputColor2[0]; - if (tmp <= 0.0f) - output[0] = 0.0f; - else { - tmp = 1.0f - (1.0f - inputColor1[0]) / tmp; - if (tmp < 0.0f) - output[0] = 0.0f; - else if (tmp > 1.0f) - output[0] = 1.0f; - else - output[0] = tmp; - } - - tmp = valuem + value * inputColor2[1]; - if (tmp <= 0.0f) - output[1] = 0.0f; - else { - tmp = 1.0f - (1.0f - inputColor1[1]) / tmp; - if (tmp < 0.0f) - output[1] = 0.0f; - else if (tmp > 1.0f) - output[1] = 1.0f; - else - output[1] = tmp; - } - - tmp = valuem + value * inputColor2[2]; - if (tmp <= 0.0f) - output[2] = 0.0f; - else { - tmp = 1.0f - (1.0f - inputColor1[2]) / tmp; - if (tmp < 0.0f) - output[2] = 0.0f; - else if (tmp > 1.0f) - output[2] = 1.0f; - else - output[2] = tmp; - } - - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - diff --git a/source/blender/compositor/operations/COM_MixColorOperation.cpp b/source/blender/compositor/operations/COM_MixColorOperation.cpp deleted file mode 100644 index 6919a636aeb..00000000000 --- a/source/blender/compositor/operations/COM_MixColorOperation.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixColorOperation.h" - -extern "C" { - #include "BLI_math.h" -} - -MixColorOperation::MixColorOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixColorOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - float colH, colS, colV; - rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); - if (colS != 0.0f) { - float rH, rS, rV; - float tmpr, tmpg, tmpb; - rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); - hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb); - output[0] = (valuem * inputColor1[0]) + (value * tmpr); - output[1] = (valuem * inputColor1[1]) + (value * tmpg); - output[2] = (valuem * inputColor1[2]) + (value * tmpb); - } - else { - copy_v3_v3(output, inputColor1); - } - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - diff --git a/source/blender/compositor/operations/COM_MixDarkenOperation.cpp b/source/blender/compositor/operations/COM_MixDarkenOperation.cpp deleted file mode 100644 index d56d9fdf122..00000000000 --- a/source/blender/compositor/operations/COM_MixDarkenOperation.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixDarkenOperation.h" - -MixDarkenOperation::MixDarkenOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixDarkenOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - float tmp; - tmp = inputColor2[0] + ((1.0f - inputColor2[0]) * valuem); - if (tmp < inputColor1[0]) output[0] = tmp; - else output[0] = inputColor1[0]; - tmp = inputColor2[1] + ((1.0f - inputColor2[1]) * valuem); - if (tmp < inputColor1[1]) output[1] = tmp; - else output[1] = inputColor1[1]; - tmp = inputColor2[2] + ((1.0f - inputColor2[2]) * valuem); - if (tmp < inputColor1[2]) output[2] = tmp; - else output[2] = inputColor1[2]; - - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - diff --git a/source/blender/compositor/operations/COM_MixDarkenOperation.h b/source/blender/compositor/operations/COM_MixDarkenOperation.h deleted file mode 100644 index f9c35fa364b..00000000000 --- a/source/blender/compositor/operations/COM_MixDarkenOperation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixDarkenOperation_h -#define _COM_MixDarkenOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixDarkenOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixDarkenOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixDifferenceOperation.cpp b/source/blender/compositor/operations/COM_MixDifferenceOperation.cpp deleted file mode 100644 index 13494401c60..00000000000 --- a/source/blender/compositor/operations/COM_MixDifferenceOperation.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixDifferenceOperation.h" -#include "BLI_math.h" - -MixDifferenceOperation::MixDifferenceOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixDifferenceOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - output[0] = valuem * inputColor1[0] + value *fabsf(inputColor1[0] - inputColor2[0]); - output[1] = valuem * inputColor1[1] + value *fabsf(inputColor1[1] - inputColor2[1]); - output[2] = valuem * inputColor1[2] + value *fabsf(inputColor1[2] - inputColor2[2]); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - diff --git a/source/blender/compositor/operations/COM_MixDifferenceOperation.h b/source/blender/compositor/operations/COM_MixDifferenceOperation.h deleted file mode 100644 index 7e4bf3c675c..00000000000 --- a/source/blender/compositor/operations/COM_MixDifferenceOperation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixDifferenceOperation_h -#define _COM_MixDifferenceOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixDifferenceOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixDifferenceOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixDivideOperation.cpp b/source/blender/compositor/operations/COM_MixDivideOperation.cpp deleted file mode 100644 index 3e0eb66565c..00000000000 --- a/source/blender/compositor/operations/COM_MixDivideOperation.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixDivideOperation.h" - -MixDivideOperation::MixDivideOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixDivideOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - if (inputColor2[0] != 0.0f) - output[0] = valuem * (inputColor1[0]) + value * (inputColor1[0]) / inputColor2[0]; - else - output[0] = 0.0f; - if (inputColor2[1] != 0.0f) - output[1] = valuem * (inputColor1[1]) + value * (inputColor1[1]) / inputColor2[1]; - else - output[1] = 0.0f; - if (inputColor2[2] != 0.0f) - output[2] = valuem * (inputColor1[2]) + value * (inputColor1[2]) / inputColor2[2]; - else - output[2] = 0.0f; - - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - diff --git a/source/blender/compositor/operations/COM_MixDivideOperation.h b/source/blender/compositor/operations/COM_MixDivideOperation.h deleted file mode 100644 index f543265075b..00000000000 --- a/source/blender/compositor/operations/COM_MixDivideOperation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixDivideOperation_h -#define _COM_MixDivideOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixDivideOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixDivideOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixDodgeOperation.cpp b/source/blender/compositor/operations/COM_MixDodgeOperation.cpp deleted file mode 100644 index acb39f665ff..00000000000 --- a/source/blender/compositor/operations/COM_MixDodgeOperation.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixDodgeOperation.h" - -MixDodgeOperation::MixDodgeOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixDodgeOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - float tmp; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - - if (inputColor1[0] != 0.0f) { - tmp = 1.0f - value * inputColor2[0]; - if (tmp <= 0.0f) - output[0] = 1.0f; - else { - tmp = inputColor1[0] / tmp; - if (tmp > 1.0f) - output[0] = 1.0f; - else - output[0] = tmp; - } - } - else - output[0] = 0.0f; - - if (inputColor1[1] != 0.0f) { - tmp = 1.0f - value * inputColor2[1]; - if (tmp <= 0.0f) - output[1] = 1.0f; - else { - tmp = inputColor1[1] / tmp; - if (tmp > 1.0f) - output[1] = 1.0f; - else - output[1] = tmp; - } - } - else - output[1] = 0.0f; - - if (inputColor1[2] != 0.0f) { - tmp = 1.0f - value * inputColor2[2]; - if (tmp <= 0.0f) - output[2] = 1.0f; - else { - tmp = inputColor1[2] / tmp; - if (tmp > 1.0f) - output[2] = 1.0f; - else - output[2] = tmp; - } - } - else - output[2] = 0.0f; - - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - diff --git a/source/blender/compositor/operations/COM_MixDodgeOperation.h b/source/blender/compositor/operations/COM_MixDodgeOperation.h deleted file mode 100644 index 9a285c675c5..00000000000 --- a/source/blender/compositor/operations/COM_MixDodgeOperation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixDodgeOperation_h -#define _COM_MixDodgeOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixDodgeOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixDodgeOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixGlareOperation.cpp b/source/blender/compositor/operations/COM_MixGlareOperation.cpp deleted file mode 100644 index 1c6555206da..00000000000 --- a/source/blender/compositor/operations/COM_MixGlareOperation.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2011, Glareer Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixGlareOperation.h" - -MixGlareOperation::MixGlareOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixGlareOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - float value; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - value = inputValue[0]; - float mf = 2.f - 2.f * fabsf(value - 0.5f); - - if (inputColor1[0] < 0.0f) inputColor1[0] = 0.0f; - if (inputColor1[1] < 0.0f) inputColor1[1] = 0.0f; - if (inputColor1[2] < 0.0f) inputColor1[2] = 0.0f; - - output[0] = mf * max(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f); - output[1] = mf * max(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f); - output[2] = mf * max(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} diff --git a/source/blender/compositor/operations/COM_MixGlareOperation.h b/source/blender/compositor/operations/COM_MixGlareOperation.h deleted file mode 100644 index 99d478e347d..00000000000 --- a/source/blender/compositor/operations/COM_MixGlareOperation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Glareer Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixGlareOperation_h -#define _COM_MixGlareOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixGlareOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixGlareOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixHueOperation.cpp b/source/blender/compositor/operations/COM_MixHueOperation.cpp deleted file mode 100644 index 64c88592b93..00000000000 --- a/source/blender/compositor/operations/COM_MixHueOperation.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixHueOperation.h" - -extern "C" { - #include "BLI_math.h" -} - -MixHueOperation::MixHueOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixHueOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - float colH, colS, colV; - rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); - if (colS != 0.0f) { - float rH, rS, rV; - float tmpr, tmpg, tmpb; - rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); - hsv_to_rgb(colH, rS, rV, &tmpr, &tmpg, &tmpb); - output[0] = valuem * (inputColor1[0]) + value * tmpr; - output[1] = valuem * (inputColor1[1]) + value * tmpg; - output[2] = valuem * (inputColor1[2]) + value * tmpb; - } - else { - copy_v3_v3(output, inputColor1); - } - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} diff --git a/source/blender/compositor/operations/COM_MixHueOperation.h b/source/blender/compositor/operations/COM_MixHueOperation.h deleted file mode 100644 index d9864bbe3dc..00000000000 --- a/source/blender/compositor/operations/COM_MixHueOperation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixHueOperation_h -#define _COM_MixHueOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixHueOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixHueOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixLightenOperation.cpp b/source/blender/compositor/operations/COM_MixLightenOperation.cpp deleted file mode 100644 index a468fb39442..00000000000 --- a/source/blender/compositor/operations/COM_MixLightenOperation.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixLightenOperation.h" - -MixLightenOperation::MixLightenOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixLightenOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float tmp; - tmp = value * inputColor2[0]; - if (tmp > inputColor1[0]) output[0] = tmp; - else output[0] = inputColor1[0]; - tmp = value * inputColor2[1]; - if (tmp > inputColor1[1]) output[1] = tmp; - else output[1] = inputColor1[1]; - tmp = value * inputColor2[2]; - if (tmp > inputColor1[2]) output[2] = tmp; - else output[2] = inputColor1[2]; - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - diff --git a/source/blender/compositor/operations/COM_MixLightenOperation.h b/source/blender/compositor/operations/COM_MixLightenOperation.h deleted file mode 100644 index 5f08a067e11..00000000000 --- a/source/blender/compositor/operations/COM_MixLightenOperation.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixLightenOperation_h -#define _COM_MixLightenOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixLightenOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixLightenOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixLinearLightOperation.cpp b/source/blender/compositor/operations/COM_MixLinearLightOperation.cpp deleted file mode 100644 index e1b5e040f0f..00000000000 --- a/source/blender/compositor/operations/COM_MixLinearLightOperation.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixLinearLightOperation.h" - -MixLinearLightOperation::MixLinearLightOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixLinearLightOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - if (inputColor2[0] > 0.5f) - output[0] = inputColor1[0] + value * (2.0f * (inputColor2[0] - 0.5f)); - else - output[0] = inputColor1[0] + value * (2.0f * (inputColor2[0]) - 1.0f); - if (inputColor2[1] > 0.5f) - output[1] = inputColor1[1] + value * (2.0f * (inputColor2[1] - 0.5f)); - else - output[1] = inputColor1[1] + value * (2.0f * (inputColor2[1]) - 1.0f); - if (inputColor2[2] > 0.5f) - output[2] = inputColor1[2] + value * (2.0f * (inputColor2[2] - 0.5f)); - else - output[2] = inputColor1[2] + value * (2.0f * (inputColor2[2]) - 1.0f); - - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} diff --git a/source/blender/compositor/operations/COM_MixLinearLightOperation.h b/source/blender/compositor/operations/COM_MixLinearLightOperation.h deleted file mode 100644 index 35451a9f3db..00000000000 --- a/source/blender/compositor/operations/COM_MixLinearLightOperation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixLinearLightOperation_h -#define _COM_MixLinearLightOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixLinearLightOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixLinearLightOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixMultiplyOperation.cpp b/source/blender/compositor/operations/COM_MixMultiplyOperation.cpp deleted file mode 100644 index e53addb7041..00000000000 --- a/source/blender/compositor/operations/COM_MixMultiplyOperation.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixMultiplyOperation.h" - -MixMultiplyOperation::MixMultiplyOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixMultiplyOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - output[0] = inputColor1[0] * (valuem + value * inputColor2[0]); - output[1] = inputColor1[1] * (valuem + value * inputColor2[1]); - output[2] = inputColor1[2] * (valuem + value * inputColor2[2]); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - diff --git a/source/blender/compositor/operations/COM_MixMultiplyOperation.h b/source/blender/compositor/operations/COM_MixMultiplyOperation.h deleted file mode 100644 index cdd56bd2f39..00000000000 --- a/source/blender/compositor/operations/COM_MixMultiplyOperation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixMultiplyOperation_h -#define _COM_MixMultiplyOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixMultiplyOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixMultiplyOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixOperation.cpp b/source/blender/compositor/operations/COM_MixOperation.cpp new file mode 100644 index 00000000000..f094e93f147 --- /dev/null +++ b/source/blender/compositor/operations/COM_MixOperation.cpp @@ -0,0 +1,848 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + */ + +#include "COM_MixOperation.h" + +extern "C" { + #include "BLI_math.h" +} + +/* ******** Mix Base Operation ******** */ + +MixBaseOperation::MixBaseOperation() : NodeOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputValueOperation = NULL; + this->m_inputColor1Operation = NULL; + this->m_inputColor2Operation = NULL; + this->setUseValueAlphaMultiply(false); + this->setUseClamp(false); +} + +void MixBaseOperation::initExecution() +{ + this->m_inputValueOperation = this->getInputSocketReader(0); + this->m_inputColor1Operation = this->getInputSocketReader(1); + this->m_inputColor2Operation = this->getInputSocketReader(2); +} + +void MixBaseOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + output[0] = valuem * (inputColor1[0]) + value * (inputColor2[0]); + output[1] = valuem * (inputColor1[1]) + value * (inputColor2[1]); + output[2] = valuem * (inputColor1[2]) + value * (inputColor2[2]); + output[3] = inputColor1[3]; +} + +void MixBaseOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) +{ + InputSocket *socket; + unsigned int tempPreferredResolution[2] = {0, 0}; + unsigned int tempResolution[2]; + + socket = this->getInputSocket(1); + socket->determineResolution(tempResolution, tempPreferredResolution); + if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { + this->setResolutionInputSocketIndex(1); + } + else { + socket = this->getInputSocket(2); + socket->determineResolution(tempResolution, tempPreferredResolution); + if ((tempResolution[0] != 0) && (tempResolution[1] != 0)) { + this->setResolutionInputSocketIndex(2); + } + else { + this->setResolutionInputSocketIndex(0); + } + } + NodeOperation::determineResolution(resolution, preferredResolution); +} + +void MixBaseOperation::deinitExecution() +{ + this->m_inputValueOperation = NULL; + this->m_inputColor1Operation = NULL; + this->m_inputColor2Operation = NULL; +} + +/* ******** Mix Add Operation ******** */ + +MixAddOperation::MixAddOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixAddOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + output[0] = inputColor1[0] + value * inputColor2[0]; + output[1] = inputColor1[1] + value * inputColor2[1]; + output[2] = inputColor1[2] + value * inputColor2[2]; + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Blend Operation ******** */ + +MixBlendOperation::MixBlendOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixBlendOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + float value; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + value = inputValue[0]; + + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + output[0] = valuem * (inputColor1[0]) + value * (inputColor2[0]); + output[1] = valuem * (inputColor1[1]) + value * (inputColor2[1]); + output[2] = valuem * (inputColor1[2]) + value * (inputColor2[2]); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Burn Operation ******** */ + +MixBurnOperation::MixBurnOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixBurnOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + float tmp; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + tmp = valuem + value * inputColor2[0]; + if (tmp <= 0.0f) + output[0] = 0.0f; + else { + tmp = 1.0f - (1.0f - inputColor1[0]) / tmp; + if (tmp < 0.0f) + output[0] = 0.0f; + else if (tmp > 1.0f) + output[0] = 1.0f; + else + output[0] = tmp; + } + + tmp = valuem + value * inputColor2[1]; + if (tmp <= 0.0f) + output[1] = 0.0f; + else { + tmp = 1.0f - (1.0f - inputColor1[1]) / tmp; + if (tmp < 0.0f) + output[1] = 0.0f; + else if (tmp > 1.0f) + output[1] = 1.0f; + else + output[1] = tmp; + } + + tmp = valuem + value * inputColor2[2]; + if (tmp <= 0.0f) + output[2] = 0.0f; + else { + tmp = 1.0f - (1.0f - inputColor1[2]) / tmp; + if (tmp < 0.0f) + output[2] = 0.0f; + else if (tmp > 1.0f) + output[2] = 1.0f; + else + output[2] = tmp; + } + + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Color Operation ******** */ + +MixColorOperation::MixColorOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixColorOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + float colH, colS, colV; + rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); + if (colS != 0.0f) { + float rH, rS, rV; + float tmpr, tmpg, tmpb; + rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); + hsv_to_rgb(colH, colS, rV, &tmpr, &tmpg, &tmpb); + output[0] = (valuem * inputColor1[0]) + (value * tmpr); + output[1] = (valuem * inputColor1[1]) + (value * tmpg); + output[2] = (valuem * inputColor1[2]) + (value * tmpb); + } + else { + copy_v3_v3(output, inputColor1); + } + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Darken Operation ******** */ + +MixDarkenOperation::MixDarkenOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixDarkenOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + float tmp; + tmp = inputColor2[0] + ((1.0f - inputColor2[0]) * valuem); + if (tmp < inputColor1[0]) output[0] = tmp; + else output[0] = inputColor1[0]; + tmp = inputColor2[1] + ((1.0f - inputColor2[1]) * valuem); + if (tmp < inputColor1[1]) output[1] = tmp; + else output[1] = inputColor1[1]; + tmp = inputColor2[2] + ((1.0f - inputColor2[2]) * valuem); + if (tmp < inputColor1[2]) output[2] = tmp; + else output[2] = inputColor1[2]; + + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Difference Operation ******** */ + +MixDifferenceOperation::MixDifferenceOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixDifferenceOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + output[0] = valuem * inputColor1[0] + value *fabsf(inputColor1[0] - inputColor2[0]); + output[1] = valuem * inputColor1[1] + value *fabsf(inputColor1[1] - inputColor2[1]); + output[2] = valuem * inputColor1[2] + value *fabsf(inputColor1[2] - inputColor2[2]); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Difference Operation ******** */ + +MixDivideOperation::MixDivideOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixDivideOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + if (inputColor2[0] != 0.0f) + output[0] = valuem * (inputColor1[0]) + value * (inputColor1[0]) / inputColor2[0]; + else + output[0] = 0.0f; + if (inputColor2[1] != 0.0f) + output[1] = valuem * (inputColor1[1]) + value * (inputColor1[1]) / inputColor2[1]; + else + output[1] = 0.0f; + if (inputColor2[2] != 0.0f) + output[2] = valuem * (inputColor1[2]) + value * (inputColor1[2]) / inputColor2[2]; + else + output[2] = 0.0f; + + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Dodge Operation ******** */ + +MixDodgeOperation::MixDodgeOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixDodgeOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + float tmp; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + + if (inputColor1[0] != 0.0f) { + tmp = 1.0f - value * inputColor2[0]; + if (tmp <= 0.0f) + output[0] = 1.0f; + else { + tmp = inputColor1[0] / tmp; + if (tmp > 1.0f) + output[0] = 1.0f; + else + output[0] = tmp; + } + } + else + output[0] = 0.0f; + + if (inputColor1[1] != 0.0f) { + tmp = 1.0f - value * inputColor2[1]; + if (tmp <= 0.0f) + output[1] = 1.0f; + else { + tmp = inputColor1[1] / tmp; + if (tmp > 1.0f) + output[1] = 1.0f; + else + output[1] = tmp; + } + } + else + output[1] = 0.0f; + + if (inputColor1[2] != 0.0f) { + tmp = 1.0f - value * inputColor2[2]; + if (tmp <= 0.0f) + output[2] = 1.0f; + else { + tmp = inputColor1[2] / tmp; + if (tmp > 1.0f) + output[2] = 1.0f; + else + output[2] = tmp; + } + } + else + output[2] = 0.0f; + + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Glare Operation ******** */ + +MixGlareOperation::MixGlareOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixGlareOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + float value; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + value = inputValue[0]; + float mf = 2.f - 2.f * fabsf(value - 0.5f); + + if (inputColor1[0] < 0.0f) inputColor1[0] = 0.0f; + if (inputColor1[1] < 0.0f) inputColor1[1] = 0.0f; + if (inputColor1[2] < 0.0f) inputColor1[2] = 0.0f; + + output[0] = mf * max(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f); + output[1] = mf * max(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f); + output[2] = mf * max(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Hue Operation ******** */ + +MixHueOperation::MixHueOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixHueOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + float colH, colS, colV; + rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); + if (colS != 0.0f) { + float rH, rS, rV; + float tmpr, tmpg, tmpb; + rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); + hsv_to_rgb(colH, rS, rV, &tmpr, &tmpg, &tmpb); + output[0] = valuem * (inputColor1[0]) + value * tmpr; + output[1] = valuem * (inputColor1[1]) + value * tmpg; + output[2] = valuem * (inputColor1[2]) + value * tmpb; + } + else { + copy_v3_v3(output, inputColor1); + } + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Lighten Operation ******** */ + +MixLightenOperation::MixLightenOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixLightenOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float tmp; + tmp = value * inputColor2[0]; + if (tmp > inputColor1[0]) output[0] = tmp; + else output[0] = inputColor1[0]; + tmp = value * inputColor2[1]; + if (tmp > inputColor1[1]) output[1] = tmp; + else output[1] = inputColor1[1]; + tmp = value * inputColor2[2]; + if (tmp > inputColor1[2]) output[2] = tmp; + else output[2] = inputColor1[2]; + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Linear Light Operation ******** */ + +MixLinearLightOperation::MixLinearLightOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixLinearLightOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + if (inputColor2[0] > 0.5f) + output[0] = inputColor1[0] + value * (2.0f * (inputColor2[0] - 0.5f)); + else + output[0] = inputColor1[0] + value * (2.0f * (inputColor2[0]) - 1.0f); + if (inputColor2[1] > 0.5f) + output[1] = inputColor1[1] + value * (2.0f * (inputColor2[1] - 0.5f)); + else + output[1] = inputColor1[1] + value * (2.0f * (inputColor2[1]) - 1.0f); + if (inputColor2[2] > 0.5f) + output[2] = inputColor1[2] + value * (2.0f * (inputColor2[2] - 0.5f)); + else + output[2] = inputColor1[2] + value * (2.0f * (inputColor2[2]) - 1.0f); + + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Multiply Operation ******** */ + +MixMultiplyOperation::MixMultiplyOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixMultiplyOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + output[0] = inputColor1[0] * (valuem + value * inputColor2[0]); + output[1] = inputColor1[1] * (valuem + value * inputColor2[1]); + output[2] = inputColor1[2] * (valuem + value * inputColor2[2]); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Ovelray Operation ******** */ + +MixOverlayOperation::MixOverlayOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixOverlayOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + + float valuem = 1.0f - value; + + if (inputColor1[0] < 0.5f) { + output[0] = inputColor1[0] * (valuem + 2.0f * value * inputColor2[0]); + } + else { + output[0] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[0])) * (1.0f - inputColor1[0]); + } + if (inputColor1[1] < 0.5f) { + output[1] = inputColor1[1] * (valuem + 2.0f * value * inputColor2[1]); + } + else { + output[1] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[1])) * (1.0f - inputColor1[1]); + } + if (inputColor1[2] < 0.5f) { + output[2] = inputColor1[2] * (valuem + 2.0f * value * inputColor2[2]); + } + else { + output[2] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[2])) * (1.0f - inputColor1[2]); + } + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Saturation Operation ******** */ + +MixSaturationOperation::MixSaturationOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixSaturationOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + float rH, rS, rV; + rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); + if (rS != 0.0f) { + float colH, colS, colV; + rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); + hsv_to_rgb(rH, (valuem * rS + value * colS), rV, &output[0], &output[1], &output[2]); + } + else { + copy_v3_v3(output, inputColor1); + } + + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Screen Operation ******** */ + +MixScreenOperation::MixScreenOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixScreenOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + output[0] = 1.0f - (valuem + value * (1.0f - inputColor2[0])) * (1.0f - inputColor1[0]); + output[1] = 1.0f - (valuem + value * (1.0f - inputColor2[1])) * (1.0f - inputColor1[1]); + output[2] = 1.0f - (valuem + value * (1.0f - inputColor2[2])) * (1.0f - inputColor1[2]); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Soft Light Operation ******** */ + +MixSoftLightOperation::MixSoftLightOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixSoftLightOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) \ +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + float scr, scg, scb; + + /* first calculate non-fac based Screen mix */ + scr = 1.0f - (1.0f - inputColor2[0]) * (1.0f - inputColor1[0]); + scg = 1.0f - (1.0f - inputColor2[1]) * (1.0f - inputColor1[1]); + scb = 1.0f - (1.0f - inputColor2[2]) * (1.0f - inputColor1[2]); + + output[0] = valuem * (inputColor1[0]) + value * (((1.0f - inputColor1[0]) * inputColor2[0] * (inputColor1[0])) + (inputColor1[0] * scr)); + output[1] = valuem * (inputColor1[1]) + value * (((1.0f - inputColor1[1]) * inputColor2[1] * (inputColor1[1])) + (inputColor1[1] * scg)); + output[2] = valuem * (inputColor1[2]) + value * (((1.0f - inputColor1[2]) * inputColor2[2] * (inputColor1[2])) + (inputColor1[2] * scb)); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Subtract Operation ******** */ + +MixSubtractOperation::MixSubtractOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixSubtractOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + output[0] = inputColor1[0] - value * (inputColor2[0]); + output[1] = inputColor1[1] - value * (inputColor2[1]); + output[2] = inputColor1[2] - value * (inputColor2[2]); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} + +/* ******** Mix Value Operation ******** */ + +MixValueOperation::MixValueOperation() : MixBaseOperation() +{ + /* pass */ +} + +void MixValueOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float inputColor1[4]; + float inputColor2[4]; + float inputValue[4]; + + this->m_inputValueOperation->read(inputValue, x, y, sampler); + this->m_inputColor1Operation->read(inputColor1, x, y, sampler); + this->m_inputColor2Operation->read(inputColor2, x, y, sampler); + + float value = inputValue[0]; + if (this->useValueAlphaMultiply()) { + value *= inputColor2[3]; + } + float valuem = 1.0f - value; + + float rH, rS, rV; + float colH, colS, colV; + rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); + rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); + hsv_to_rgb(rH, rS, (valuem * rV + value * colV), &output[0], &output[1], &output[2]); + output[3] = inputColor1[3]; + + clampIfNeeded(output); +} diff --git a/source/blender/compositor/operations/COM_MixOperation.h b/source/blender/compositor/operations/COM_MixOperation.h new file mode 100644 index 00000000000..93dbe6f36a6 --- /dev/null +++ b/source/blender/compositor/operations/COM_MixOperation.h @@ -0,0 +1,197 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + */ + +#ifndef _COM_MixBaseOperation_h +#define _COM_MixBaseOperation_h +#include "COM_NodeOperation.h" + + +/** + * All this programs converts an input color to an output value. + * it assumes we are in sRGB color space. + */ + +class MixBaseOperation : public NodeOperation { +protected: + /** + * Prefetched reference to the inputProgram + */ + SocketReader *m_inputValueOperation; + SocketReader *m_inputColor1Operation; + SocketReader *m_inputColor2Operation; + bool m_valueAlphaMultiply; + bool m_useClamp; + + inline void clampIfNeeded(float color[4]) + { + if (m_useClamp) { + CLAMP(color[0], 0.0f, 1.0f); + CLAMP(color[1], 0.0f, 1.0f); + CLAMP(color[2], 0.0f, 1.0f); + CLAMP(color[3], 0.0f, 1.0f); + } + } + +public: + /** + * Default constructor + */ + MixBaseOperation(); + + /** + * the inner loop of this program + */ + void executePixel(float output[4], float x, float y, PixelSampler sampler); + + /** + * Initialize the execution + */ + void initExecution(); + + /** + * Deinitialize the execution + */ + void deinitExecution(); + + void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + + + void setUseValueAlphaMultiply(const bool value) { this->m_valueAlphaMultiply = value; } + bool useValueAlphaMultiply() { return this->m_valueAlphaMultiply; } + void setUseClamp(bool value) { this->m_useClamp = value; } +}; + +class MixAddOperation : public MixBaseOperation { +public: + MixAddOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixBlendOperation : public MixBaseOperation { +public: + MixBlendOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixBurnOperation : public MixBaseOperation { +public: + MixBurnOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixColorOperation : public MixBaseOperation { +public: + MixColorOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixDarkenOperation : public MixBaseOperation { +public: + MixDarkenOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixDifferenceOperation : public MixBaseOperation { +public: + MixDifferenceOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixDivideOperation : public MixBaseOperation { +public: + MixDivideOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixDodgeOperation : public MixBaseOperation { +public: + MixDodgeOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixGlareOperation : public MixBaseOperation { +public: + MixGlareOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixHueOperation : public MixBaseOperation { +public: + MixHueOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixLightenOperation : public MixBaseOperation { +public: + MixLightenOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixLinearLightOperation : public MixBaseOperation { +public: + MixLinearLightOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixMultiplyOperation : public MixBaseOperation { +public: + MixMultiplyOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixOverlayOperation : public MixBaseOperation { +public: + MixOverlayOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixSaturationOperation : public MixBaseOperation { +public: + MixSaturationOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixScreenOperation : public MixBaseOperation { +public: + MixScreenOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixSoftLightOperation : public MixBaseOperation { +public: + MixSoftLightOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixSubtractOperation : public MixBaseOperation { +public: + MixSubtractOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class MixValueOperation : public MixBaseOperation { +public: + MixValueOperation(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +#endif diff --git a/source/blender/compositor/operations/COM_MixOverlayOperation.cpp b/source/blender/compositor/operations/COM_MixOverlayOperation.cpp deleted file mode 100644 index d5e1c6d1167..00000000000 --- a/source/blender/compositor/operations/COM_MixOverlayOperation.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixOverlayOperation.h" - -MixOverlayOperation::MixOverlayOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixOverlayOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - - float valuem = 1.0f - value; - - if (inputColor1[0] < 0.5f) { - output[0] = inputColor1[0] * (valuem + 2.0f * value * inputColor2[0]); - } - else { - output[0] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[0])) * (1.0f - inputColor1[0]); - } - if (inputColor1[1] < 0.5f) { - output[1] = inputColor1[1] * (valuem + 2.0f * value * inputColor2[1]); - } - else { - output[1] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[1])) * (1.0f - inputColor1[1]); - } - if (inputColor1[2] < 0.5f) { - output[2] = inputColor1[2] * (valuem + 2.0f * value * inputColor2[2]); - } - else { - output[2] = 1.0f - (valuem + 2.0f * value * (1.0f - inputColor2[2])) * (1.0f - inputColor1[2]); - } - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - diff --git a/source/blender/compositor/operations/COM_MixOverlayOperation.h b/source/blender/compositor/operations/COM_MixOverlayOperation.h deleted file mode 100644 index 4f2c08ce95f..00000000000 --- a/source/blender/compositor/operations/COM_MixOverlayOperation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixOverlayOperation_h -#define _COM_MixOverlayOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixOverlayOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixOverlayOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixSaturationOperation.cpp b/source/blender/compositor/operations/COM_MixSaturationOperation.cpp deleted file mode 100644 index ca45a1c703a..00000000000 --- a/source/blender/compositor/operations/COM_MixSaturationOperation.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixSaturationOperation.h" - -extern "C" { - #include "BLI_math.h" -} - -MixSaturationOperation::MixSaturationOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixSaturationOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - float rH, rS, rV; - rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); - if (rS != 0.0f) { - float colH, colS, colV; - rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); - hsv_to_rgb(rH, (valuem * rS + value * colS), rV, &output[0], &output[1], &output[2]); - } - else { - copy_v3_v3(output, inputColor1); - } - - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} diff --git a/source/blender/compositor/operations/COM_MixSaturationOperation.h b/source/blender/compositor/operations/COM_MixSaturationOperation.h deleted file mode 100644 index c690db38daf..00000000000 --- a/source/blender/compositor/operations/COM_MixSaturationOperation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixSaturationOperation_h -#define _COM_MixSaturationOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixSaturationOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixSaturationOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixScreenOperation.cpp b/source/blender/compositor/operations/COM_MixScreenOperation.cpp deleted file mode 100644 index 511768a49ad..00000000000 --- a/source/blender/compositor/operations/COM_MixScreenOperation.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixScreenOperation.h" - -MixScreenOperation::MixScreenOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixScreenOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - output[0] = 1.0f - (valuem + value * (1.0f - inputColor2[0])) * (1.0f - inputColor1[0]); - output[1] = 1.0f - (valuem + value * (1.0f - inputColor2[1])) * (1.0f - inputColor1[1]); - output[2] = 1.0f - (valuem + value * (1.0f - inputColor2[2])) * (1.0f - inputColor1[2]); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - diff --git a/source/blender/compositor/operations/COM_MixScreenOperation.h b/source/blender/compositor/operations/COM_MixScreenOperation.h deleted file mode 100644 index 5ba3cf769bb..00000000000 --- a/source/blender/compositor/operations/COM_MixScreenOperation.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixScreenOperation_h -#define _COM_MixScreenOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixScreenOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixScreenOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixSoftLightOperation.cpp b/source/blender/compositor/operations/COM_MixSoftLightOperation.cpp deleted file mode 100644 index 71d83ce54ea..00000000000 --- a/source/blender/compositor/operations/COM_MixSoftLightOperation.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixSoftLightOperation.h" - -MixSoftLightOperation::MixSoftLightOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixSoftLightOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) \ -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - float scr, scg, scb; - - /* first calculate non-fac based Screen mix */ - scr = 1.0f - (1.0f - inputColor2[0]) * (1.0f - inputColor1[0]); - scg = 1.0f - (1.0f - inputColor2[1]) * (1.0f - inputColor1[1]); - scb = 1.0f - (1.0f - inputColor2[2]) * (1.0f - inputColor1[2]); - - output[0] = valuem * (inputColor1[0]) + value * (((1.0f - inputColor1[0]) * inputColor2[0] * (inputColor1[0])) + (inputColor1[0] * scr)); - output[1] = valuem * (inputColor1[1]) + value * (((1.0f - inputColor1[1]) * inputColor2[1] * (inputColor1[1])) + (inputColor1[1] * scg)); - output[2] = valuem * (inputColor1[2]) + value * (((1.0f - inputColor1[2]) * inputColor2[2] * (inputColor1[2])) + (inputColor1[2] * scb)); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - diff --git a/source/blender/compositor/operations/COM_MixSoftLightOperation.h b/source/blender/compositor/operations/COM_MixSoftLightOperation.h deleted file mode 100644 index 55f6a70791a..00000000000 --- a/source/blender/compositor/operations/COM_MixSoftLightOperation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixSoftLightOperation_h -#define _COM_MixSoftLightOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixSoftLightOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixSoftLightOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixSubtractOperation.cpp b/source/blender/compositor/operations/COM_MixSubtractOperation.cpp deleted file mode 100644 index e6efe0f62f3..00000000000 --- a/source/blender/compositor/operations/COM_MixSubtractOperation.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixSubtractOperation.h" - -MixSubtractOperation::MixSubtractOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixSubtractOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - output[0] = inputColor1[0] - value * (inputColor2[0]); - output[1] = inputColor1[1] - value * (inputColor2[1]); - output[2] = inputColor1[2] - value * (inputColor2[2]); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} - diff --git a/source/blender/compositor/operations/COM_MixSubtractOperation.h b/source/blender/compositor/operations/COM_MixSubtractOperation.h deleted file mode 100644 index 046d8d4949b..00000000000 --- a/source/blender/compositor/operations/COM_MixSubtractOperation.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixSubtractOperation_h -#define _COM_MixSubtractOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixSubtractOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixSubtractOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); - -}; -#endif diff --git a/source/blender/compositor/operations/COM_MixValueOperation.cpp b/source/blender/compositor/operations/COM_MixValueOperation.cpp deleted file mode 100644 index 553041e39bf..00000000000 --- a/source/blender/compositor/operations/COM_MixValueOperation.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_MixValueOperation.h" - -extern "C" { - #include "BLI_math.h" -} - -MixValueOperation::MixValueOperation() : MixBaseOperation() -{ - /* pass */ -} - -void MixValueOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float inputColor1[4]; - float inputColor2[4]; - float inputValue[4]; - - this->m_inputValueOperation->read(inputValue, x, y, sampler); - this->m_inputColor1Operation->read(inputColor1, x, y, sampler); - this->m_inputColor2Operation->read(inputColor2, x, y, sampler); - - float value = inputValue[0]; - if (this->useValueAlphaMultiply()) { - value *= inputColor2[3]; - } - float valuem = 1.0f - value; - - float rH, rS, rV; - float colH, colS, colV; - rgb_to_hsv(inputColor1[0], inputColor1[1], inputColor1[2], &rH, &rS, &rV); - rgb_to_hsv(inputColor2[0], inputColor2[1], inputColor2[2], &colH, &colS, &colV); - hsv_to_rgb(rH, rS, (valuem * rV + value * colV), &output[0], &output[1], &output[2]); - output[3] = inputColor1[3]; - - clampIfNeeded(output); -} diff --git a/source/blender/compositor/operations/COM_MixValueOperation.h b/source/blender/compositor/operations/COM_MixValueOperation.h deleted file mode 100644 index 6c3f3ce8072..00000000000 --- a/source/blender/compositor/operations/COM_MixValueOperation.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_MixValueOperation_h -#define _COM_MixValueOperation_h -#include "COM_MixBaseOperation.h" - - -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class MixValueOperation : public MixBaseOperation { -public: - /** - * Default constructor - */ - MixValueOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); -}; -#endif diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp index 1c9dd0f170e..e2a95b2e33b 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp @@ -27,16 +27,15 @@ extern "C" { #include "IMB_imbuf_types.h" } -MultilayerBaseOperation::MultilayerBaseOperation(int pass) : BaseImageOperation() +MultilayerBaseOperation::MultilayerBaseOperation(int passindex) : BaseImageOperation() { - this->m_passId = pass; + this->m_passId = passindex; } ImBuf *MultilayerBaseOperation::getImBuf() { - RenderPass *rpass; - rpass = (RenderPass *)BLI_findlink(&this->m_renderlayer->passes, this->m_passId); + RenderPass *rpass = (RenderPass *)BLI_findlink(&this->m_renderlayer->passes, this->m_passId); if (rpass) { - this->m_imageUser->pass = this->m_passId; + this->m_imageUser->pass = m_passId; BKE_image_multilayer_index(this->m_image->rr, this->m_imageUser); return BaseImageOperation::getImBuf(); } @@ -47,7 +46,7 @@ void MultilayerColorOperation::executePixel(float output[4], float x, float y, P { int yi = y; int xi = x; - if (this->m_imageBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) { + if (this->m_imageFloatBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) { zero_v4(output); } else { @@ -66,7 +65,7 @@ void MultilayerColorOperation::executePixel(float output[4], float x, float y, P } else { int offset = (yi * this->getWidth() + xi) * 3; - copy_v3_v3(output, &this->m_imageBuffer[offset]); + copy_v3_v3(output, &this->m_imageFloatBuffer[offset]); } } } @@ -75,11 +74,11 @@ void MultilayerValueOperation::executePixel(float output[4], float x, float y, P { int yi = y; int xi = x; - if (this->m_imageBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) { + if (this->m_imageFloatBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) { output[0] = 0.0f; } else { - float result = this->m_imageBuffer[yi * this->getWidth() + xi]; + float result = this->m_imageFloatBuffer[yi * this->getWidth() + xi]; output[0] = result; } } @@ -88,11 +87,11 @@ void MultilayerVectorOperation::executePixel(float output[4], float x, float y, { int yi = y; int xi = x; - if (this->m_imageBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) { + if (this->m_imageFloatBuffer == NULL || xi < 0 || yi < 0 || (unsigned int)xi >= this->getWidth() || (unsigned int)yi >= this->getHeight() ) { output[0] = 0.0f; } else { int offset = (yi * this->getWidth() + xi) * 3; - copy_v3_v3(output, &this->m_imageBuffer[offset]); + copy_v3_v3(output, &this->m_imageFloatBuffer[offset]); } } diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.h b/source/blender/compositor/operations/COM_MultilayerImageOperation.h index 3c498e962b5..065bcc7da1e 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.h +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.h @@ -37,13 +37,13 @@ public: /** * Constructor */ - MultilayerBaseOperation(int pass); + MultilayerBaseOperation(int passindex); void setRenderLayer(RenderLayer *renderlayer) { this->m_renderlayer = renderlayer; } }; class MultilayerColorOperation : public MultilayerBaseOperation { public: - MultilayerColorOperation(int pass) : MultilayerBaseOperation(pass) { + MultilayerColorOperation(int passindex) : MultilayerBaseOperation(passindex) { this->addOutputSocket(COM_DT_COLOR); } void executePixel(float output[4], float x, float y, PixelSampler sampler); @@ -51,7 +51,7 @@ public: class MultilayerValueOperation : public MultilayerBaseOperation { public: - MultilayerValueOperation(int pass) : MultilayerBaseOperation(pass) { + MultilayerValueOperation(int passindex) : MultilayerBaseOperation(passindex) { this->addOutputSocket(COM_DT_VALUE); } void executePixel(float output[4], float x, float y, PixelSampler sampler); @@ -59,7 +59,7 @@ public: class MultilayerVectorOperation : public MultilayerBaseOperation { public: - MultilayerVectorOperation(int pass) : MultilayerBaseOperation(pass) { + MultilayerVectorOperation(int passindex) : MultilayerBaseOperation(passindex) { this->addOutputSocket(COM_DT_VECTOR); } void executePixel(float output[4], float x, float y, PixelSampler sampler); diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp index 15e5ab947d4..a5be993f241 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp @@ -138,7 +138,7 @@ void OutputSingleLayerOperation::deinitExecution() ibuf->mall |= IB_rectfloat; ibuf->dither = this->m_rd->dither_intensity; - IMB_colormanagement_imbuf_for_write(ibuf, TRUE, FALSE, m_viewSettings, m_displaySettings, + IMB_colormanagement_imbuf_for_write(ibuf, true, false, m_viewSettings, m_displaySettings, this->m_format); BKE_makepicstring(filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format, @@ -184,15 +184,21 @@ void OutputOpenExrMultiLayerOperation::add_layer(const char *name, DataType data void OutputOpenExrMultiLayerOperation::initExecution() { for (unsigned int i = 0; i < this->m_layers.size(); ++i) { - this->m_layers[i].imageInput = getInputSocketReader(i); - this->m_layers[i].outputBuffer = init_buffer(this->getWidth(), this->getHeight(), this->m_layers[i].datatype); + SocketReader *reader = getInputSocketReader(i); + this->m_layers[i].imageInput = reader; + if (reader) + this->m_layers[i].outputBuffer = init_buffer(this->getWidth(), this->getHeight(), this->m_layers[i].datatype); + else + this->m_layers[i].outputBuffer = NULL; } } void OutputOpenExrMultiLayerOperation::executeRegion(rcti *rect, unsigned int tileNumber) { for (unsigned int i = 0; i < this->m_layers.size(); ++i) { - write_buffer_rect(rect, this->m_tree, this->m_layers[i].imageInput, this->m_layers[i].outputBuffer, this->getWidth(), this->m_layers[i].datatype); + OutputOpenExrLayer &layer = this->m_layers[i]; + if (layer.imageInput) + write_buffer_rect(rect, this->m_tree, layer.imageInput, layer.outputBuffer, this->getWidth(), layer.datatype); } } @@ -210,6 +216,10 @@ void OutputOpenExrMultiLayerOperation::deinitExecution() BLI_make_existing_file(filename); for (unsigned int i = 0; i < this->m_layers.size(); ++i) { + OutputOpenExrLayer &layer = this->m_layers[i]; + if (!layer.imageInput) + continue; /* skip unconnected sockets */ + char channelname[EXR_TOT_MAXNAME]; BLI_strncpy(channelname, this->m_layers[i].name, sizeof(channelname) - 2); char *channelname_ext = channelname + strlen(channelname); diff --git a/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.cpp new file mode 100644 index 00000000000..51e803f696b --- /dev/null +++ b/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.cpp @@ -0,0 +1,95 @@ +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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. + * + * Contributor: + * Sergey Sharybin + */ + +#include "COM_PlaneTrackMaskOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color.h" + +extern "C" { + #include "BKE_movieclip.h" + #include "BKE_node.h" + #include "BKE_tracking.h" +} + +PlaneTrackCommonOperation::PlaneTrackCommonOperation() : NodeOperation() +{ + this->m_movieClip = NULL; + this->m_framenumber = 0; + this->m_trackingObjectName[0] = '\0'; + this->m_planeTrackName[0] = '\0'; +} + +void PlaneTrackCommonOperation::initExecution() +{ + MovieTracking *tracking; + MovieTrackingObject *object; + + memset(this->m_corners, 0, sizeof(this->m_corners)); + memset(this->m_frameSpaceCorners, 0, sizeof(this->m_frameSpaceCorners)); + + if (!this->m_movieClip) + return; + + tracking = &this->m_movieClip->tracking; + + object = BKE_tracking_object_get_named(tracking, this->m_trackingObjectName); + if (object) { + MovieTrackingPlaneTrack *plane_track; + + plane_track = BKE_tracking_plane_track_get_named(tracking, object, this->m_planeTrackName); + + if (plane_track) { + MovieTrackingPlaneMarker *plane_marker; + int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, this->m_framenumber); + + plane_marker = BKE_tracking_plane_marker_get(plane_track, clip_framenr); + memcpy(this->m_corners, plane_marker->corners, sizeof(this->m_corners)); + } + } + + for (int i = 0; i < 4; i++) { + this->m_frameSpaceCorners[i][0] = this->m_corners[i][0] * this->getWidth(); + this->m_frameSpaceCorners[i][1] = this->m_corners[i][1] * this->getHeight(); + } +} + +void PlaneTrackCommonOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) +{ + NodeOperation::determineResolution(resolution, preferredResolution); + + resolution[0] = 0; + resolution[1] = 0; + + if (this->m_movieClip) { + int width, height; + MovieClipUser user = {0}; + + BKE_movieclip_user_set_frame(&user, this->m_framenumber); + BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height); + + resolution[0] = width; + resolution[1] = height; + } +} diff --git a/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.h b/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.h new file mode 100644 index 00000000000..705bdf4bd81 --- /dev/null +++ b/source/blender/compositor/operations/COM_PlaneTrackCommonOperation.h @@ -0,0 +1,62 @@ + +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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. + * + * Contributor: + * Sergey Sharybin + */ + +#ifndef _COM_PlaneTrackCommonOperation_h +#define _COM_PlaneTrackCommonOperation_h + +#include <string.h> + +#include "COM_NodeOperation.h" + +#include "DNA_movieclip_types.h" +#include "DNA_tracking_types.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +class PlaneTrackCommonOperation : public NodeOperation { +protected: + MovieClip *m_movieClip; + int m_framenumber; + char m_trackingObjectName[64]; + char m_planeTrackName[64]; + + float m_corners[4][2]; /* Corners coordinates in normalized space. */ + float m_frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */ + + /** + * Determine the output resolution. The resolution is retrieved from the Renderer + */ + void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + +public: + PlaneTrackCommonOperation(); + + void setMovieClip(MovieClip *clip) {this->m_movieClip = clip;} + void setTrackingObject(char *object) { BLI_strncpy(this->m_trackingObjectName, object, sizeof(this->m_trackingObjectName)); } + void setPlaneTrackName(char *plane_track) { BLI_strncpy(this->m_planeTrackName, plane_track, sizeof(this->m_planeTrackName)); } + void setFramenumber(int framenumber) {this->m_framenumber = framenumber;} + + void initExecution(); +}; + +#endif diff --git a/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.cpp new file mode 100644 index 00000000000..8aa1324d8e2 --- /dev/null +++ b/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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. + * + * Contributor: + * Sergey Sharybin + */ + +#include "COM_PlaneTrackMaskOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color.h" + +extern "C" { + #include "BLI_jitter.h" + + #include "BKE_movieclip.h" + #include "BKE_node.h" + #include "BKE_tracking.h" +} + +PlaneTrackMaskOperation::PlaneTrackMaskOperation() : PlaneTrackCommonOperation() +{ + this->addOutputSocket(COM_DT_VALUE); + + /* Currently hardcoded to 8 samples. */ + this->m_osa = 8; +} + +void PlaneTrackMaskOperation::initExecution() +{ + PlaneTrackCommonOperation::initExecution(); + + BLI_jitter_init(this->m_jitter[0], this->m_osa); +} + +void PlaneTrackMaskOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float point[2]; + + int inside_counter = 0; + for (int sample = 0; sample < this->m_osa; sample++) { + point[0] = x + this->m_jitter[sample][0]; + point[1] = y + this->m_jitter[sample][1]; + + if (isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[1], this->m_frameSpaceCorners[2]) || + isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[2], this->m_frameSpaceCorners[3])) + { + inside_counter++; + } + } + + output[0] = (float) inside_counter / this->m_osa; +} diff --git a/source/blender/compositor/operations/COM_SeparateChannelOperation.h b/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.h index f964df5df02..db32f9830e0 100644 --- a/source/blender/compositor/operations/COM_SeparateChannelOperation.h +++ b/source/blender/compositor/operations/COM_PlaneTrackMaskOperation.h @@ -1,5 +1,6 @@ + /* - * Copyright 2011, Blender Foundation. + * Copyright 2013, Blender Foundation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,28 +16,34 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand + * Contributor: + * Sergey Sharybin */ -#ifndef _COM_SeparateChannelOperation_h_ -#define _COM_SeparateChannelOperation_h_ +#ifndef _COM_PlaneTrackMaskOperation_h +#define _COM_PlaneTrackMaskOperation_h + +#include <string.h> + +#include "COM_PlaneTrackCommonOperation.h" + +#include "DNA_movieclip_types.h" +#include "DNA_tracking_types.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" -#include "COM_NodeOperation.h" +class PlaneTrackMaskOperation : public PlaneTrackCommonOperation { +protected: + int m_osa; + float m_jitter[32][2]; -class SeparateChannelOperation : public NodeOperation { -private: - SocketReader *m_inputOperation; - int m_channel; public: - SeparateChannelOperation(); - void executePixel(float output[4], float x, float y, PixelSampler sampler); - + PlaneTrackMaskOperation(); + void initExecution(); - void deinitExecution(); - - void setChannel(int channel) { this->m_channel = channel; } + + void executePixel(float output[4], float x, float y, PixelSampler sampler); }; #endif diff --git a/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.cpp new file mode 100644 index 00000000000..df487a766f3 --- /dev/null +++ b/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.cpp @@ -0,0 +1,184 @@ +/* + * Copyright 2013, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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. + * + * Contributor: + * Sergey Sharybin + */ + +#include "COM_PlaneTrackWarpImageOperation.h" +#include "COM_ReadBufferOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color.h" + +extern "C" { + #include "BLI_jitter.h" + + #include "BKE_movieclip.h" + #include "BKE_node.h" + #include "BKE_tracking.h" +} + +BLI_INLINE bool isPointInsideQuad(const float x, const float y, const float corners[4][2]) +{ + float point[2]; + + point[0] = x; + point[1] = y; + + return isect_point_tri_v2(point, corners[0], corners[1], corners[2]) || + isect_point_tri_v2(point, corners[0], corners[2], corners[3]); +} + +BLI_INLINE bool resolveUV(const float x, const float y, const float corners[4][2], float uv[2]) +{ + float point[2]; + bool inside; + + inside = isPointInsideQuad(x, y, corners); + + point[0] = x; + point[1] = y; + + /* Use reverse bilinear to get UV coordinates within original frame */ + resolve_quad_uv(uv, point, corners[0], corners[1], corners[2], corners[3]); + + return inside; +} + +BLI_INLINE void resolveUVAndDxDy(const float x, const float y, const float corners[4][2], + float *u_r, float *v_r, float *dx_r, float *dy_r) +{ + float inputUV[2]; + float uv_a[2], uv_b[2]; + + float dx, dy; + float uv_l, uv_r; + float uv_u, uv_d; + + bool ok1, ok2; + + resolveUV(x, y, corners, inputUV); + + /* adaptive sampling, red (U) channel */ + ok1 = resolveUV(x - 1, y, corners, uv_a); + ok2 = resolveUV(x + 1, y, corners, uv_b); + uv_l = ok1 ? fabsf(inputUV[0] - uv_a[0]) : 0.0f; + uv_r = ok2 ? fabsf(inputUV[0] - uv_b[0]) : 0.0f; + + dx = 0.5f * (uv_l + uv_r); + + /* adaptive sampling, green (V) channel */ + ok1 = resolveUV(x, y - 1, corners, uv_a); + ok2 = resolveUV(x, y + 1, corners, uv_b); + uv_u = ok1 ? fabsf(inputUV[1] - uv_a[1]) : 0.f; + uv_d = ok2 ? fabsf(inputUV[1] - uv_b[1]) : 0.f; + + dy = 0.5f * (uv_u + uv_d); + + *dx_r = dx; + *dy_r = dy; + + *u_r = inputUV[0]; + *v_r = inputUV[1]; +} + +PlaneTrackWarpImageOperation::PlaneTrackWarpImageOperation() : PlaneTrackCommonOperation() +{ + this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); + this->addOutputSocket(COM_DT_COLOR); + this->m_pixelReader = NULL; + this->setComplex(true); + + /* Currently hardcoded to 8 samples. */ + this->m_osa = 8; +} + +void PlaneTrackWarpImageOperation::initExecution() +{ + PlaneTrackCommonOperation::initExecution(); + + this->m_pixelReader = this->getInputSocketReader(0); + + BLI_jitter_init(this->m_jitter[0], this->m_osa); +} + +void PlaneTrackWarpImageOperation::deinitExecution() +{ + this->m_pixelReader = NULL; +} + +void PlaneTrackWarpImageOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + float color_accum[4]; + + zero_v4(color_accum); + for (int sample = 0; sample < this->m_osa; sample++) { + float current_x = x + this->m_jitter[sample][0], + current_y = y + this->m_jitter[sample][1]; + if (isPointInsideQuad(current_x, current_y, this->m_frameSpaceCorners)) { + float current_color[4]; + float u, v, dx, dy; + + resolveUVAndDxDy(current_x, current_y, this->m_frameSpaceCorners, &u, &v, &dx, &dy); + + u *= this->m_pixelReader->getWidth(); + v *= this->m_pixelReader->getHeight(); + + this->m_pixelReader->read(current_color, u, v, dx, dy, COM_PS_NEAREST); + add_v4_v4(color_accum, current_color); + } + } + + mul_v4_v4fl(output, color_accum, 1.0f / this->m_osa); +} + +bool PlaneTrackWarpImageOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + float frame_space_corners[4][2]; + + for (int i = 0; i < 4; i++) { + frame_space_corners[i][0] = this->m_corners[i][0] * this->getWidth(); + frame_space_corners[i][1] = this->m_corners[i][1] * this->getHeight(); + } + + float UVs[4][2]; + + /* TODO(sergey): figure out proper way to do this. */ + resolveUV(input->xmin - 2, input->ymin - 2, frame_space_corners, UVs[0]); + resolveUV(input->xmax + 2, input->ymin - 2, frame_space_corners, UVs[1]); + resolveUV(input->xmax + 2, input->ymax + 2, frame_space_corners, UVs[2]); + resolveUV(input->xmin - 2, input->ymax + 2, frame_space_corners, UVs[3]); + + float min[2], max[2]; + INIT_MINMAX2(min, max); + for (int i = 0; i < 4; i++) { + minmax_v2v2_v2(min, max, UVs[i]); + } + + rcti newInput; + + newInput.xmin = min[0] * readOperation->getWidth() - 1; + newInput.ymin = min[1] * readOperation->getHeight() - 1; + newInput.xmax = max[0] * readOperation->getWidth() + 1; + newInput.ymax = max[1] * readOperation->getHeight() + 1; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.h b/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.h index d0191f292d2..a92ff3f9ddf 100644 --- a/source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.h +++ b/source/blender/compositor/operations/COM_PlaneTrackWarpImageOperation.h @@ -1,5 +1,6 @@ + /* - * Copyright 2012, Blender Foundation. + * Copyright 2013, Blender Foundation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -16,34 +17,37 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Contributor: - * Dalai Felinto + * Sergey Sharybin */ -#ifndef _COM_ConvertStraightToPremulOperation_h -#define _COM_ConvertStraightToPremulOperation_h -#include "COM_NodeOperation.h" +#ifndef _COM_PlaneTrackWarpImageOperation_h +#define _COM_PlaneTrackWarpImageOperation_h +#include <string.h> + +#include "COM_PlaneTrackCommonOperation.h" + +#include "DNA_movieclip_types.h" +#include "DNA_tracking_types.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +class PlaneTrackWarpImageOperation : public PlaneTrackCommonOperation { +protected: + SocketReader *m_pixelReader; + int m_osa; + float m_jitter[32][2]; -/** - * this program converts an input color to an output value. - * it assumes we are in sRGB color space. - */ -class ConvertStraightToPremulOperation : public NodeOperation { -private: - SocketReader *m_inputColor; public: - /** - * Default constructor - */ - ConvertStraightToPremulOperation(); - - /** - * the inner loop of this program - */ - void executePixel(float output[4], float x, float y, PixelSampler sampler); + PlaneTrackWarpImageOperation(); void initExecution(); void deinitExecution(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); + + bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output); }; + #endif diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp index 5cc02a1ed65..e8b900b9a85 100644 --- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp +++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp @@ -55,11 +55,11 @@ void ProjectorLensDistortionOperation::executePixel(float output[4], int x, int const float v = (y + 0.5f) / height; const float u = (x + 0.5f) / width; MemoryBuffer *inputBuffer = (MemoryBuffer *)data; - inputBuffer->readCubic(inputValue, (u * width + this->m_kr2) - 0.5f, v * height - 0.5f); + inputBuffer->readBilinear(inputValue, (u * width + this->m_kr2) - 0.5f, v * height - 0.5f); output[0] = inputValue[0]; inputBuffer->read(inputValue, x, y); output[1] = inputValue[1]; - inputBuffer->readCubic(inputValue, (u * width - this->m_kr2) - 0.5f, v * height - 0.5f); + inputBuffer->readBilinear(inputValue, (u * width - this->m_kr2) - 0.5f, v * height - 0.5f); output[2] = inputValue[2]; output[3] = 1.0f; } diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp b/source/blender/compositor/operations/COM_ReadBufferOperation.cpp index 03d41edda64..3aeef6bf409 100644 --- a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp +++ b/source/blender/compositor/operations/COM_ReadBufferOperation.cpp @@ -27,6 +27,7 @@ ReadBufferOperation::ReadBufferOperation() : NodeOperation() { this->addOutputSocket(COM_DT_COLOR); + this->m_single_value = false; this->m_offset = 0; this->m_buffer = NULL; } @@ -47,21 +48,48 @@ void ReadBufferOperation::determineResolution(unsigned int resolution[2], unsign if (this->m_memoryProxy->getExecutor()) { this->m_memoryProxy->getExecutor()->setResolution(resolution); } + + m_single_value = operation->isSingleValue(); } } void ReadBufferOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) { - if (sampler == COM_PS_NEAREST) { + if (m_single_value) { + /* write buffer has a single value stored at (0,0) */ + m_buffer->read(output, 0, 0); + } + else if (sampler == COM_PS_NEAREST) { m_buffer->read(output, x, y); } else { - m_buffer->readCubic(output, x, y); + m_buffer->readBilinear(output, x, y); + } +} + +void ReadBufferOperation::executePixelExtend(float output[4], float x, float y, PixelSampler sampler, + MemoryBufferExtend extend_x, MemoryBufferExtend extend_y) +{ + if (m_single_value) { + /* write buffer has a single value stored at (0,0) */ + m_buffer->read(output, 0, 0); + } + else if (sampler == COM_PS_NEAREST) { + m_buffer->read(output, x, y, extend_x, extend_y); + } + else { + m_buffer->readBilinear(output, x, y, extend_x, extend_y); } } void ReadBufferOperation::executePixel(float output[4], float x, float y, float dx, float dy, PixelSampler sampler) { - m_buffer->readEWA(output, x, y, dx, dy, sampler); + if (m_single_value) { + /* write buffer has a single value stored at (0,0) */ + m_buffer->read(output, 0, 0); + } + else { + m_buffer->readEWA(output, x, y, dx, dy, sampler); + } } bool ReadBufferOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.h b/source/blender/compositor/operations/COM_ReadBufferOperation.h index 7e3ac147ee3..7a67056eda6 100644 --- a/source/blender/compositor/operations/COM_ReadBufferOperation.h +++ b/source/blender/compositor/operations/COM_ReadBufferOperation.h @@ -29,6 +29,7 @@ class ReadBufferOperation : public NodeOperation { private: MemoryProxy *m_memoryProxy; + bool m_single_value; /* single value stored in buffer, copied from associated write operation */ unsigned int m_offset; MemoryBuffer *m_buffer; public: @@ -40,10 +41,12 @@ public: void *initializeTileData(rcti *rect); void executePixel(float output[4], float x, float y, PixelSampler sampler); + void executePixelExtend(float output[4], float x, float y, PixelSampler sampler, + MemoryBufferExtend extend_x, MemoryBufferExtend extend_y); void executePixel(float output[4], float x, float y, float dx, float dy, PixelSampler sampler); const bool isReadBufferOperation() const { return true; } void setOffset(unsigned int offset) { this->m_offset = offset; } - unsigned int getOffset() { return this->m_offset; } + unsigned int getOffset() const { return this->m_offset; } bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output); MemoryBuffer *getInputMemoryBuffer(MemoryBuffer **memoryBuffers) { return memoryBuffers[this->m_offset]; } void readResolutionFromWriteBuffer(); diff --git a/source/blender/compositor/operations/COM_RenderLayersAOOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersAOOperation.cpp deleted file mode 100644 index bb165c2fe1c..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersAOOperation.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersAOOperation.h" - -RenderLayersAOOperation::RenderLayersAOOperation() : RenderLayersBaseProg(SCE_PASS_AO, 3) -{ - this->addOutputSocket(COM_DT_COLOR); -} - diff --git a/source/blender/compositor/operations/COM_RenderLayersAOOperation.h b/source/blender/compositor/operations/COM_RenderLayersAOOperation.h deleted file mode 100644 index 71b0b885e81..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersAOOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersAOOperation_h -#define _COM_RenderLayersAOOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersAOOperation : public RenderLayersBaseProg { -public: - RenderLayersAOOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersAlphaProg.cpp b/source/blender/compositor/operations/COM_RenderLayersAlphaProg.cpp deleted file mode 100644 index 74cb506d264..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersAlphaProg.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersAlphaProg.h" - -RenderLayersAlphaProg::RenderLayersAlphaProg() : RenderLayersBaseProg(SCE_PASS_COMBINED, 4) -{ - this->addOutputSocket(COM_DT_VALUE); -} - -void RenderLayersAlphaProg::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - int ix = x; - int iy = y; - float *inputBuffer = this->getInputBuffer(); - - if (inputBuffer == NULL || ix < 0 || iy < 0 || ix >= (int)this->getWidth() || iy >= (int)this->getHeight() ) { - output[0] = 0.0f; - output[1] = 0.0f; - output[2] = 0.0f; - output[3] = 0.0f; - } - else { - unsigned int offset = (iy * this->getWidth() + ix) * 4; - output[0] = inputBuffer[offset + 3]; - output[1] = 0.0f; - output[2] = 0.0f; - output[3] = 0.0f; - } -} diff --git a/source/blender/compositor/operations/COM_RenderLayersBaseProg.cpp b/source/blender/compositor/operations/COM_RenderLayersBaseProg.cpp deleted file mode 100644 index b50dca33f3b..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersBaseProg.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersBaseProg.h" - -#include "BLI_listbase.h" -#include "DNA_scene_types.h" - -extern "C" { - #include "RE_pipeline.h" - #include "RE_shader_ext.h" - #include "RE_render_ext.h" -} - -RenderLayersBaseProg::RenderLayersBaseProg(int renderpass, int elementsize) : NodeOperation() -{ - this->m_renderpass = renderpass; - this->setScene(NULL); - this->m_inputBuffer = NULL; - this->m_elementsize = elementsize; - this->m_rd = NULL; -} - - -void RenderLayersBaseProg::initExecution() -{ - Scene *scene = this->getScene(); - Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL; - RenderResult *rr = NULL; - - if (re) - rr = RE_AcquireResultRead(re); - - if (rr) { - SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, getLayerId()); - if (srl) { - - RenderLayer *rl = RE_GetRenderLayer(rr, srl->name); - if (rl && rl->rectf) { - this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_renderpass); - - if (this->m_inputBuffer == NULL || this->m_renderpass == SCE_PASS_COMBINED) { - this->m_inputBuffer = rl->rectf; - } - } - } - } - if (re) { - RE_ReleaseResult(re); - re = NULL; - } -} - -void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, PixelSampler sampler) -{ - unsigned int offset; - int ix, iy; - int width = this->getWidth(), height = this->getHeight(); - - switch (sampler) { - case COM_PS_NEAREST: - ix = x; - iy = y; - offset = (iy * width + ix) * this->m_elementsize; - - if (this->m_elementsize == 1) - output[0] = this->m_inputBuffer[offset]; - else if (this->m_elementsize == 3) - copy_v3_v3(output, &this->m_inputBuffer[offset]); - else - copy_v4_v4(output, &this->m_inputBuffer[offset]); - - break; - - case COM_PS_BILINEAR: - BLI_bilinear_interpolation_fl(this->m_inputBuffer, output, width, height, this->m_elementsize, x, y); - break; - - case COM_PS_BICUBIC: - BLI_bicubic_interpolation_fl(this->m_inputBuffer, output, width, height, this->m_elementsize, x, y); - break; - } - - if (this->m_elementsize == 1) { - output[1] = 0.0f; - output[2] = 0.0f; - output[3] = 0.0f; - } - else if (this->m_elementsize == 3) { - output[3] = 1.0f; - } -} - -void RenderLayersBaseProg::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ -#if 0 - const RenderData *rd = this->m_rd; - - int dx = 0, dy = 0; - - if (rd->mode & R_BORDER && rd->mode & R_CROP) { - /* see comment in executeRegion describing coordinate mapping, - * here it simply goes other way around - */ - int full_width = rd->xsch * rd->size / 100; - int full_height = rd->ysch * rd->size / 100; - - dx = rd->border.xmin * full_width - (full_width - this->getWidth()) / 2.0f; - dy = rd->border.ymin * full_height - (full_height - this->getHeight()) / 2.0f; - } - - int ix = x - dx; - int iy = y - dy; -#else - int ix = x; - int iy = y; -#endif - - if (this->m_inputBuffer == NULL || ix < 0 || iy < 0 || ix >= (int)this->getWidth() || iy >= (int)this->getHeight() ) { - zero_v4(output); - } - else { - doInterpolation(output, ix, iy, sampler); - } -} - -void RenderLayersBaseProg::deinitExecution() -{ - this->m_inputBuffer = NULL; -} - -void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) -{ - Scene *sce = this->getScene(); - Render *re = (sce) ? RE_GetRender(sce->id.name) : NULL; - RenderResult *rr = NULL; - - resolution[0] = 0; - resolution[1] = 0; - - if (re) - rr = RE_AcquireResultRead(re); - - if (rr) { - SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&sce->r.layers, getLayerId()); - if (srl) { - RenderLayer *rl = RE_GetRenderLayer(rr, srl->name); - if (rl && rl->rectf) { - resolution[0] = rl->rectx; - resolution[1] = rl->recty; - } - } - } - - if (re) - RE_ReleaseResult(re); - -} - diff --git a/source/blender/compositor/operations/COM_RenderLayersColorOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersColorOperation.cpp deleted file mode 100644 index 3083c37c2bb..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersColorOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersColorOperation.h" - -RenderLayersColorOperation::RenderLayersColorOperation() : RenderLayersBaseProg(SCE_PASS_RGBA, 4) -{ - this->addOutputSocket(COM_DT_COLOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersCyclesOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersCyclesOperation.cpp deleted file mode 100644 index b056896994e..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersCyclesOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersCyclesOperation.h" - -RenderLayersCyclesOperation::RenderLayersCyclesOperation(int pass) : RenderLayersBaseProg(pass, 3) -{ - this->addOutputSocket(COM_DT_COLOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersCyclesOperation.h b/source/blender/compositor/operations/COM_RenderLayersCyclesOperation.h deleted file mode 100644 index baa53c7388b..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersCyclesOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersCyclesOperation_h -#define _COM_RenderLayersCyclesOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersCyclesOperation : public RenderLayersBaseProg { -public: - RenderLayersCyclesOperation(int pass); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersDepthProg.cpp b/source/blender/compositor/operations/COM_RenderLayersDepthProg.cpp deleted file mode 100644 index ae5fc3b2254..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersDepthProg.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersDepthProg.h" - -RenderLayersDepthProg::RenderLayersDepthProg() : RenderLayersBaseProg(SCE_PASS_Z, 1) -{ - this->addOutputSocket(COM_DT_VALUE); -} - diff --git a/source/blender/compositor/operations/COM_RenderLayersDepthProg.h b/source/blender/compositor/operations/COM_RenderLayersDepthProg.h deleted file mode 100644 index fdbe25c818e..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersDepthProg.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersDepthProg_h -#define _COM_RenderLayersDepthProg_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersDepthProg : public RenderLayersBaseProg { -public: - RenderLayersDepthProg(); - -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersDiffuseOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersDiffuseOperation.cpp deleted file mode 100644 index 6baa25e5600..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersDiffuseOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersDiffuseOperation.h" - -RenderLayersDiffuseOperation::RenderLayersDiffuseOperation() : RenderLayersBaseProg(SCE_PASS_DIFFUSE, 3) -{ - this->addOutputSocket(COM_DT_COLOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersDiffuseOperation.h b/source/blender/compositor/operations/COM_RenderLayersDiffuseOperation.h deleted file mode 100644 index 8c20d6f497d..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersDiffuseOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersDiffuseOperation_h -#define _COM_RenderLayersDiffuseOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersDiffuseOperation : public RenderLayersBaseProg { -public: - RenderLayersDiffuseOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersEmitOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersEmitOperation.cpp deleted file mode 100644 index 1b03a4e169f..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersEmitOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersEmitOperation.h" - -RenderLayersEmitOperation::RenderLayersEmitOperation() : RenderLayersBaseProg(SCE_PASS_EMIT, 3) -{ - this->addOutputSocket(COM_DT_COLOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersEmitOperation.h b/source/blender/compositor/operations/COM_RenderLayersEmitOperation.h deleted file mode 100644 index c003cb2f87b..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersEmitOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersEmitOperation_h -#define _COM_RenderLayersEmitOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersEmitOperation : public RenderLayersBaseProg { -public: - RenderLayersEmitOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersEnvironmentOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersEnvironmentOperation.cpp deleted file mode 100644 index f4d6dc7353b..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersEnvironmentOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersEnvironmentOperation.h" - -RenderLayersEnvironmentOperation::RenderLayersEnvironmentOperation() : RenderLayersBaseProg(SCE_PASS_ENVIRONMENT, 3) -{ - this->addOutputSocket(COM_DT_COLOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersEnvironmentOperation.h b/source/blender/compositor/operations/COM_RenderLayersEnvironmentOperation.h deleted file mode 100644 index b9310a1778b..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersEnvironmentOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersEnvironmentOperation_h -#define _COM_RenderLayersEnvironmentOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersEnvironmentOperation : public RenderLayersBaseProg { -public: - RenderLayersEnvironmentOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersImageProg.cpp b/source/blender/compositor/operations/COM_RenderLayersImageProg.cpp deleted file mode 100644 index f21585844ff..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersImageProg.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersImageProg.h" - -RenderLayersColorProg::RenderLayersColorProg() : RenderLayersBaseProg(SCE_PASS_COMBINED, 4) -{ - this->addOutputSocket(COM_DT_COLOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersImageProg.h b/source/blender/compositor/operations/COM_RenderLayersImageProg.h deleted file mode 100644 index 5fa74c8b21f..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersImageProg.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersColorProg_h -#define _COM_RenderLayersColorProg_h - -#include "COM_RenderLayersBaseProg.h" - -/// @todo rename to image operation -class RenderLayersColorProg : public RenderLayersBaseProg { -public: - RenderLayersColorProg(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersIndirectOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersIndirectOperation.cpp deleted file mode 100644 index 4258cb94a26..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersIndirectOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersIndirectOperation.h" - -RenderLayersIndirectOperation::RenderLayersIndirectOperation() : RenderLayersBaseProg(SCE_PASS_INDIRECT, 3) -{ - this->addOutputSocket(COM_DT_COLOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersIndirectOperation.h b/source/blender/compositor/operations/COM_RenderLayersIndirectOperation.h deleted file mode 100644 index d64207a4355..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersIndirectOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersIndirectOperation_h -#define _COM_RenderLayersIndirectOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersIndirectOperation : public RenderLayersBaseProg { -public: - RenderLayersIndirectOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersMaterialIndexOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersMaterialIndexOperation.cpp deleted file mode 100644 index aab7e0089e4..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersMaterialIndexOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersMaterialIndexOperation.h" - -RenderLayersMaterialIndexOperation::RenderLayersMaterialIndexOperation() : RenderLayersBaseProg(SCE_PASS_INDEXMA, 1) -{ - this->addOutputSocket(COM_DT_VALUE); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersMaterialIndexOperation.h b/source/blender/compositor/operations/COM_RenderLayersMaterialIndexOperation.h deleted file mode 100644 index d06568f5a10..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersMaterialIndexOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersMaterialIndexOperation_h -#define _COM_RenderLayersMaterialIndexOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersMaterialIndexOperation : public RenderLayersBaseProg { -public: - RenderLayersMaterialIndexOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersMistOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersMistOperation.cpp deleted file mode 100644 index c64ddc6e9d8..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersMistOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersMistOperation.h" - -RenderLayersMistOperation::RenderLayersMistOperation() : RenderLayersBaseProg(SCE_PASS_MIST, 1) -{ - this->addOutputSocket(COM_DT_VALUE); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersNormalOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersNormalOperation.cpp deleted file mode 100644 index 9d8e7d6272c..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersNormalOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersNormalOperation.h" - -RenderLayersNormalOperation::RenderLayersNormalOperation() : RenderLayersBaseProg(SCE_PASS_NORMAL, 3) -{ - this->addOutputSocket(COM_DT_VECTOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersNormalOperation.h b/source/blender/compositor/operations/COM_RenderLayersNormalOperation.h deleted file mode 100644 index 39b2040863a..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersNormalOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersNormalOperation_h -#define _COM_RenderLayersNormalOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersNormalOperation : public RenderLayersBaseProg { -public: - RenderLayersNormalOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersObjectIndexOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersObjectIndexOperation.cpp deleted file mode 100644 index 430ea698263..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersObjectIndexOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersObjectIndexOperation.h" - -RenderLayersObjectIndexOperation::RenderLayersObjectIndexOperation() : RenderLayersBaseProg(SCE_PASS_INDEXOB, 1) -{ - this->addOutputSocket(COM_DT_VALUE); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersObjectIndexOperation.h b/source/blender/compositor/operations/COM_RenderLayersObjectIndexOperation.h deleted file mode 100644 index e8a1602cbfc..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersObjectIndexOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersObjectIndexOperation_h -#define _COM_RenderLayersObjectIndexOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersObjectIndexOperation : public RenderLayersBaseProg { -public: - RenderLayersObjectIndexOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp new file mode 100644 index 00000000000..ea6ad86d92c --- /dev/null +++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp @@ -0,0 +1,361 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + */ + +#include "COM_RenderLayersProg.h" + +#include "BLI_listbase.h" +#include "DNA_scene_types.h" + +extern "C" { + #include "RE_pipeline.h" + #include "RE_shader_ext.h" + #include "RE_render_ext.h" +} + +/* ******** Render Layers Base Prog ******** */ + +RenderLayersBaseProg::RenderLayersBaseProg(int renderpass, int elementsize) : NodeOperation() +{ + this->m_renderpass = renderpass; + this->setScene(NULL); + this->m_inputBuffer = NULL; + this->m_elementsize = elementsize; + this->m_rd = NULL; +} + + +void RenderLayersBaseProg::initExecution() +{ + Scene *scene = this->getScene(); + Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL; + RenderResult *rr = NULL; + + if (re) + rr = RE_AcquireResultRead(re); + + if (rr) { + SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, getLayerId()); + if (srl) { + + RenderLayer *rl = RE_GetRenderLayer(rr, srl->name); + if (rl && rl->rectf) { + this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_renderpass); + + if (this->m_inputBuffer == NULL || this->m_renderpass == SCE_PASS_COMBINED) { + this->m_inputBuffer = rl->rectf; + } + } + } + } + if (re) { + RE_ReleaseResult(re); + re = NULL; + } +} + +void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, PixelSampler sampler) +{ + unsigned int offset; + int ix, iy; + int width = this->getWidth(), height = this->getHeight(); + + switch (sampler) { + case COM_PS_NEAREST: + ix = x; + iy = y; + offset = (iy * width + ix) * this->m_elementsize; + + if (this->m_elementsize == 1) + output[0] = this->m_inputBuffer[offset]; + else if (this->m_elementsize == 3) + copy_v3_v3(output, &this->m_inputBuffer[offset]); + else + copy_v4_v4(output, &this->m_inputBuffer[offset]); + + break; + + case COM_PS_BILINEAR: + BLI_bilinear_interpolation_fl(this->m_inputBuffer, output, width, height, this->m_elementsize, x, y); + break; + + case COM_PS_BICUBIC: + BLI_bicubic_interpolation_fl(this->m_inputBuffer, output, width, height, this->m_elementsize, x, y); + break; + } + + if (this->m_elementsize == 1) { + output[1] = 0.0f; + output[2] = 0.0f; + output[3] = 0.0f; + } + else if (this->m_elementsize == 3) { + output[3] = 1.0f; + } +} + +void RenderLayersBaseProg::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ +#if 0 + const RenderData *rd = this->m_rd; + + int dx = 0, dy = 0; + + if (rd->mode & R_BORDER && rd->mode & R_CROP) { + /* see comment in executeRegion describing coordinate mapping, + * here it simply goes other way around + */ + int full_width = rd->xsch * rd->size / 100; + int full_height = rd->ysch * rd->size / 100; + + dx = rd->border.xmin * full_width - (full_width - this->getWidth()) / 2.0f; + dy = rd->border.ymin * full_height - (full_height - this->getHeight()) / 2.0f; + } + + int ix = x - dx; + int iy = y - dy; +#else + int ix = x; + int iy = y; +#endif + + if (this->m_inputBuffer == NULL || ix < 0 || iy < 0 || ix >= (int)this->getWidth() || iy >= (int)this->getHeight() ) { + zero_v4(output); + } + else { + doInterpolation(output, ix, iy, sampler); + } +} + +void RenderLayersBaseProg::deinitExecution() +{ + this->m_inputBuffer = NULL; +} + +void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) +{ + Scene *sce = this->getScene(); + Render *re = (sce) ? RE_GetRender(sce->id.name) : NULL; + RenderResult *rr = NULL; + + resolution[0] = 0; + resolution[1] = 0; + + if (re) + rr = RE_AcquireResultRead(re); + + if (rr) { + SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&sce->r.layers, getLayerId()); + if (srl) { + RenderLayer *rl = RE_GetRenderLayer(rr, srl->name); + if (rl && rl->rectf) { + resolution[0] = rl->rectx; + resolution[1] = rl->recty; + } + } + } + + if (re) + RE_ReleaseResult(re); + +} + +/* ******** Render Layers AO Operation ******** */ + +RenderLayersAOOperation::RenderLayersAOOperation() : RenderLayersBaseProg(SCE_PASS_AO, 3) +{ + this->addOutputSocket(COM_DT_COLOR); +} + +/* ******** Render Layers Alpha Operation ******** */ + +RenderLayersAlphaProg::RenderLayersAlphaProg() : RenderLayersBaseProg(SCE_PASS_COMBINED, 4) +{ + this->addOutputSocket(COM_DT_VALUE); +} + +void RenderLayersAlphaProg::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + int ix = x; + int iy = y; + float *inputBuffer = this->getInputBuffer(); + + if (inputBuffer == NULL || ix < 0 || iy < 0 || ix >= (int)this->getWidth() || iy >= (int)this->getHeight() ) { + output[0] = 0.0f; + output[1] = 0.0f; + output[2] = 0.0f; + output[3] = 0.0f; + } + else { + unsigned int offset = (iy * this->getWidth() + ix) * 4; + output[0] = inputBuffer[offset + 3]; + output[1] = 0.0f; + output[2] = 0.0f; + output[3] = 0.0f; + } +} + +/* ******** Render Layers Color Operation ******** */ + +RenderLayersColorOperation::RenderLayersColorOperation() : RenderLayersBaseProg(SCE_PASS_RGBA, 4) +{ + this->addOutputSocket(COM_DT_COLOR); +} + +/* ******** Render Layers Cycles Operation ******** */ + +RenderLayersCyclesOperation::RenderLayersCyclesOperation(int pass) : RenderLayersBaseProg(pass, 3) +{ + this->addOutputSocket(COM_DT_COLOR); +} + +/* ******** Render Layers Depth Operation ******** */ + +RenderLayersDepthProg::RenderLayersDepthProg() : RenderLayersBaseProg(SCE_PASS_Z, 1) +{ + this->addOutputSocket(COM_DT_VALUE); +} + +void RenderLayersDepthProg::executePixel(float output[4], float x, float y, PixelSampler sampler) +{ + int ix = x; + int iy = y; + float *inputBuffer = this->getInputBuffer(); + + if (inputBuffer == NULL || ix < 0 || iy < 0 || ix >= (int)this->getWidth() || iy >= (int)this->getHeight() ) { + output[0] = 0.0f; + output[1] = 0.0f; + output[2] = 0.0f; + output[3] = 0.0f; + } + else { + unsigned int offset = (iy * this->getWidth() + ix); + output[0] = inputBuffer[offset]; + output[1] = 0.0f; + output[2] = 0.0f; + output[3] = 0.0f; + } +} + +/* ******** Render Layers Diffuse Operation ******** */ + +RenderLayersDiffuseOperation::RenderLayersDiffuseOperation() : RenderLayersBaseProg(SCE_PASS_DIFFUSE, 3) +{ + this->addOutputSocket(COM_DT_COLOR); +} + +/* ******** Render Layers Emit Operation ******** */ + +RenderLayersEmitOperation::RenderLayersEmitOperation() : RenderLayersBaseProg(SCE_PASS_EMIT, 3) +{ + this->addOutputSocket(COM_DT_COLOR); +} + +/* ******** Render Layers Environment Operation ******** */ + +RenderLayersEnvironmentOperation::RenderLayersEnvironmentOperation() : RenderLayersBaseProg(SCE_PASS_ENVIRONMENT, 3) +{ + this->addOutputSocket(COM_DT_COLOR); +} + +/* ******** Render Layers Image Operation ******** */ + +RenderLayersColorProg::RenderLayersColorProg() : RenderLayersBaseProg(SCE_PASS_COMBINED, 4) +{ + this->addOutputSocket(COM_DT_COLOR); +} + +/* ******** Render Layers Indirect Operation ******** */ + +RenderLayersIndirectOperation::RenderLayersIndirectOperation() : RenderLayersBaseProg(SCE_PASS_INDIRECT, 3) +{ + this->addOutputSocket(COM_DT_COLOR); +} + +/* ******** Render Layers Material Index Operation ******** */ + +RenderLayersMaterialIndexOperation::RenderLayersMaterialIndexOperation() : RenderLayersBaseProg(SCE_PASS_INDEXMA, 1) +{ + this->addOutputSocket(COM_DT_VALUE); +} + +/* ******** Render Layers Mist Operation ******** */ + +RenderLayersMistOperation::RenderLayersMistOperation() : RenderLayersBaseProg(SCE_PASS_MIST, 1) +{ + this->addOutputSocket(COM_DT_VALUE); +} + +/* ******** Render Layers Normal Operation ******** */ + +RenderLayersNormalOperation::RenderLayersNormalOperation() : RenderLayersBaseProg(SCE_PASS_NORMAL, 3) +{ + this->addOutputSocket(COM_DT_VECTOR); +} + +/* ******** Render Layers Object Index Operation ******** */ + +RenderLayersObjectIndexOperation::RenderLayersObjectIndexOperation() : RenderLayersBaseProg(SCE_PASS_INDEXOB, 1) +{ + this->addOutputSocket(COM_DT_VALUE); +} + +/* ******** Render Layers Reflection Operation ******** */ + +RenderLayersReflectionOperation::RenderLayersReflectionOperation() : RenderLayersBaseProg(SCE_PASS_REFLECT, 3) +{ + this->addOutputSocket(COM_DT_COLOR); +} + +/* ******** Render Layers Refraction Operation ******** */ + +RenderLayersRefractionOperation::RenderLayersRefractionOperation() : RenderLayersBaseProg(SCE_PASS_REFRACT, 3) +{ + this->addOutputSocket(COM_DT_COLOR); +} + +/* ******** Render Layers Shadow Operation ******** */ + +RenderLayersShadowOperation::RenderLayersShadowOperation() : RenderLayersBaseProg(SCE_PASS_SHADOW, 3) +{ + this->addOutputSocket(COM_DT_COLOR); +} + +/* ******** Render Layers Specular Operation ******** */ + +RenderLayersSpecularOperation::RenderLayersSpecularOperation() : RenderLayersBaseProg(SCE_PASS_SPEC, 3) +{ + this->addOutputSocket(COM_DT_COLOR); +} + +/* ******** Render Layers Speed Operation ******** */ + +RenderLayersSpeedOperation::RenderLayersSpeedOperation() : RenderLayersBaseProg(SCE_PASS_VECTOR, 4) +{ + this->addOutputSocket(COM_DT_COLOR); +} + +/* ******** Render Layers UV Operation ******** */ + +RenderLayersUVOperation::RenderLayersUVOperation() : RenderLayersBaseProg(SCE_PASS_UV, 3) +{ + this->addOutputSocket(COM_DT_VECTOR); +} diff --git a/source/blender/compositor/operations/COM_RenderLayersBaseProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h index 84d6c1ee188..04861174387 100644 --- a/source/blender/compositor/operations/COM_RenderLayersBaseProg.h +++ b/source/blender/compositor/operations/COM_RenderLayersProg.h @@ -102,4 +102,107 @@ public: void executePixel(float output[4], float x, float y, PixelSampler sampler); }; +class RenderLayersAOOperation : public RenderLayersBaseProg { +public: + RenderLayersAOOperation(); +}; + +class RenderLayersAlphaProg : public RenderLayersBaseProg { +public: + RenderLayersAlphaProg(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class RenderLayersColorOperation : public RenderLayersBaseProg { +public: + RenderLayersColorOperation(); +}; + +class RenderLayersCyclesOperation : public RenderLayersBaseProg { +public: + RenderLayersCyclesOperation(int pass); +}; + +class RenderLayersDepthProg : public RenderLayersBaseProg { +public: + RenderLayersDepthProg(); + void executePixel(float output[4], float x, float y, PixelSampler sampler); +}; + +class RenderLayersDiffuseOperation : public RenderLayersBaseProg { +public: + RenderLayersDiffuseOperation(); +}; + +class RenderLayersEmitOperation : public RenderLayersBaseProg { +public: + RenderLayersEmitOperation(); +}; + +class RenderLayersEnvironmentOperation : public RenderLayersBaseProg { +public: + RenderLayersEnvironmentOperation(); +}; + +/// @todo rename to image operation +class RenderLayersColorProg : public RenderLayersBaseProg { +public: + RenderLayersColorProg(); +}; + +class RenderLayersIndirectOperation : public RenderLayersBaseProg { +public: + RenderLayersIndirectOperation(); +}; + +class RenderLayersMaterialIndexOperation : public RenderLayersBaseProg { +public: + RenderLayersMaterialIndexOperation(); +}; + +class RenderLayersMistOperation : public RenderLayersBaseProg { +public: + RenderLayersMistOperation(); +}; + +class RenderLayersNormalOperation : public RenderLayersBaseProg { +public: + RenderLayersNormalOperation(); +}; + +class RenderLayersObjectIndexOperation : public RenderLayersBaseProg { +public: + RenderLayersObjectIndexOperation(); +}; + +class RenderLayersReflectionOperation : public RenderLayersBaseProg { +public: + RenderLayersReflectionOperation(); +}; + +class RenderLayersRefractionOperation : public RenderLayersBaseProg { +public: + RenderLayersRefractionOperation(); +}; + +class RenderLayersShadowOperation : public RenderLayersBaseProg { +public: + RenderLayersShadowOperation(); +}; + +class RenderLayersSpecularOperation : public RenderLayersBaseProg { +public: + RenderLayersSpecularOperation(); +}; + +class RenderLayersSpeedOperation : public RenderLayersBaseProg { +public: + RenderLayersSpeedOperation(); +}; + +class RenderLayersUVOperation : public RenderLayersBaseProg { +public: + RenderLayersUVOperation(); +}; + #endif diff --git a/source/blender/compositor/operations/COM_RenderLayersReflectionOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersReflectionOperation.cpp deleted file mode 100644 index 1fbd599235b..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersReflectionOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersReflectionOperation.h" - -RenderLayersReflectionOperation::RenderLayersReflectionOperation() : RenderLayersBaseProg(SCE_PASS_REFLECT, 3) -{ - this->addOutputSocket(COM_DT_COLOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersReflectionOperation.h b/source/blender/compositor/operations/COM_RenderLayersReflectionOperation.h deleted file mode 100644 index 3dc7148930b..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersReflectionOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersReflectionOperation_h -#define _COM_RenderLayersReflectionOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersReflectionOperation : public RenderLayersBaseProg { -public: - RenderLayersReflectionOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersRefractionOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersRefractionOperation.cpp deleted file mode 100644 index 2ec9be46059..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersRefractionOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersRefractionOperation.h" - -RenderLayersRefractionOperation::RenderLayersRefractionOperation() : RenderLayersBaseProg(SCE_PASS_REFRACT, 3) -{ - this->addOutputSocket(COM_DT_COLOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersRefractionOperation.h b/source/blender/compositor/operations/COM_RenderLayersRefractionOperation.h deleted file mode 100644 index 02ac7aa14f4..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersRefractionOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersRefractionOperation_h -#define _COM_RenderLayersRefractionOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersRefractionOperation : public RenderLayersBaseProg { -public: - RenderLayersRefractionOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersShadowOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersShadowOperation.cpp deleted file mode 100644 index 7582e010e2c..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersShadowOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersShadowOperation.h" - -RenderLayersShadowOperation::RenderLayersShadowOperation() : RenderLayersBaseProg(SCE_PASS_SHADOW, 3) -{ - this->addOutputSocket(COM_DT_COLOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersShadowOperation.h b/source/blender/compositor/operations/COM_RenderLayersShadowOperation.h deleted file mode 100644 index af35915c2ee..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersShadowOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersShadowOperation_h -#define _COM_RenderLayersShadowOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersShadowOperation : public RenderLayersBaseProg { -public: - RenderLayersShadowOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersSpecularOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersSpecularOperation.cpp deleted file mode 100644 index 60c1636dcda..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersSpecularOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersSpecularOperation.h" - -RenderLayersSpecularOperation::RenderLayersSpecularOperation() : RenderLayersBaseProg(SCE_PASS_SPEC, 3) -{ - this->addOutputSocket(COM_DT_COLOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersSpecularOperation.h b/source/blender/compositor/operations/COM_RenderLayersSpecularOperation.h deleted file mode 100644 index fc7d77976a3..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersSpecularOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersSpecularOperation_h -#define _COM_RenderLayersSpecularOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersSpecularOperation : public RenderLayersBaseProg { -public: - RenderLayersSpecularOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersSpeedOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersSpeedOperation.cpp deleted file mode 100644 index 5a0662d13eb..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersSpeedOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersSpeedOperation.h" - -RenderLayersSpeedOperation::RenderLayersSpeedOperation() : RenderLayersBaseProg(SCE_PASS_VECTOR, 4) -{ - this->addOutputSocket(COM_DT_COLOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersSpeedOperation.h b/source/blender/compositor/operations/COM_RenderLayersSpeedOperation.h deleted file mode 100644 index d341aa43950..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersSpeedOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersSpeedOperation_h -#define _COM_RenderLayersSpeedOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersSpeedOperation : public RenderLayersBaseProg { -public: - RenderLayersSpeedOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_RenderLayersUVOperation.cpp b/source/blender/compositor/operations/COM_RenderLayersUVOperation.cpp deleted file mode 100644 index b966f98632c..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersUVOperation.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_RenderLayersUVOperation.h" - -RenderLayersUVOperation::RenderLayersUVOperation() : RenderLayersBaseProg(SCE_PASS_UV, 3) -{ - this->addOutputSocket(COM_DT_VECTOR); -} diff --git a/source/blender/compositor/operations/COM_RenderLayersUVOperation.h b/source/blender/compositor/operations/COM_RenderLayersUVOperation.h deleted file mode 100644 index 3068372a66c..00000000000 --- a/source/blender/compositor/operations/COM_RenderLayersUVOperation.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#ifndef _COM_RenderLayersUVOperation_h -#define _COM_RenderLayersUVOperation_h - -#include "COM_RenderLayersBaseProg.h" - -class RenderLayersUVOperation : public RenderLayersBaseProg { -public: - RenderLayersUVOperation(); -}; - -#endif diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp index fb996f2abaf..d1060224444 100644 --- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp +++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp @@ -103,7 +103,7 @@ void ScreenLensDistortionOperation::executePixel(float output[4], int x, int y, d = 1.0f / (1.0f + sqrtf(t)); const float nx = (u * d + 0.5f) * width - 0.5f; const float ny = (v * d + 0.5f) * height - 0.5f; - buffer->readCubic(color, nx, ny); + buffer->readBilinear(color, nx, ny); tc[0] += (1.0f - tz) * color[0], tc[1] += tz * color[1]; dr++, dg++; } @@ -121,7 +121,7 @@ void ScreenLensDistortionOperation::executePixel(float output[4], int x, int y, d = 1.0f / (1.0f + sqrtf(t)); const float nx = (u * d + 0.5f) * width - 0.5f; const float ny = (v * d + 0.5f) * height - 0.5f; - buffer->readCubic(color, nx, ny); + buffer->readBilinear(color, nx, ny); tc[1] += (1.0f - tz) * color[1], tc[2] += tz * color[2]; dg++, db++; } diff --git a/source/blender/compositor/operations/COM_SeparateChannelOperation.cpp b/source/blender/compositor/operations/COM_SeparateChannelOperation.cpp deleted file mode 100644 index 9fc266cce86..00000000000 --- a/source/blender/compositor/operations/COM_SeparateChannelOperation.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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. - * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand - */ - -#include "COM_SeparateChannelOperation.h" - -SeparateChannelOperation::SeparateChannelOperation() : NodeOperation() -{ - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_VALUE); - this->m_inputOperation = NULL; -} -void SeparateChannelOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void SeparateChannelOperation::deinitExecution() -{ - this->m_inputOperation = NULL; -} - - -void SeparateChannelOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) -{ - float input[4]; - this->m_inputOperation->read(input, x, y, sampler); - output[0] = input[this->m_channel]; -} diff --git a/source/blender/compositor/operations/COM_SetColorOperation.h b/source/blender/compositor/operations/COM_SetColorOperation.h index 7895c34620b..8377decdd7b 100644 --- a/source/blender/compositor/operations/COM_SetColorOperation.h +++ b/source/blender/compositor/operations/COM_SetColorOperation.h @@ -58,7 +58,7 @@ public: void executePixel(float output[4], float x, float y, PixelSampler sampler); void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); - const bool isSetOperation() const { return true; } + bool isSetOperation() const { return true; } }; #endif diff --git a/source/blender/compositor/operations/COM_SetValueOperation.h b/source/blender/compositor/operations/COM_SetValueOperation.h index 3ddc667bc7e..b88b85d66f2 100644 --- a/source/blender/compositor/operations/COM_SetValueOperation.h +++ b/source/blender/compositor/operations/COM_SetValueOperation.h @@ -49,6 +49,6 @@ public: void executePixel(float output[4], float x, float y, PixelSampler sampler); void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); - const bool isSetOperation() const { return true; } + bool isSetOperation() const { return true; } }; #endif diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.h b/source/blender/compositor/operations/COM_SetVectorOperation.h index e9d6a163e9f..d15da58e58e 100644 --- a/source/blender/compositor/operations/COM_SetVectorOperation.h +++ b/source/blender/compositor/operations/COM_SetVectorOperation.h @@ -57,7 +57,7 @@ public: void executePixel(float output[4], float x, float y, PixelSampler sampler); void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); - const bool isSetOperation() const { return true; } + bool isSetOperation() const { return true; } void setVector(float vector[3]) { setX(vector[0]); diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.h b/source/blender/compositor/operations/COM_TrackPositionOperation.h index b5499ab76b7..7a4ce9f9213 100644 --- a/source/blender/compositor/operations/COM_TrackPositionOperation.h +++ b/source/blender/compositor/operations/COM_TrackPositionOperation.h @@ -72,7 +72,7 @@ public: void executePixel(float output[4], float x, float y, PixelSampler sampler); - const bool isSetOperation() const { return true; } + bool isSetOperation() const { return true; } }; #endif diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cpp b/source/blender/compositor/operations/COM_ViewerOperation.cpp index e9f083178e4..468aec64a56 100644 --- a/source/blender/compositor/operations/COM_ViewerOperation.cpp +++ b/source/blender/compositor/operations/COM_ViewerOperation.cpp @@ -173,7 +173,7 @@ void ViewerOperation::updateImage(rcti *rect) { IMB_partial_display_buffer_update(this->m_ibuf, this->m_outputBuffer, NULL, getWidth(), 0, 0, this->m_viewSettings, this->m_displaySettings, - rect->xmin, rect->ymin, rect->xmax, rect->ymax, FALSE); + rect->xmin, rect->ymin, rect->xmax, rect->ymax, false); this->updateDraw(); } diff --git a/source/blender/compositor/operations/COM_WrapOperation.cpp b/source/blender/compositor/operations/COM_WrapOperation.cpp index 68c3e74a237..ea19952f60c 100644 --- a/source/blender/compositor/operations/COM_WrapOperation.cpp +++ b/source/blender/compositor/operations/COM_WrapOperation.cpp @@ -23,21 +23,9 @@ #include "COM_WrapOperation.h" -WrapOperation::WrapOperation() : NodeOperation() +WrapOperation::WrapOperation() : ReadBufferOperation() { - this->addInputSocket(COM_DT_COLOR); - this->addOutputSocket(COM_DT_COLOR); - this->setResolutionInputSocketIndex(0); - this->m_inputOperation = NULL; -} -void WrapOperation::initExecution() -{ - this->m_inputOperation = this->getInputSocketReader(0); -} - -void WrapOperation::deinitExecution() -{ - this->m_inputOperation = NULL; + this->m_wrappingType = CMP_NODE_WRAP_NONE; } inline float WrapOperation::getWrappedOriginalXPos(float x) @@ -59,6 +47,7 @@ void WrapOperation::executePixel(float output[4], float x, float y, PixelSampler float nx, ny; nx = x; ny = y; + MemoryBufferExtend extend_x = COM_MB_CLIP, extend_y = COM_MB_CLIP; switch (m_wrappingType) { case CMP_NODE_WRAP_NONE: //Intentionally empty, originalXPos and originalYPos have been set before @@ -66,20 +55,23 @@ void WrapOperation::executePixel(float output[4], float x, float y, PixelSampler case CMP_NODE_WRAP_X: // wrap only on the x-axis nx = this->getWrappedOriginalXPos(x); + extend_x = COM_MB_REPEAT; break; case CMP_NODE_WRAP_Y: // wrap only on the y-axis ny = this->getWrappedOriginalYPos(y); + extend_y = COM_MB_REPEAT; break; case CMP_NODE_WRAP_XY: // wrap on both nx = this->getWrappedOriginalXPos(x); ny = this->getWrappedOriginalYPos(y); + extend_x = COM_MB_REPEAT; + extend_y = COM_MB_REPEAT; break; } - this->m_inputOperation->read(output, nx, ny, sampler); - + executePixelExtend(output, nx, ny, sampler, extend_x, extend_y); } bool WrapOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) @@ -110,7 +102,7 @@ bool WrapOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOper } } - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); + return ReadBufferOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } void WrapOperation::setWrapping(int wrapping_type) diff --git a/source/blender/compositor/operations/COM_WrapOperation.h b/source/blender/compositor/operations/COM_WrapOperation.h index b84d85e7b5d..ddd5fa8032d 100644 --- a/source/blender/compositor/operations/COM_WrapOperation.h +++ b/source/blender/compositor/operations/COM_WrapOperation.h @@ -23,20 +23,16 @@ #ifndef _COM_WrapOperation_h_ #define _COM_WrapOperation_h_ -#include "COM_NodeOperation.h" +#include "COM_ReadBufferOperation.h" -class WrapOperation : public NodeOperation { +class WrapOperation : public ReadBufferOperation { private: - SocketReader *m_inputOperation; int m_wrappingType; public: WrapOperation(); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output); void executePixel(float output[4], float x, float y, PixelSampler sampler); - void initExecution(); - void deinitExecution(); - void setWrapping(int wrapping_type); float getWrappedOriginalXPos(float x); float getWrappedOriginalYPos(float y); diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp index 17c8f4d9fd1..cf462607936 100644 --- a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp +++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp @@ -75,7 +75,6 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber) for (x = x1; x < x2; x++) { this->m_input->read(&(buffer[offset4]), x, y, data); offset4 += COM_NUMBER_OF_CHANNELS; - } if (isBreaked()) { breaked = true; @@ -174,6 +173,21 @@ void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device, rcti *rect, delete clKernelsToCleanUp; } +void WriteBufferOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) +{ + NodeOperation::determineResolution(resolution, preferredResolution); + /* make sure there is at least one pixel stored in case the input is a single value */ + m_single_value = false; + if (resolution[0] == 0) { + resolution[0] = 1; + m_single_value = true; + } + if (resolution[1] == 0) { + resolution[1] = 1; + m_single_value = true; + } +} + void WriteBufferOperation::readResolutionFromInputSocket() { NodeOperation *inputOperation = this->getInputOperation(0); diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.h b/source/blender/compositor/operations/COM_WriteBufferOperation.h index d89444045d4..157543fcb72 100644 --- a/source/blender/compositor/operations/COM_WriteBufferOperation.h +++ b/source/blender/compositor/operations/COM_WriteBufferOperation.h @@ -32,6 +32,7 @@ */ class WriteBufferOperation : public NodeOperation { MemoryProxy *m_memoryProxy; + bool m_single_value; /* single value stored in buffer */ NodeOperation *m_input; public: WriteBufferOperation(); @@ -40,11 +41,13 @@ public: MemoryProxy *getMemoryProxy() { return this->m_memoryProxy; } void executePixel(float output[4], float x, float y, PixelSampler sampler); const bool isWriteBufferOperation() const { return true; } + bool isSingleValue() const { return m_single_value; } void executeRegion(rcti *rect, unsigned int tileNumber); void initExecution(); void deinitExecution(); void executeOpenCLRegion(OpenCLDevice *device, rcti *rect, unsigned int chunkNumber, MemoryBuffer **memoryBuffers, MemoryBuffer *outputBuffer); + void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); void readResolutionFromInputSocket(); inline NodeOperation *getInput() { return m_input; diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.h b/source/blender/compositor/operations/COM_ZCombineOperation.h index 4545775f26f..eeeb29d330f 100644 --- a/source/blender/compositor/operations/COM_ZCombineOperation.h +++ b/source/blender/compositor/operations/COM_ZCombineOperation.h @@ -22,7 +22,7 @@ #ifndef _COM_ZCombineOperation_h #define _COM_ZCombineOperation_h -#include "COM_MixBaseOperation.h" +#include "COM_MixOperation.h" /** diff --git a/source/blender/datatoc/datatoc.c b/source/blender/datatoc/datatoc.c index 236d9af8ef1..4e49a9a7694 100644 --- a/source/blender/datatoc/datatoc.c +++ b/source/blender/datatoc/datatoc.c @@ -25,6 +25,10 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/datatoc/datatoc.c + * \ingroup datatoc + */ + #include <stdio.h> #include <string.h> #include <stdlib.h> diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 845ad72d7aa..142342997be 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -1828,7 +1828,7 @@ static void *acf_dsmball_setting_ptr(bAnimListElem *ale, int setting, short *typ switch (setting) { case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(mb->flag, type); + return GET_ACF_FLAG_PTR(mb->flag2, type); case ACHANNEL_SETTING_SELECT: /* selected */ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ @@ -2781,6 +2781,9 @@ static void ANIM_init_channel_typeinfo_data(void) if (ACF_INIT) { ACF_INIT = 0; + /* NOTE: need to keep the order of these synchronized with the definition of + * channel types (eAnim_ChannelType) in ED_anim_api.h + */ animchannelTypeInfo[type++] = NULL; /* None */ animchannelTypeInfo[type++] = NULL; /* AnimData */ animchannelTypeInfo[type++] = NULL; /* Special */ @@ -2808,8 +2811,8 @@ static void ANIM_init_channel_typeinfo_data(void) animchannelTypeInfo[type++] = &ACF_DSMESH; /* Mesh Channel */ animchannelTypeInfo[type++] = &ACF_DSTEX; /* Texture Channel */ animchannelTypeInfo[type++] = &ACF_DSLAT; /* Lattice Channel */ - animchannelTypeInfo[type++] = &ACF_DSSPK; /* Speaker Channel */ animchannelTypeInfo[type++] = &ACF_DSLINESTYLE; /* LineStyle Channel */ + animchannelTypeInfo[type++] = &ACF_DSSPK; /* Speaker Channel */ animchannelTypeInfo[type++] = &ACF_SHAPEKEY; /* ShapeKey */ diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 91003674524..09b6e7d2206 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -1541,10 +1541,18 @@ static size_t animdata_filter_ds_nodetree(bAnimContext *ac, ListBase *anim_data, static size_t animdata_filter_ds_linestyle(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode) { SceneRenderLayer *srl; + FreestyleLineSet *lineset; size_t items = 0; for (srl = sce->r.layers.first; srl; srl = srl->next) { - FreestyleLineSet *lineset; + for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { + if (lineset->linestyle) { + lineset->linestyle->id.flag |= LIB_DOIT; + } + } + } + + for (srl = sce->r.layers.first; srl; srl = srl->next) { /* skip render layers without Freestyle enabled */ if (!(srl->layflag & SCE_LAY_FRS)) @@ -1555,6 +1563,13 @@ static size_t animdata_filter_ds_linestyle(bAnimContext *ac, ListBase *anim_data FreestyleLineStyle *linestyle = lineset->linestyle; ListBase tmp_data = {NULL, NULL}; size_t tmp_items = 0; + + if ((linestyle == NULL) || + !(linestyle->id.flag & LIB_DOIT)) + { + continue; + } + linestyle->id.flag &= ~LIB_DOIT; /* add scene-level animation channels */ BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_LS_SCED(linestyle)) @@ -2533,13 +2548,13 @@ static size_t animdata_filter_remove_invalid(ListBase *anim_data) static size_t animdata_filter_remove_duplis(ListBase *anim_data) { bAnimListElem *ale, *next; - GHash *gh; + GSet *gs; size_t items = 0; /* build new hashtable to efficiently store and retrieve which entries have been * encountered already while searching */ - gh = BLI_ghash_ptr_new("animdata_filter_duplis_remove gh"); + gs = BLI_gset_ptr_new(__func__); /* loop through items, removing them from the list if a similar item occurs already */ for (ale = anim_data->first; ale; ale = next) { @@ -2549,9 +2564,8 @@ static size_t animdata_filter_remove_duplis(ListBase *anim_data) * - just use ale->data for now, though it would be nicer to involve * ale->type in combination too to capture corner cases (where same data performs differently) */ - if (BLI_ghash_haskey(gh, ale->data) == 0) { + if (BLI_gset_reinsert(gs, ale->data, NULL)) { /* this entry is 'unique' and can be kept */ - BLI_ghash_insert(gh, ale->data, NULL); items++; } else { @@ -2561,7 +2575,7 @@ static size_t animdata_filter_remove_duplis(ListBase *anim_data) } /* free the hash... */ - BLI_ghash_free(gh, NULL, NULL); + BLI_gset_free(gs, NULL); /* return the number of items still in the list */ return items; diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index 21941c7ed62..d3e6d8f474f 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -132,7 +132,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) propname = RNA_property_ui_name(prop); /* Array Index - only if applicable */ - if (RNA_property_array_length(&ptr, prop)) { + if (RNA_property_array_check(prop)) { char c = RNA_property_array_item_char(prop, fcu->array_index); /* we need to write the index to a temp buffer (in py syntax) */ diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index df93da8b7c1..826e204d981 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -75,7 +75,8 @@ void free_anim_drivers_copybuf(void); * for the given Animation Data block. This assumes that all the destinations are valid. * * - add: 0 - don't add anything if not found, - * 1 - add new Driver FCurve, + * 1 - add new Driver FCurve (with keyframes for visual tweaking), + * 2 - add new Driver FCurve (with generator, for script backwards compatability) * -1 - add new Driver FCurve without driver stuff (for pasting) */ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_index, short add) @@ -114,11 +115,38 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde /* if add is negative, don't init this data yet, since it will be filled in by the pasted driver */ if (add > 0) { + BezTriple *bezt; + size_t i; + /* add some new driver data */ fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver"); + fcu->driver->flag |= DRIVER_FLAG_SHOWDEBUG; - /* add simple generator modifier for driver so that there is some visible representation */ - add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR); + /* F-Modifier or Keyframes? */ + // FIXME: replace these magic numbers with defines + if (add == 2) { + /* Python API Backwards compatability hack: + * Create FModifier so that old scripts won't break + * for now before 2.7 series -- (September 4, 2013) + */ + add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR); + } + else { + /* add 2 keyframes so that user has something to work with + * - These are configured to 0,0 and 1,1 to give a 1-1 mapping + * which can be easily tweaked from there. + */ + insert_vert_fcurve(fcu, 0.0f, 0.0f, INSERTKEY_FAST); + insert_vert_fcurve(fcu, 1.0f, 1.0f, INSERTKEY_FAST); + + /* configure this curve to extrapolate */ + for (i = 0, bezt = fcu->bezt; (i < fcu->totvert) && bezt; i++, bezt++) { + bezt->h1 = bezt->h2 = HD_VECT; + } + + fcu->extend = FCURVE_EXTRAPOLATE_LINEAR; + calchandles_fcurve(fcu); + } } /* just add F-Curve to end of driver list */ @@ -166,8 +194,10 @@ short ANIM_add_driver(ReportList *reports, ID *id, const char rna_path[], int ar /* will only loop once unless the array index was -1 */ for (; array_index < array_index_max; array_index++) { + short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1; + /* create F-Curve with Driver */ - fcu = verify_driver_fcurve(id, rna_path, array_index, 1); + fcu = verify_driver_fcurve(id, rna_path, array_index, add_mode); if (fcu && fcu->driver) { ChannelDriver *driver = fcu->driver; diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index decbc351cad..71717284d8e 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -396,7 +396,7 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac) int filter; /* when not in graph view, don't use handles */ SpaceIpo *sipo = (ac->spacetype == SPACE_IPO) ? (SpaceIpo *)ac->sl : NULL; - const short use_handle = sipo ? !(sipo->flag & SIPO_NOHANDLES) : FALSE; + const bool use_handle = sipo ? !(sipo->flag & SIPO_NOHANDLES) : false; /* filter animation data */ filter = ANIMFILTER_DATA_VISIBLE; diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 63acc5a943c..6b9200afb75 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -61,6 +61,7 @@ #include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_main.h" +#include "BKE_idcode.h" #include "BKE_nla.h" #include "BKE_global.h" #include "BKE_context.h" @@ -141,9 +142,18 @@ bAction *verify_adt_action(ID *id, short add) /* init action if none available yet */ /* TODO: need some wizardry to handle NLA stuff correct */ if ((adt->action == NULL) && (add)) { + /* init action name from name of ID block */ char actname[sizeof(id->name) - 2]; BLI_snprintf(actname, sizeof(actname), "%sAction", id->name + 2); + + /* create action */ adt->action = add_empty_action(G.main, actname); + + /* set ID-type from ID-block that this is going to be assigned to + * so that users can't accidentally break actions by assigning them + * to the wrong places + */ + adt->action->idroot = GS(id->name); } /* return the action */ @@ -256,7 +266,7 @@ int insert_bezt_fcurve(FCurve *fcu, BezTriple *bezt, short flag) dst->f1 = bezt->f1; dst->f2 = bezt->f2; dst->f3 = bezt->f3; - + /* TODO: perform some other operations? */ } } @@ -508,19 +518,19 @@ static float setting_get_rna_value(PointerRNA *ptr, PropertyRNA *prop, int index switch (RNA_property_type(prop)) { case PROP_BOOLEAN: - if (RNA_property_array_length(ptr, prop)) + if (RNA_property_array_check(prop)) value = (float)RNA_property_boolean_get_index(ptr, prop, index); else value = (float)RNA_property_boolean_get(ptr, prop); break; case PROP_INT: - if (RNA_property_array_length(ptr, prop)) + if (RNA_property_array_check(prop)) value = (float)RNA_property_int_get_index(ptr, prop, index); else value = (float)RNA_property_int_get(ptr, prop); break; case PROP_FLOAT: - if (RNA_property_array_length(ptr, prop)) + if (RNA_property_array_check(prop)) value = RNA_property_float_get_index(ptr, prop, index); else value = RNA_property_float_get(ptr, prop); @@ -996,6 +1006,34 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou * The flag argument is used for special settings that alter the behavior of * the keyframe deletion. These include the quick refresh options. */ + + + +/** + * \note caller needs to run #BKE_nla_tweakedit_remap to get NLA relative frame. + * caller should also check #BKE_fcurve_is_protected before keying. + */ +static bool delete_keyframe_fcurve(AnimData *adt, FCurve *fcu, float cfra) +{ + bool found; + int i; + + /* try to find index of beztriple to get rid of */ + i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); + if (found) { + /* delete the key at the index (will sanity check + do recalc afterwards) */ + delete_fcurve_key(fcu, i, 1); + + /* Only delete curve too if it won't be doing anything anymore */ + if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) + ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); + + /* return success */ + return true; + } + return false; +} + short delete_keyframe(ReportList *reports, ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short UNUSED(flag)) { AnimData *adt = BKE_animdata_from_id(id); @@ -1055,32 +1093,20 @@ short delete_keyframe(ReportList *reports, ID *id, bAction *act, const char grou /* will only loop once unless the array index was -1 */ for (; array_index < array_index_max; array_index++) { FCurve *fcu = verify_fcurve(act, group, &ptr, rna_path, array_index, 0); - bool found; - int i; - + /* check if F-Curve exists and/or whether it can be edited */ if (fcu == NULL) continue; - - if ( (fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ) { - if (G.debug & G_DEBUG) - printf("WARNING: not deleting keyframe for locked F-Curve\n"); + + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf(reports, RPT_WARNING, + "not deleting keyframe for locked F-Curve '%s' for %s '%s'", + fcu->rna_path, BKE_idcode_to_name(GS(id->name)), id->name + 2); continue; } - - /* try to find index of beztriple to get rid of */ - i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); - if (found) { - /* delete the key at the index (will sanity check + do recalc afterwards) */ - delete_fcurve_key(fcu, i, 1); - - /* Only delete curve too if it won't be doing anything anymore */ - if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) - ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); - - /* return success */ - ret++; - } + + ret += delete_keyframe_fcurve(adt, fcu, cfra); + } /* return success/failure */ @@ -1158,7 +1184,7 @@ static short clear_keyframe(ReportList *reports, ID *id, bAction *act, const cha if (fcu == NULL) continue; - if ( (fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ) { + if (BKE_fcurve_is_protected(fcu)) { if (G.debug & G_DEBUG) printf("WARNING: not deleting keyframe for locked F-Curve\n"); continue; @@ -1537,14 +1563,22 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op) AnimData *adt = ob->adt; bAction *act = adt->action; FCurve *fcu, *fcn; + const float cfra_unmap = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); for (fcu = act->curves.first; fcu; fcu = fcn) { fcn = fcu->next; - + + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf(op->reports, RPT_WARNING, + "not deleting keyframe for locked F-Curve '%s', object '%s'", + fcu->rna_path, id->name + 2); + continue; + } + /* delete keyframes on current frame * WARNING: this can delete the next F-Curve, hence the "fcn" copying */ - success += delete_keyframe(op->reports, id, NULL, NULL, fcu->rna_path, fcu->array_index, cfra, 0); + success += delete_keyframe_fcurve(adt, fcu, cfra_unmap); } } diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 1ee2dc80a97..8745d571a28 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -182,16 +182,22 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n if (ob->pose) { bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, oldname); if (pchan) { + GHash *gh = ob->pose->chanhash; + + /* remove the old hash entry, and replace with the new name */ + if (gh) { + BLI_assert(BLI_ghash_haskey(gh, pchan->name)); + BLI_ghash_remove(gh, pchan->name, NULL, NULL); + } + BLI_strncpy(pchan->name, newname, MAXBONENAME); - - if (ob->pose->chanhash) { - GHash *gh = ob->pose->chanhash; - - /* remove the old hash entry, and replace with the new name */ - BLI_ghash_remove(gh, oldname, NULL, NULL); + + if (gh) { BLI_ghash_insert(gh, pchan->name, pchan); } } + + BLI_assert(BKE_pose_channels_is_valid(ob->pose) == true); } /* Update any object constraints to use the new bone name */ @@ -294,9 +300,13 @@ static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op)) /* since we renamed stuff... */ DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - /* note, notifier might evolve */ - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); - + /* copied from #rna_Bone_update_renamed */ + /* redraw view */ + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + + /* update animation channels */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, ob->data); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index 22bd22c8561..0301db4b4cf 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -255,7 +255,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, bDeformGroup *dgroup; bPoseChannel *pchan; Mesh *mesh; - Mat4 *bbone = NULL; + Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = NULL; float (*root)[3], (*tip)[3], (*verts)[3]; int *selected; int numbones, vertsfilled = 0, i, j, segments = 0; @@ -309,7 +309,8 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) { if (bone->segments > 1) { segments = bone->segments; - bbone = b_bone_spline_setup(pchan, 1); + b_bone_spline_setup(pchan, 1, bbone_array); + bbone = bbone_array; } } } diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 4991ef63cf5..76cd12f12f8 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -488,7 +488,6 @@ void ED_armature_from_edit(Object *obedit) /* don't change active selection, this messes up separate which uses * editmode toggle and can separate active bone which is de-selected originally */ /* newBone->flag |= BONE_SELECTED; */ /* important, editbones can be active with only 1 point selected */ - arm->act_edbone = NULL; arm->act_bone = newBone; } newBone->roll = 0.0f; @@ -575,6 +574,7 @@ void ED_armature_edit_free(struct Object *ob) } MEM_freeN(arm->edbo); arm->edbo = NULL; + arm->act_edbone = NULL; } } diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 76068c122bf..16d7f9c9420 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -281,7 +281,7 @@ static void laplacian_system_construct_end(LaplacianSystem *sys) sys->varea = MEM_callocN(sizeof(float) * totvert, "LaplacianSystemVarea"); - sys->edgehash = BLI_edgehash_new(); + sys->edgehash = BLI_edgehash_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(sys->totface)); for (a = 0, face = sys->faces; a < sys->totface; a++, face++) { laplacian_increase_edge_count(sys->edgehash, (*face)[0], (*face)[1]); laplacian_increase_edge_count(sys->edgehash, (*face)[1], (*face)[2]); diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index e84008c3d15..31ff1e161e8 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -148,36 +148,6 @@ static short pose_has_protected_selected(Object *ob, short warn) } #endif -/* only for real IK, not for auto-IK */ -static int pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan, int level) -{ - bConstraint *con; - Bone *bone; - - /* No need to check if constraint is active (has influence), - * since all constraints with CONSTRAINT_IK_AUTO are active */ - for (con = pchan->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_KINEMATIC) { - bKinematicConstraint *data = con->data; - if (data->rootbone == 0 || data->rootbone > level) { - if ((data->flag & CONSTRAINT_IK_AUTO) == 0) - return 1; - } - } - } - for (bone = pchan->bone->childbase.first; bone; bone = bone->next) { - pchan = BKE_pose_channel_find_name(ob->pose, bone->name); - if (pchan && pose_channel_in_IK_chain(ob, pchan, level + 1)) - return 1; - } - return 0; -} - -int ED_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan) -{ - return pose_channel_in_IK_chain(ob, pchan, 0); -} - /* ********************************************** */ /* Motion Paths */ diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index ec1662c7fa6..d0e1b15064a 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -602,7 +602,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p pose_slide_refresh(C, pso); /* set cursor to indicate modal */ - WM_cursor_modal(win, BC_EW_SCROLLCURSOR); + WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR); /* header print */ pose_slide_draw_status(pso); @@ -624,7 +624,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) { /* return to normal cursor and header status */ ED_area_headerprint(pso->sa, NULL); - WM_cursor_restore(win); + WM_cursor_modal_restore(win); /* insert keyframes as required... */ pose_slide_autoKeyframe(C, pso); @@ -639,7 +639,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) { /* return to normal cursor and header status */ ED_area_headerprint(pso->sa, NULL); - WM_cursor_restore(win); + WM_cursor_modal_restore(win); /* reset transforms back to original state */ pose_slide_reset(pso); diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c index f66fb38a2a6..3a09f531d44 100644 --- a/source/blender/editors/armature/reeb.c +++ b/source/blender/editors/armature/reeb.c @@ -198,7 +198,7 @@ ReebGraph *newReebGraph(void) rg = MEM_callocN(sizeof(ReebGraph), "reeb graph"); rg->totnodes = 0; - rg->emap = BLI_edgehash_new(); + rg->emap = BLI_edgehash_new(__func__); rg->free_arc = REEB_freeArc; diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt index 4f34bd19b5b..0b449c4334d 100644 --- a/source/blender/editors/curve/CMakeLists.txt +++ b/source/blender/editors/curve/CMakeLists.txt @@ -36,6 +36,7 @@ set(INC_SYS set(SRC curve_ops.c editcurve.c + editcurve_add.c editfont.c lorem.c diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h index d197697e60b..da8f86580f6 100644 --- a/source/blender/editors/curve/curve_intern.h +++ b/source/blender/editors/curve/curve_intern.h @@ -33,6 +33,9 @@ #define __CURVE_INTERN_H__ /* internal exports only */ +struct ListBase; +struct EditNurb; +struct Object; struct wmOperatorType; /* lorem.c */ @@ -71,11 +74,13 @@ void FONT_OT_unlink(struct wmOperatorType *ot); void FONT_OT_textbox_add(struct wmOperatorType *ot); void FONT_OT_textbox_remove(struct wmOperatorType *ot); + /* editcurve.c */ void CURVE_OT_hide(struct wmOperatorType *ot); void CURVE_OT_reveal(struct wmOperatorType *ot); void CURVE_OT_separate(struct wmOperatorType *ot); +void CURVE_OT_split(struct wmOperatorType *ot); void CURVE_OT_duplicate(struct wmOperatorType *ot); void CURVE_OT_delete(struct wmOperatorType *ot); @@ -92,19 +97,6 @@ void CURVE_OT_smooth_weight(struct wmOperatorType *ot); void CURVE_OT_smooth_radius(struct wmOperatorType *ot); void CURVE_OT_smooth_tilt(struct wmOperatorType *ot); -void CURVE_OT_primitive_bezier_curve_add(struct wmOperatorType *ot); -void CURVE_OT_primitive_bezier_circle_add(struct wmOperatorType *ot); -void CURVE_OT_primitive_nurbs_curve_add(struct wmOperatorType *ot); -void CURVE_OT_primitive_nurbs_circle_add(struct wmOperatorType *ot); -void CURVE_OT_primitive_nurbs_path_add(struct wmOperatorType *ot); - -void SURFACE_OT_primitive_nurbs_surface_curve_add(struct wmOperatorType *ot); -void SURFACE_OT_primitive_nurbs_surface_circle_add(struct wmOperatorType *ot); -void SURFACE_OT_primitive_nurbs_surface_surface_add(struct wmOperatorType *ot); -void SURFACE_OT_primitive_nurbs_surface_cylinder_add(struct wmOperatorType *ot); -void SURFACE_OT_primitive_nurbs_surface_sphere_add(struct wmOperatorType *ot); -void SURFACE_OT_primitive_nurbs_surface_torus_add(struct wmOperatorType *ot); - void CURVE_OT_de_select_first(struct wmOperatorType *ot); void CURVE_OT_de_select_last(struct wmOperatorType *ot); void CURVE_OT_select_all(struct wmOperatorType *ot); @@ -126,5 +118,24 @@ void CURVE_OT_vertex_add(struct wmOperatorType *ot); void CURVE_OT_extrude(struct wmOperatorType *ot); void CURVE_OT_cyclic_toggle(struct wmOperatorType *ot); -#endif /* ED_UTIL_INTERN_H */ +/* helper functions */ +void ed_editnurb_translate_flag(struct ListBase *editnurb, short flag, const float vec[3]); +bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, short flag); +bool ed_editnurb_spin(float viewmat[4][4], struct Object *obedit, const float axis[3], const float cent[3]); + + +/* editcurve_add.c */ +void CURVE_OT_primitive_bezier_curve_add(struct wmOperatorType *ot); +void CURVE_OT_primitive_bezier_circle_add(struct wmOperatorType *ot); +void CURVE_OT_primitive_nurbs_curve_add(struct wmOperatorType *ot); +void CURVE_OT_primitive_nurbs_circle_add(struct wmOperatorType *ot); +void CURVE_OT_primitive_nurbs_path_add(struct wmOperatorType *ot); + +void SURFACE_OT_primitive_nurbs_surface_curve_add(struct wmOperatorType *ot); +void SURFACE_OT_primitive_nurbs_surface_circle_add(struct wmOperatorType *ot); +void SURFACE_OT_primitive_nurbs_surface_surface_add(struct wmOperatorType *ot); +void SURFACE_OT_primitive_nurbs_surface_cylinder_add(struct wmOperatorType *ot); +void SURFACE_OT_primitive_nurbs_surface_sphere_add(struct wmOperatorType *ot); +void SURFACE_OT_primitive_nurbs_surface_torus_add(struct wmOperatorType *ot); +#endif /* __CURVE_INTERN_H__ */ diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c index 2452a5d1a4b..1cf194e02c4 100644 --- a/source/blender/editors/curve/curve_ops.c +++ b/source/blender/editors/curve/curve_ops.c @@ -87,6 +87,7 @@ void ED_operatortypes_curve(void) WM_operatortype_append(CURVE_OT_reveal); WM_operatortype_append(CURVE_OT_separate); + WM_operatortype_append(CURVE_OT_split); WM_operatortype_append(CURVE_OT_duplicate); WM_operatortype_append(CURVE_OT_delete); @@ -244,6 +245,7 @@ void ED_keymap_curve(wmKeyConfig *keyconf) RNA_boolean_set(kmi->ptr, "deselect", TRUE); WM_keymap_add_item(keymap, "CURVE_OT_separate", PKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "CURVE_OT_split", YKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "CURVE_OT_extrude_move", EKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "CURVE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "CURVE_OT_make_segment", FKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 660f8098a38..2dc32f711b4 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -29,16 +29,6 @@ * \ingroup edcurve */ -#include <math.h> -#include <string.h> - -#ifndef WIN32 -#include <unistd.h> -#else -#include <io.h> -#endif -#include <stdlib.h> - #include "DNA_key_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -49,9 +39,7 @@ #include "BLI_blenlib.h" #include "BLI_bitmap.h" #include "BLI_math.h" -#include "BLI_dynstr.h" #include "BLI_rand.h" -#include "BLI_utildefines.h" #include "BLI_ghash.h" #include "BLF_translation.h" @@ -62,7 +50,6 @@ #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_key.h" -#include "BKE_library.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_animsys.h" @@ -106,16 +93,25 @@ typedef struct { Nurb *orig_nu; } CVKeyIndex; -void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatus); -static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus); +typedef enum eVisible_Types { + HIDDEN = true, + VISIBLE = false, +} eVisible_Types; -/* still need to eradicate a few :( */ -#define CALLOC_STRUCT_N(x, y, name) (x *)MEM_callocN((y) * sizeof(x), name) +typedef enum eEndPoint_Types { + FIRST = true, + LAST = false, +} eEndPoint_Types; -static float nurbcircle[8][2] = { - {0.0, -1.0}, {-1.0, -1.0}, {-1.0, 0.0}, {-1.0, 1.0}, - {0.0, 1.0}, { 1.0, 1.0}, { 1.0, 0.0}, { 1.0, -1.0} -}; +typedef enum eCurveElem_Types { + CURVE_VERTEX = 0, + CURVE_SEGMENT, +} eCurveElem_Types; + +void selectend_nurb(Object *obedit, enum eEndPoint_Types selfirst, bool doswap, bool selstatus); +static void select_adjacent_cp(ListBase *editnurb, short next, const bool cont, const bool selstatus); +static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, const short flag, const bool split); +static int curve_delete_selected(Object *obedit, const eCurveElem_Types type, const bool split); ListBase *object_editcurve_get(Object *ob) { @@ -149,69 +145,59 @@ static Nurb *get_actNurb(Object *obedit) /* ******************* SELECTION FUNCTIONS ********************* */ -#define HIDDEN 1 -#define VISIBLE 0 - -#define FIRST 1 -#define LAST 0 - /* returns 1 in case (de)selection was successful */ -static short select_beztriple(BezTriple *bezt, short selstatus, short flag, short hidden) +static bool select_beztriple(BezTriple *bezt, bool selstatus, short flag, eVisible_Types hidden) { - if (bezt) { - if ((bezt->hide == 0) || (hidden == 1)) { - if (selstatus == 1) { /* selects */ - bezt->f1 |= flag; - bezt->f2 |= flag; - bezt->f3 |= flag; - return 1; - } - else { /* deselects */ - bezt->f1 &= ~flag; - bezt->f2 &= ~flag; - bezt->f3 &= ~flag; - return 1; - } + if ((bezt->hide == 0) || (hidden == HIDDEN)) { + if (selstatus == SELECT) { /* selects */ + bezt->f1 |= flag; + bezt->f2 |= flag; + bezt->f3 |= flag; + return true; + } + else { /* deselects */ + bezt->f1 &= ~flag; + bezt->f2 &= ~flag; + bezt->f3 &= ~flag; + return true; } } - return 0; + return false; } /* returns 1 in case (de)selection was successful */ -static short select_bpoint(BPoint *bp, short selstatus, short flag, short hidden) +static bool select_bpoint(BPoint *bp, bool selstatus, short flag, bool hidden) { - if (bp) { - if ((bp->hide == 0) || (hidden == 1)) { - if (selstatus == 1) { - bp->f1 |= flag; - return 1; - } - else { - bp->f1 &= ~flag; - return 1; - } + if ((bp->hide == 0) || (hidden == 1)) { + if (selstatus == SELECT) { + bp->f1 |= flag; + return true; + } + else { + bp->f1 &= ~flag; + return true; } } - return 0; + return false; } -static short swap_selection_beztriple(BezTriple *bezt) +static bool swap_selection_beztriple(BezTriple *bezt) { if (bezt->f2 & SELECT) - return select_beztriple(bezt, DESELECT, 1, VISIBLE); + return select_beztriple(bezt, DESELECT, SELECT, VISIBLE); else - return select_beztriple(bezt, SELECT, 1, VISIBLE); + return select_beztriple(bezt, SELECT, SELECT, VISIBLE); } -static short swap_selection_bpoint(BPoint *bp) +static bool swap_selection_bpoint(BPoint *bp) { if (bp->f1 & SELECT) - return select_bpoint(bp, DESELECT, 1, VISIBLE); + return select_bpoint(bp, DESELECT, SELECT, VISIBLE); else - return select_bpoint(bp, SELECT, 1, VISIBLE); + return select_bpoint(bp, SELECT, SELECT, VISIBLE); } int isNurbsel(Nurb *nu) @@ -361,7 +347,7 @@ static CVKeyIndex *getCVKeyIndex(EditNurb *editnurb, void *cv) static CVKeyIndex *popCVKeyIndex(EditNurb *editnurb, void *cv) { - return BLI_ghash_pop(editnurb->keyindex, cv, NULL); + return BLI_ghash_popkey(editnurb->keyindex, cv, NULL); } static BezTriple *getKeyIndexOrig_bezt(EditNurb *editnurb, BezTriple *bezt) @@ -674,7 +660,7 @@ static GHash *dupli_keyIndexHash(GHash *keyindex) GHash *gh; GHashIterator *hashIter; - gh = BLI_ghash_ptr_new("dupli_keyIndex gh"); + gh = BLI_ghash_ptr_new_ex("dupli_keyIndex gh", BLI_ghash_size(keyindex)); for (hashIter = BLI_ghashIterator_new(keyindex); BLI_ghashIterator_done(hashIter) == false; @@ -1463,6 +1449,49 @@ void CURVE_OT_separate(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/******************** split operator ***********************/ + +static int curve_split_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + ListBase *editnurb = object_editcurve_get(obedit); + ListBase newnurb = {NULL, NULL}; + + adduplicateflagNurb(obedit, &newnurb, SELECT, true); + + if (newnurb.first != NULL) { + curve_delete_selected(obedit, CURVE_SEGMENT, true); + BLI_movelisttolist(editnurb, &newnurb); + + if (ED_curve_updateAnimPaths(obedit->data)) + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DAG_id_tag_update(obedit->data, 0); + } + else { + BKE_report(op->reports, RPT_ERROR, "Cannot split current selection"); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; +} + +void CURVE_OT_split(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Split"; + ot->idname = "CURVE_OT_split"; + ot->description = "Split off selected points from connected unselected points"; + + /* api callbacks */ + ot->exec = curve_split_exec; + ot->poll = ED_operator_editcurve; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /* ******************* FLAGS ********************* */ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag) @@ -1510,34 +1539,7 @@ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag) return 0; } -static void setflagsNurb(ListBase *editnurb, short flag) -{ - Nurb *nu; - BezTriple *bezt; - BPoint *bp; - int a; - - for (nu = editnurb->first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - a = nu->pntsu; - bezt = nu->bezt; - while (a--) { - bezt->f1 = bezt->f2 = bezt->f3 = flag; - bezt++; - } - } - else { - a = nu->pntsu * nu->pntsv; - bp = nu->bp; - while (a--) { - bp->f1 = flag; - bp++; - } - } - } -} - -static void rotateflagNurb(ListBase *editnurb, short flag, float *cent, float rotmat[3][3]) +static void rotateflagNurb(ListBase *editnurb, short flag, const float cent[3], float rotmat[3][3]) { /* all verts with (flag & 'flag') rotate */ Nurb *nu; @@ -1561,7 +1563,7 @@ static void rotateflagNurb(ListBase *editnurb, short flag, float *cent, float ro } } -static void translateflagNurb(ListBase *editnurb, short flag, const float vec[3]) +void ed_editnurb_translate_flag(ListBase *editnurb, short flag, const float vec[3]) { /* all verts with ('flag' & flag) translate */ Nurb *nu; @@ -1614,9 +1616,8 @@ static void weightflagNurb(ListBase *editnurb, short flag, float w) } } -static int deleteflagNurb(bContext *C, wmOperator *UNUSED(op), int flag) +static int deleteflagNurb(Object *obedit, short flag) { - Object *obedit = CTX_data_edit_object(C); Curve *cu = obedit->data; ListBase *editnurb = object_editcurve_get(obedit); Nurb *nu, *next; @@ -1744,18 +1745,16 @@ static int deleteflagNurb(bContext *C, wmOperator *UNUSED(op), int flag) nu = next; } - if (ED_curve_updateAnimPaths(obedit->data)) - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); - return OPERATOR_FINISHED; } /* only for OB_SURF */ -static short extrudeflagNurb(EditNurb *editnurb, int flag) +bool ed_editnurb_extrude_flag(EditNurb *editnurb, short flag) { Nurb *nu; BPoint *bp, *bpn, *newbp; - int ok = 0, a, u, v, len; + int a, u, v, len; + bool ok = false; nu = editnurb->nurbs.first; while (nu) { @@ -1774,7 +1773,7 @@ static short extrudeflagNurb(EditNurb *editnurb, int flag) a--; } if (a == 0) { - ok = 1; + ok = true; newbp = (BPoint *)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1"); ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu); bp = newbp + nu->pntsu; @@ -1808,7 +1807,7 @@ static short extrudeflagNurb(EditNurb *editnurb, int flag) } if (u == 0 || u == nu->pntsv - 1) { /* row in u-direction selected */ - ok = 1; + ok = true; newbp = (BPoint *)MEM_mallocN(nu->pntsu * (nu->pntsv + 1) * sizeof(BPoint), "extrudeNurb1"); if (u == 0) { @@ -1836,7 +1835,7 @@ static short extrudeflagNurb(EditNurb *editnurb, int flag) BKE_nurb_knot_calc_v(nu); } else if (v == 0 || v == nu->pntsu - 1) { /* column in v-direction selected */ - ok = 1; + ok = true; bpn = newbp = (BPoint *)MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), "extrudeNurb1"); bp = nu->bp; @@ -1869,40 +1868,54 @@ static short extrudeflagNurb(EditNurb *editnurb, int flag) return ok; } -static void adduplicateflagNurb(Object *obedit, short flag) +static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, + const short flag, const bool split) { ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu, *newnu; + Nurb *nu, *newnu, *startnu; BezTriple *bezt, *bezt1; BPoint *bp, *bp1; Curve *cu = (Curve *)obedit->data; - int a, b, starta, enda, newu, newv; + int a, b, starta, enda, diffa, newu, newv; char *usel; cu->lastsel = NULL; nu = editnurb->last; while (nu) { + startnu = NULL; if (nu->type == CU_BEZIER) { bezt = nu->bezt; for (a = 0; a < nu->pntsu; a++) { enda = -1; starta = a; while ((bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag)) { - select_beztriple(bezt, DESELECT, flag, HIDDEN); + if (!split) select_beztriple(bezt, DESELECT, flag, HIDDEN); enda = a; if (a >= nu->pntsu - 1) break; a++; bezt++; } if (enda >= starta) { - newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN"); - memcpy(newnu, nu, sizeof(Nurb)); - BLI_addtail(editnurb, newnu); - set_actNurb(obedit, newnu); - newnu->pntsu = enda - starta + 1; - newnu->bezt = (BezTriple *)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN"); - memcpy(newnu->bezt, &nu->bezt[starta], newnu->pntsu * sizeof(BezTriple)); + diffa = enda - starta + 1; + + if (startnu != NULL && enda == nu->pntsu - 1) { + /* end point of cyclic spline selected, so merge end points with start points */ + bezt1 = (BezTriple *)MEM_mallocN((startnu->pntsu + diffa) * sizeof(BezTriple), "adduplicateN"); + memcpy(bezt1, &nu->bezt[starta], diffa * sizeof(BezTriple)); + memcpy(&bezt1[diffa], startnu->bezt, startnu->pntsu * sizeof(BezTriple)); + + MEM_freeN(startnu->bezt); + startnu->bezt = bezt1; + startnu->pntsu += diffa; + newnu = startnu; + } + else { + newnu = ED_curve_nurbcpy(nu, diffa); + BLI_addtail(newnurb, newnu); + set_actNurb(obedit, newnu); + memcpy(newnu->bezt, &nu->bezt[starta], newnu->pntsu * sizeof(BezTriple)); + } b = newnu->pntsu; bezt1 = newnu->bezt; @@ -1914,6 +1927,7 @@ static void adduplicateflagNurb(Object *obedit, short flag) if (nu->flagu & CU_NURB_CYCLIC) { if (starta != 0 || enda != nu->pntsu - 1) { newnu->flagu &= ~CU_NURB_CYCLIC; + if (starta == 0) startnu = newnu; } } } @@ -1926,20 +1940,32 @@ static void adduplicateflagNurb(Object *obedit, short flag) enda = -1; starta = a; while (bp->f1 & flag) { - select_bpoint(bp, DESELECT, flag, HIDDEN); + if (!split) select_bpoint(bp, DESELECT, flag, HIDDEN); enda = a; if (a >= nu->pntsu - 1) break; a++; bp++; } if (enda >= starta) { - newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN3"); - memcpy(newnu, nu, sizeof(Nurb)); - set_actNurb(obedit, newnu); - BLI_addtail(editnurb, newnu); - newnu->pntsu = enda - starta + 1; - newnu->bp = (BPoint *)MEM_mallocN((enda - starta + 1) * sizeof(BPoint), "adduplicateN4"); - memcpy(newnu->bp, &nu->bp[starta], newnu->pntsu * sizeof(BPoint)); + diffa = enda - starta + 1; + + if (startnu != NULL && enda == nu->pntsu - 1) { + /* end point of cyclic spline selected, so merge end points with start points */ + bp1 = (BPoint *)MEM_mallocN((startnu->pntsu + diffa) * sizeof(BPoint), "adduplicateN2"); + memcpy(bp1, &nu->bp[starta], diffa * sizeof(BPoint)); + memcpy(&bp1[diffa], startnu->bp, startnu->pntsu * sizeof(BPoint)); + + MEM_freeN(startnu->bp); + startnu->bp = bp1; + startnu->pntsu += diffa; + newnu = startnu; + } + else { + newnu = ED_curve_nurbcpy(nu, diffa); + BLI_addtail(newnurb, newnu); + set_actNurb(obedit, newnu); + memcpy(newnu->bp, &nu->bp[starta], newnu->pntsu * sizeof(BPoint)); + } b = newnu->pntsu; bp1 = newnu->bp; @@ -1951,12 +1977,9 @@ static void adduplicateflagNurb(Object *obedit, short flag) if (nu->flagu & CU_NURB_CYCLIC) { if (starta != 0 || enda != nu->pntsu - 1) { newnu->flagu &= ~CU_NURB_CYCLIC; + if (starta == 0) startnu = newnu; } } - - /* knots */ - newnu->knotsu = NULL; - BKE_nurb_knot_calc_u(newnu); } bp++; } @@ -1964,7 +1987,7 @@ static void adduplicateflagNurb(Object *obedit, short flag) else { /* a rectangular area in nurb has to be selected */ if (isNurbsel(nu)) { - usel = MEM_callocN(nu->pntsu, "adduplicateN4"); + usel = MEM_callocN(nu->pntsu, "adduplicateN3"); bp = nu->bp; for (a = 0; a < nu->pntsv; a++) { for (b = 0; b < nu->pntsu; b++, bp++) { @@ -1993,13 +2016,13 @@ static void adduplicateflagNurb(Object *obedit, short flag) if (newu == 1) SWAP(int, newu, newv); - newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN5"); + newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "adduplicateN4"); memcpy(newnu, nu, sizeof(Nurb)); - BLI_addtail(editnurb, newnu); + BLI_addtail(newnurb, newnu); set_actNurb(obedit, newnu); newnu->pntsu = newu; newnu->pntsv = newv; - newnu->bp = (BPoint *)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN6"); + newnu->bp = (BPoint *)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN5"); BKE_nurb_order_clamp_u(newnu); BKE_nurb_order_clamp_v(newnu); @@ -2040,6 +2063,22 @@ static void adduplicateflagNurb(Object *obedit, short flag) nu = nu->prev; } + for (nu = newnurb->first; nu; nu = nu->next) { + /* knots done after duplicate as pntsu may change */ + if (nu->pntsv == 1) { + nu->knotsu = NULL; + BKE_nurb_knot_calc_u(nu); + } + + if (split) { + if (nu->type == CU_BEZIER) { + /* recalc first and last */ + BKE_nurb_handle_calc_simple(nu, &nu->bezt[0]); + BKE_nurb_handle_calc_simple(nu, &nu->bezt[nu->pntsu - 1]); + } + } + } + /* actnu changed */ } @@ -2513,7 +2552,8 @@ void CURVE_OT_smooth_tilt(wmOperatorType *ot) /* next == -1 -> select previous */ /* cont == 1 -> select continuously */ /* selstatus, inverts behavior */ -static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus) +static void select_adjacent_cp(ListBase *editnurb, short next, + const bool cont, const bool selstatus) { Nurb *nu; BezTriple *bezt; @@ -2531,10 +2571,10 @@ static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short if (next < 0) bezt = &nu->bezt[a - 1]; while (a--) { if (a - abs(next) < 0) break; - if ((lastsel == 0) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == 0))) { + if ((lastsel == 0) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == DESELECT))) { bezt += next; - if (!(bezt->f2 & SELECT) || (selstatus == 0)) { - short sel = select_beztriple(bezt, selstatus, 1, VISIBLE); + if (!(bezt->f2 & SELECT) || (selstatus == DESELECT)) { + short sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE); if ((sel == 1) && (cont == 0)) lastsel = true; } } @@ -2552,10 +2592,10 @@ static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short if (next < 0) bp = &nu->bp[a - 1]; while (a--) { if (a - abs(next) < 0) break; - if ((lastsel == 0) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == 0))) { + if ((lastsel == 0) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == DESELECT))) { bp += next; - if (!(bp->f1 & SELECT) || (selstatus == 0)) { - short sel = select_bpoint(bp, selstatus, 1, VISIBLE); + if (!(bp->f1 & SELECT) || (selstatus == DESELECT)) { + short sel = select_bpoint(bp, selstatus, SELECT, VISIBLE); if ((sel == 1) && (cont == 0)) lastsel = true; } } @@ -2577,7 +2617,7 @@ static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short * doswap: defines if selection state of each first/last control point is swapped * selstatus: selection status in case doswap is false */ -void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatus) +void selectend_nurb(Object *obedit, eEndPoint_Types selfirst, bool doswap, bool selstatus) { ListBase *editnurb = object_editcurve_get(obedit); Nurb *nu; @@ -2596,7 +2636,7 @@ void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatu a = nu->pntsu; /* which point? */ - if (selfirst == 0) { /* select last */ + if (selfirst == LAST) { /* select last */ bezt = &nu->bezt[a - 1]; } else { /* select first */ @@ -2604,18 +2644,18 @@ void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatu } while (a--) { - short sel; + bool sel; if (doswap) sel = swap_selection_beztriple(bezt); - else sel = select_beztriple(bezt, selstatus, 1, VISIBLE); + else sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE); - if (sel == 1) break; + if (sel == true) break; } } else { a = nu->pntsu * nu->pntsv; /* which point? */ - if (selfirst == 0) { /* select last */ + if (selfirst == LAST) { /* select last */ bp = &nu->bp[a - 1]; } else { /* select first */ @@ -2624,11 +2664,11 @@ void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatu while (a--) { if (bp->hide == 0) { - short sel; + bool sel; if (doswap) sel = swap_selection_bpoint(bp); - else sel = select_bpoint(bp, selstatus, 1, VISIBLE); + else sel = select_bpoint(bp, selstatus, SELECT, VISIBLE); - if (sel == 1) break; + if (sel == true) break; } } } @@ -2639,7 +2679,7 @@ static int de_select_first_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); - selectend_nurb(obedit, FIRST, 1, DESELECT); + selectend_nurb(obedit, FIRST, true, DESELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -2664,7 +2704,7 @@ static int de_select_last_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); - selectend_nurb(obedit, LAST, 1, DESELECT); + selectend_nurb(obedit, LAST, true, DESELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -2789,11 +2829,11 @@ static int hide_exec(bContext *C, wmOperator *op) sel = 0; while (a--) { if (invert == 0 && BEZSELECTED_HIDDENHANDLES(cu, bezt)) { - select_beztriple(bezt, DESELECT, 1, HIDDEN); + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); bezt->hide = 1; } else if (invert && !BEZSELECTED_HIDDENHANDLES(cu, bezt)) { - select_beztriple(bezt, DESELECT, 1, HIDDEN); + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); bezt->hide = 1; } if (bezt->hide) sel++; @@ -2807,11 +2847,11 @@ static int hide_exec(bContext *C, wmOperator *op) sel = 0; while (a--) { if (invert == 0 && (bp->f1 & SELECT)) { - select_bpoint(bp, DESELECT, 1, HIDDEN); + select_bpoint(bp, DESELECT, SELECT, HIDDEN); bp->hide = 1; } else if (invert && (bp->f1 & SELECT) == 0) { - select_bpoint(bp, DESELECT, 1, HIDDEN); + select_bpoint(bp, DESELECT, SELECT, HIDDEN); bp->hide = 1; } if (bp->hide) sel++; @@ -2863,7 +2903,7 @@ static int reveal_exec(bContext *C, wmOperator *UNUSED(op)) a = nu->pntsu; while (a--) { if (bezt->hide) { - select_beztriple(bezt, SELECT, 1, HIDDEN); + select_beztriple(bezt, SELECT, SELECT, HIDDEN); bezt->hide = 0; } bezt++; @@ -2874,7 +2914,7 @@ static int reveal_exec(bContext *C, wmOperator *UNUSED(op)) a = nu->pntsu * nu->pntsv; while (a--) { if (bp->hide) { - select_bpoint(bp, SELECT, 1, HIDDEN); + select_bpoint(bp, SELECT, SELECT, HIDDEN); bp->hide = 0; } bp++; @@ -3840,7 +3880,7 @@ static void merge_2_nurb(wmOperator *op, ListBase *editnurb, Nurb *nu1, Nurb *nu for (u = 0; u < nu1->pntsu; u++, bp++) { if (u < origu) { *bp = *bp1; bp1++; - select_bpoint(bp, SELECT, 1, HIDDEN); + select_bpoint(bp, SELECT, SELECT, HIDDEN); } else { *bp = *bp2; bp2++; @@ -4148,7 +4188,7 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool if (extend) { if (bezt) { if (hand == 1) { - select_beztriple(bezt, SELECT, 1, HIDDEN); + select_beztriple(bezt, SELECT, SELECT, HIDDEN); cu->lastsel = bezt; } else { @@ -4160,13 +4200,13 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool } else { cu->lastsel = bp; - select_bpoint(bp, SELECT, 1, HIDDEN); + select_bpoint(bp, SELECT, SELECT, HIDDEN); } } else if (deselect) { if (bezt) { if (hand == 1) { - select_beztriple(bezt, DESELECT, 1, HIDDEN); + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); if (bezt == cu->lastsel) cu->lastsel = NULL; } else if (hand == 0) { @@ -4177,7 +4217,7 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool } } else { - select_bpoint(bp, DESELECT, 1, HIDDEN); + select_bpoint(bp, DESELECT, SELECT, HIDDEN); if (cu->lastsel == bp) cu->lastsel = NULL; } } @@ -4185,11 +4225,11 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool if (bezt) { if (hand == 1) { if (bezt->f2 & SELECT) { - select_beztriple(bezt, DESELECT, 1, HIDDEN); + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); if (bezt == cu->lastsel) cu->lastsel = NULL; } else { - select_beztriple(bezt, SELECT, 1, HIDDEN); + select_beztriple(bezt, SELECT, SELECT, HIDDEN); cu->lastsel = bezt; } } @@ -4202,22 +4242,22 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool } else { if (bp->f1 & SELECT) { - select_bpoint(bp, DESELECT, 1, HIDDEN); + select_bpoint(bp, DESELECT, SELECT, HIDDEN); if (cu->lastsel == bp) cu->lastsel = NULL; } else { - select_bpoint(bp, SELECT, 1, HIDDEN); + select_bpoint(bp, SELECT, SELECT, HIDDEN); cu->lastsel = bp; } } } else { - setflagsNurb(editnurb, 0); + BKE_nurbList_flag_set(editnurb, 0); if (bezt) { if (hand == 1) { - select_beztriple(bezt, SELECT, 1, HIDDEN); + select_beztriple(bezt, SELECT, SELECT, HIDDEN); cu->lastsel = bezt; } else { @@ -4229,7 +4269,7 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool } else { cu->lastsel = bp; - select_bpoint(bp, SELECT, 1, HIDDEN); + select_bpoint(bp, SELECT, SELECT, HIDDEN); } } @@ -4248,7 +4288,7 @@ bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool /* 'cent' is in object space and 'dvec' in worldspace. */ -static int spin_nurb(float viewmat[4][4], Object *obedit, float *axis, float *cent) +bool ed_editnurb_spin(float viewmat[4][4], Object *obedit, const float axis[3], const float cent[3]) { Curve *cu = (Curve *)obedit->data; ListBase *editnurb = object_editcurve_get(obedit); @@ -4256,7 +4296,8 @@ static int spin_nurb(float viewmat[4][4], Object *obedit, float *axis, float *ce float si, phi, n[3], q[4], cmat[3][3], tmat[3][3], imat[3][3]; float bmat[3][3], rotmat[3][3], scalemat1[3][3], scalemat2[3][3]; float persmat[3][3], persinv[3][3]; - short a, ok, changed = 0; + bool ok, changed = false; + int a; copy_m3_m4(persmat, viewmat); invert_m3_m3(persinv, persmat); @@ -4295,19 +4336,19 @@ static int spin_nurb(float viewmat[4][4], Object *obedit, float *axis, float *ce mul_m3_m3m3(tmat, persinv, cmat); mul_m3_m3m3(scalemat2, imat, tmat); - ok = 1; + ok = true; for (a = 0; a < 7; a++) { - ok = extrudeflagNurb(cu->editnurb, 1); + ok = ed_editnurb_extrude_flag(cu->editnurb, 1); - if (ok == 0) + if (ok == false) return changed; - changed = 1; + changed = true; rotateflagNurb(editnurb, SELECT, cent, rotmat); - if ((a & SELECT) == 0) { + if ((a & 1) == 0) { rotateflagNurb(editnurb, SELECT, cent, scalemat1); weightflagNurb(editnurb, SELECT, 0.25 * M_SQRT2); } @@ -4347,7 +4388,7 @@ static int spin_exec(bContext *C, wmOperator *op) else unit_m4(viewmat); - if (!spin_nurb(viewmat, obedit, axis, cent)) { + if (!ed_editnurb_spin(viewmat, obedit, axis, cent)) { BKE_report(op->reports, RPT_ERROR, "Cannot spin"); return OPERATOR_CANCELLED; } @@ -4762,7 +4803,7 @@ static int extrude_exec(bContext *C, wmOperator *UNUSED(op)) addvert_Nurb(C, 'e', NULL); } else { - if (extrudeflagNurb(editnurb, 1)) { /* '1'= flag */ + if (ed_editnurb_extrude_flag(editnurb, 1)) { /* '1'= flag */ if (ED_curve_updateAnimPaths(obedit->data)) WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); @@ -4944,7 +4985,7 @@ static int select_linked_exec(bContext *C, wmOperator *UNUSED(op)) a = nu->pntsu; bezt = nu->bezt; while (a--) { - select_beztriple(bezt, SELECT, 1, VISIBLE); + select_beztriple(bezt, SELECT, SELECT, VISIBLE); bezt++; } break; @@ -4960,7 +5001,7 @@ static int select_linked_exec(bContext *C, wmOperator *UNUSED(op)) a = nu->pntsu * nu->pntsv; bp = nu->bp; while (a--) { - select_bpoint(bp, SELECT, 1, VISIBLE); + select_bpoint(bp, SELECT, SELECT, VISIBLE); bp++; } break; @@ -5021,8 +5062,8 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent a = nu->pntsu; bezt = nu->bezt; while (a--) { - if (deselect) select_beztriple(bezt, DESELECT, 1, VISIBLE); - else select_beztriple(bezt, SELECT, 1, VISIBLE); + if (deselect) select_beztriple(bezt, DESELECT, SELECT, VISIBLE); + else select_beztriple(bezt, SELECT, SELECT, VISIBLE); bezt++; } } @@ -5030,8 +5071,8 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent a = nu->pntsu * nu->pntsv; bp = nu->bp; while (a--) { - if (deselect) select_bpoint(bp, DESELECT, 1, VISIBLE); - else select_bpoint(bp, SELECT, 1, VISIBLE); + if (deselect) select_bpoint(bp, DESELECT, SELECT, VISIBLE); + else select_bpoint(bp, SELECT, SELECT, VISIBLE); bp++; } } @@ -5095,7 +5136,7 @@ static int select_row_exec(bContext *C, wmOperator *UNUSED(op)) if (ok) { if (last == cu->lastsel) { direction = 1 - direction; - setflagsNurb(editnurb, 0); + BKE_nurbList_flag_set(editnurb, 0); } last = cu->lastsel; @@ -5103,10 +5144,10 @@ static int select_row_exec(bContext *C, wmOperator *UNUSED(op)) for (a = 0; a < nu->pntsv; a++) { for (b = 0; b < nu->pntsu; b++, bp++) { if (direction) { - if (a == v) select_bpoint(bp, SELECT, 1, VISIBLE); + if (a == v) select_bpoint(bp, SELECT, SELECT, VISIBLE); } else { - if (b == u) select_bpoint(bp, SELECT, 1, VISIBLE); + if (b == u) select_bpoint(bp, SELECT, SELECT, VISIBLE); } } } @@ -5217,14 +5258,14 @@ static int select_more_exec(bContext *C, wmOperator *UNUSED(op)) /* upper control point */ if (a % nu->pntsu != 0) { tempbp = bp - 1; - if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, 1, VISIBLE); + if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, SELECT, VISIBLE); } /* left control point. select only if it is not selected already */ if (a - nu->pntsu > 0) { sel = 0; tempbp = bp + nu->pntsu; - if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, 1, VISIBLE); + if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE); /* make sure selected bpoint is discarded */ if (sel == 1) BLI_BITMAP_SET(selbpoints, a - nu->pntsu); } @@ -5232,14 +5273,14 @@ static int select_more_exec(bContext *C, wmOperator *UNUSED(op)) /* right control point */ if (a + nu->pntsu < nu->pntsu * nu->pntsv) { tempbp = bp - nu->pntsu; - if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, 1, VISIBLE); + if (!(tempbp->f1 & SELECT)) select_bpoint(tempbp, SELECT, SELECT, VISIBLE); } /* lower control point. skip next bp in case selection was made */ if (a % nu->pntsu != 1) { sel = 0; tempbp = bp + 1; - if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, 1, VISIBLE); + if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE); if (sel) { bp++; a--; @@ -5341,7 +5382,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) } if (sel != 4) { - select_bpoint(bp, DESELECT, 1, VISIBLE); + select_bpoint(bp, DESELECT, SELECT, VISIBLE); BLI_BITMAP_SET(selbpoints, a); } } @@ -5387,7 +5428,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) } if (sel != 2) { - select_beztriple(bezt, DESELECT, 1, VISIBLE); + select_beztriple(bezt, DESELECT, SELECT, VISIBLE); lastsel = true; } else { @@ -5429,7 +5470,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) } if (sel != 2) { - select_bpoint(bp, DESELECT, 1, VISIBLE); + select_bpoint(bp, DESELECT, SELECT, VISIBLE); lastsel = true; } else { @@ -5481,7 +5522,7 @@ static void selectrandom_curve(ListBase *editnurb, float randfac) a = nu->pntsu; while (a--) { if (BLI_frand() < randfac) - select_beztriple(bezt, SELECT, 1, VISIBLE); + select_beztriple(bezt, SELECT, SELECT, VISIBLE); bezt++; } } @@ -5491,7 +5532,7 @@ static void selectrandom_curve(ListBase *editnurb, float randfac) while (a--) { if (BLI_frand() < randfac) - select_bpoint(bp, SELECT, 1, VISIBLE); + select_bpoint(bp, SELECT, SELECT, VISIBLE); bp++; } } @@ -5534,15 +5575,13 @@ void CURVE_OT_select_random(wmOperatorType *ot) /********************* every nth number of point *******************/ -static int point_on_nurb(Nurb *nu, void *point) +static bool point_in_nurb(Nurb *nu, void *point) { if (nu->bezt) { - BezTriple *bezt = (BezTriple *)point; - return bezt >= nu->bezt && bezt < &nu->bezt[nu->pntsu]; + return ARRAY_HAS_ITEM((BezTriple *)point, nu->bezt, nu->pntsu); } else { - BPoint *bp = (BPoint *)point; - return bp >= nu->bp && bp < &nu->bp[nu->pntsu * nu->pntsv]; + return ARRAY_HAS_ITEM((BPoint *)point, nu->bp, nu->pntsu); } } @@ -5555,7 +5594,7 @@ static Nurb *get_lastsel_nurb(Curve *cu) return NULL; while (nu) { - if (point_on_nurb(nu, cu->lastsel)) + if (point_in_nurb(nu, cu->lastsel)) return nu; nu = nu->next; @@ -5574,7 +5613,7 @@ static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth) while (a--) { if (abs(start - a) % nth) { - select_beztriple(bezt, DESELECT, 1, HIDDEN); + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); } bezt--; @@ -5597,7 +5636,7 @@ static void select_nth_bp(Nurb *nu, BPoint *bp, int nth) while (a--) { dist = abs(pnt - startpnt) + abs(row - startrow); if (dist % nth) { - select_bpoint(bp, DESELECT, 1, HIDDEN); + select_bpoint(bp, DESELECT, SELECT, HIDDEN); } pnt--; @@ -5672,9 +5711,14 @@ void CURVE_OT_select_nth(wmOperatorType *ot) static int duplicate_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); + ListBase newnurb = {NULL, NULL}; - adduplicateflagNurb(obedit, 1); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + adduplicateflagNurb(obedit, &newnurb, SELECT, false); + + if (newnurb.first != NULL) { + BLI_movelisttolist(object_editcurve_get(obedit), &newnurb); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } return OPERATOR_FINISHED; } @@ -5696,37 +5740,31 @@ void CURVE_OT_duplicate(wmOperatorType *ot) /********************** delete operator *********************/ -static int delete_exec(bContext *C, wmOperator *op) +static int curve_delete_selected(Object *obedit, eCurveElem_Types type, const bool split) { - Object *obedit = CTX_data_edit_object(C); Curve *cu = obedit->data; EditNurb *editnurb = cu->editnurb; ListBase *nubase = &editnurb->nurbs; - Nurb *nu, *nu1; + Nurb *nu, *nu1, *startnu; BezTriple *bezt, *bezt1, *bezt2; BPoint *bp, *bp1, *bp2; - int a, cut = 0, type = RNA_enum_get(op->ptr, "type"); + int a, b, starta, enda, cut = 0; int nuindex = 0; + ListBase newnurb = {NULL, NULL}; if (obedit->type == OB_SURF) { - if (type == 0) { - deleteflagNurb(C, op, 1); + if (type == CURVE_VERTEX) { + return deleteflagNurb(obedit, SELECT); } else { keyIndex_delNurbList(editnurb, nubase); BKE_nurbList_free(nubase); - if (ED_curve_updateAnimPaths(obedit->data)) - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + return OPERATOR_FINISHED; } - - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); - - return OPERATOR_FINISHED; } - if (type == 0) { + if (type == CURVE_VERTEX) { /* first loop, can we remove entire pieces? */ Nurb *next; nu = nubase->first; @@ -5861,204 +5899,343 @@ static int delete_exec(bContext *C, wmOperator *op) nu = next; } } - else if (type == 1) { /* erase segment */ - /* find the 2 selected points */ - bezt1 = bezt2 = NULL; - bp1 = bp2 = NULL; - nu1 = NULL; - nuindex = 0; + else if (type == CURVE_SEGMENT) { for (nu = nubase->first; nu; nu = nu->next) { + startnu = nu1 = NULL; + starta = enda = cut = -1; + if (nu->type == CU_BEZIER) { - bezt = nu->bezt; - for (a = 0; a < nu->pntsu - 1; a++) { - if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) { - bezt1 = bezt; - bezt2 = bezt + 1; - if ((bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT)) { - /* pass */ + for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) { + if (!BEZSELECTED_HIDDENHANDLES(cu, bezt)) { + enda = a; + if (starta == -1) starta = a; + if (a < nu->pntsu - 1) continue; + } + else if (a < nu->pntsu - 1 && !BEZSELECTED_HIDDENHANDLES(cu, bezt + 1)) { + /* if just single selected point then continue */ + continue; + } + + if (starta >= 0) { + /* got selected segment, now check where and copy */ + if (starta <= 1 && a == nu->pntsu - 1) { + /* copying all points in spline */ + if (starta == 1 && enda != a) nu->flagu &= ~CU_NURB_CYCLIC; + + starta = 0; + enda = a; + cut = enda - starta + 1; + + nu1 = ED_curve_nurbcpy(nu, cut); + } + else if (starta == 0) { + /* if start of curve copy next end point */ + enda++; + cut = enda - starta + 1; + + bezt1 = &nu->bezt[nu->pntsu - 1]; + bezt2 = &nu->bezt[nu->pntsu - 2]; + + if ((nu->flagu & CU_NURB_CYCLIC) && + BEZSELECTED_HIDDENHANDLES(cu, bezt1) && + BEZSELECTED_HIDDENHANDLES(cu, bezt2)) + { + /* check if need to join start of spline to end */ + nu1 = ED_curve_nurbcpy(nu, cut + 1); + ED_curve_beztcpy(editnurb, &nu1->bezt[1], nu->bezt, cut); + starta = nu->pntsu - 1; + cut = 1; + } + else { + nu1 = ED_curve_nurbcpy(nu, cut); + + if (nu->flagu & CU_NURB_CYCLIC) startnu = nu1; + } } - else { /* maybe do not make cyclic */ - if (a == 0 && (nu->flagu & CU_NURB_CYCLIC)) { - bezt2 = bezt + (nu->pntsu - 1); - if ((bezt2->f1 & SELECT) || (bezt2->f2 & SELECT) || (bezt2->f3 & SELECT)) { - nu->flagu &= ~CU_NURB_CYCLIC; - BKE_nurb_handles_calc(nu); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); + else if (enda == nu->pntsu - 1) { + /* if end of curve copy previous start point */ + starta--; + cut = enda - starta + 1; + + bezt1 = nu->bezt; + bezt2 = &nu->bezt[1]; + + if ((nu->flagu & CU_NURB_CYCLIC) && + BEZSELECTED_HIDDENHANDLES(cu, bezt1) && + BEZSELECTED_HIDDENHANDLES(cu, bezt2)) + { + /* check if need to join start of spline to end */ + nu1 = ED_curve_nurbcpy(nu, cut + 1); + ED_curve_beztcpy(editnurb, &nu1->bezt[cut], nu->bezt, 1); + } + else if (startnu != NULL) { + /* if startnu exists it is a cyclic spline, start and end should be connected */ + bezt1 = (BezTriple *)MEM_mallocN((cut + startnu->pntsu) * sizeof(BezTriple), "delNurb3"); + ED_curve_beztcpy(editnurb, bezt1, &nu->bezt[starta], cut); + ED_curve_beztcpy(editnurb, &bezt1[cut], nu->bezt, startnu->pntsu); + + MEM_freeN(startnu->bezt); + startnu->bezt = bezt1; + startnu->pntsu += cut; + + if (split) { + for (b = 0; b < startnu->pntsu; b++, bezt1++) { + select_beztriple(bezt1, DESELECT, SELECT, true); + } } + + BKE_nurb_handles_calc(startnu); + } + else { + nu1 = ED_curve_nurbcpy(nu, cut); } + } + else { + /* mid spline selection, copy adjacent start and end */ + starta--; + enda++; + cut = enda - starta + 1; - return OPERATOR_FINISHED; + nu1 = ED_curve_nurbcpy(nu, cut); } - cut = a; - nu1 = nu; - break; + + if (nu1 != NULL) { + ED_curve_beztcpy(editnurb, nu1->bezt, &nu->bezt[starta], cut); + + if (starta != 0 || enda != nu->pntsu - 1) nu1->flagu &= ~CU_NURB_CYCLIC; + + if (split) { + /* deselect for split operator */ + for (b = 0, bezt1 = nu1->bezt; b < nu1->pntsu; b++, bezt1++) { + select_beztriple(bezt1, DESELECT, SELECT, true); + } + } + + BLI_addtail(&newnurb, nu1); + BKE_nurb_handles_calc(nu1); + nu1 = NULL; + } + starta = enda = -1; + } + } + + if (!split && cut != -1 && nu->pntsu > 2 && !(nu->flagu & CU_NURB_CYCLIC)) { + /* start and points copied if connecting segment was deleted and not cylic spline */ + bezt1 = nu->bezt; + bezt2 = &nu->bezt[1]; + if (BEZSELECTED_HIDDENHANDLES(cu, bezt1) && BEZSELECTED_HIDDENHANDLES(cu, bezt2)) { + nu1 = ED_curve_nurbcpy(nu, 1); + ED_curve_beztcpy(editnurb, nu1->bezt, bezt1, 1); + BLI_addtail(&newnurb, nu1); + } + + bezt1 = &nu->bezt[nu->pntsu - 1]; + bezt2 = &nu->bezt[nu->pntsu - 2]; + if (BEZSELECTED_HIDDENHANDLES(cu, bezt1) && BEZSELECTED_HIDDENHANDLES(cu, bezt2)) { + nu1 = ED_curve_nurbcpy(nu, 1); + ED_curve_beztcpy(editnurb, nu1->bezt, bezt1, 1); + BLI_addtail(&newnurb, nu1); } - bezt++; } } else if (nu->pntsv == 1) { - bp = nu->bp; - for (a = 0; a < nu->pntsu - 1; a++) { - if (bp->f1 & SELECT) { - bp1 = bp; - bp2 = bp + 1; - if (bp2->f1 & SELECT) { - /* pass */ + for (a = 0, bp = nu->bp; a < nu->pntsu; a++, bp++) { + if (!(bp->f1 & SELECT)) { + enda = a; + if (starta == -1) starta = a; + if (a < nu->pntsu - 1) continue; + } + else if (a < nu->pntsu - 1 && !((bp + 1)->f1 & SELECT)) { + /* if just single selected point then continue */ + continue; + } + + if (starta >= 0) { + /* got selected segment, now check where and copy */ + if (starta <= 1 && a == nu->pntsu - 1) { + /* copying all points in spline */ + if (starta == 1 && enda != a) nu->flagu &= ~CU_NURB_CYCLIC; + + starta = 0; + enda = a; + cut = enda - starta + 1; + + nu1 = ED_curve_nurbcpy(nu, cut); + } + else if (starta == 0) { + /* if start of curve copy next end point */ + enda++; + cut = enda - starta + 1; + + bp1 = &nu->bp[nu->pntsu - 1]; + bp2 = &nu->bp[nu->pntsu - 2]; + + if ((nu->flagu & CU_NURB_CYCLIC) && (bp1->f1 & SELECT) && (bp2->f1 & SELECT)) { + /* check if need to join start of spline to end */ + nu1 = ED_curve_nurbcpy(nu, cut + 1); + ED_curve_bpcpy(editnurb, &nu1->bp[1], nu->bp, cut); + starta = nu->pntsu - 1; + cut = 1; + } + else { + nu1 = ED_curve_nurbcpy(nu, cut); + + if (nu->flagu & CU_NURB_CYCLIC) startnu = nu1; + } } - else { /* maybe do not make cyclic */ - if (a == 0 && (nu->flagu & CU_NURB_CYCLIC)) { - bp2 = bp + (nu->pntsu - 1); - if (bp2->f1 & SELECT) { - nu->flagu &= ~CU_NURB_CYCLIC; - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); + else if (enda == nu->pntsu - 1) { + /* if end of curve copy previous start point */ + starta--; + cut = enda - starta + 1; + + bp1 = nu->bp; + bp2 = &nu->bp[1]; + + if ((nu->flagu & CU_NURB_CYCLIC) && (bp1->f1 & SELECT) && (bp2->f1 & SELECT)) { + /* check if need to join start of spline to end */ + nu1 = ED_curve_nurbcpy(nu, cut + 1); + ED_curve_bpcpy(editnurb, &nu1->bp[cut], nu->bp, 1); + } + else if (startnu != NULL) { + /* if startnu exists it is a cyclic spline, start and end should be connected */ + bp1 = (BPoint *)MEM_mallocN((cut + startnu->pntsu) * sizeof(BPoint), "delNurb4"); + ED_curve_bpcpy(editnurb, bp1, &nu->bp[starta], cut); + ED_curve_bpcpy(editnurb, &bp1[cut], nu->bp, startnu->pntsu); + + MEM_freeN(startnu->bp); + startnu->bp = bp1; + startnu->pntsu += cut; + + if (split) { + for (b = 0; b < startnu->pntsu; b++, bp1++) { + select_bpoint(bp1, DESELECT, SELECT, HIDDEN); + } } + + BKE_nurb_order_clamp_u(startnu); + BKE_nurb_knot_calc_u(startnu); + } + else { + nu1 = ED_curve_nurbcpy(nu, cut); } + } + else { + /* mid spline selection, copy adjacent start and end */ + starta--; + enda++; + cut = enda - starta + 1; - return OPERATOR_FINISHED; + nu1 = ED_curve_nurbcpy(nu, cut); } - cut = a; - nu1 = nu; - break; - } - bp++; - } - } - if (nu1) break; - nuindex++; - } - if (nu1) { - if (bezt1) { - if (nu1->pntsu == 2) { /* remove completely */ - if (cu->actnu == nuindex) - cu->actnu = -1; - BLI_remlink(nubase, nu); - BKE_nurb_free(nu); nu = NULL; - } - else if (nu1->flagu & CU_NURB_CYCLIC) { /* cyclic */ - bezt = (BezTriple *)MEM_mallocN((cut + 1) * sizeof(BezTriple), "delNurb1"); - ED_curve_beztcpy(editnurb, bezt, nu1->bezt, cut + 1); - a = nu1->pntsu - cut - 1; - ED_curve_beztcpy(editnurb, nu1->bezt, bezt2, a); - ED_curve_beztcpy(editnurb, &nu1->bezt[a], bezt, cut + 1); + if (nu1 != NULL) { + ED_curve_bpcpy(editnurb, nu1->bp, &nu->bp[starta], cut); - nu1->flagu &= ~CU_NURB_CYCLIC; - MEM_freeN(bezt); - BKE_nurb_handles_calc(nu); - } - else { /* add new curve */ + if (starta != 0 || enda != nu->pntsu - 1) nu1->flagu &= ~CU_NURB_CYCLIC; -/* seems to be an error here... but where? (a can become zero) */ + if (split) { + /* deselect for split operator */ + for (b = 0, bp1 = nu1->bp; b < nu1->pntsu; b++, bp1++) { + select_bpoint(bp1, DESELECT, SELECT, HIDDEN); + } + } - nu = (Nurb *)MEM_mallocN(sizeof(Nurb), "delNurb2"); - memcpy(nu, nu1, sizeof(Nurb)); - BLI_addtail(nubase, nu); - nu->bezt = (BezTriple *)MEM_mallocN((cut + 1) * sizeof(BezTriple), "delNurb3"); - ED_curve_beztcpy(editnurb, nu->bezt, nu1->bezt, cut + 1); - a = nu1->pntsu - cut - 1; + BLI_addtail(&newnurb, nu1); + nu1->knotsu = NULL; + BKE_nurb_order_clamp_u(nu1); + BKE_nurb_knot_calc_u(nu1); + nu1 = NULL; + } + starta = enda = -1; + } + } - bezt = (BezTriple *)MEM_mallocN(a * sizeof(BezTriple), "delNurb4"); - ED_curve_beztcpy(editnurb, bezt, &nu1->bezt[cut + 1], a); - MEM_freeN(nu1->bezt); - nu1->bezt = bezt; - nu1->pntsu = a; - nu->pntsu = cut + 1; - - - BKE_nurb_handles_calc(nu); - BKE_nurb_handles_calc(nu1); - } - } - else if (bp1) { - if (nu1->pntsu == 2) { /* remove completely */ - if (cu->actnu == nuindex) - cu->actnu = -1; - - BLI_remlink(nubase, nu); - BKE_nurb_free(nu); nu = NULL; - } - else if (nu1->flagu & CU_NURB_CYCLIC) { /* cyclic */ - bp = (BPoint *)MEM_mallocN((cut + 1) * sizeof(BPoint), "delNurb5"); - ED_curve_bpcpy(editnurb, bp, nu1->bp, cut + 1); - a = nu1->pntsu - cut - 1; - ED_curve_bpcpy(editnurb, nu1->bp, bp2, a); - ED_curve_bpcpy(editnurb, &nu1->bp[a], bp, cut + 1); - - nu1->flagu &= ~CU_NURB_CYCLIC; - MEM_freeN(bp); - } - else { /* add new curve */ - nu = (Nurb *)MEM_mallocN(sizeof(Nurb), "delNurb6"); - memcpy(nu, nu1, sizeof(Nurb)); - BLI_addtail(nubase, nu); - nu->bp = (BPoint *)MEM_mallocN((cut + 1) * sizeof(BPoint), "delNurb7"); - ED_curve_bpcpy(editnurb, nu->bp, nu1->bp, cut + 1); - a = nu1->pntsu - cut - 1; - bp = (BPoint *)MEM_mallocN(a * sizeof(BPoint), "delNurb8"); - ED_curve_bpcpy(editnurb, bp, &nu1->bp[cut + 1], a); - MEM_freeN(nu1->bp); - nu1->bp = bp; - nu1->pntsu = a; - nu1->knotsu = NULL; - nu->pntsu = cut + 1; - - BKE_nurb_order_clamp_u(nu); - BKE_nurb_knot_calc_u(nu); + if (!split && cut != -1 && nu->pntsu > 2 && !(nu->flagu & CU_NURB_CYCLIC)) { + /* start and points copied if connecting segment was deleted and not cylic spline */ + bp1 = nu->bp; + bp2 = &nu->bp[1]; + if ((bp1->f1 & SELECT) && (bp2->f1 & SELECT)) { + nu1 = ED_curve_nurbcpy(nu, 1); + ED_curve_bpcpy(editnurb, nu1->bp, bp1, 1); + BLI_addtail(&newnurb, nu1); + nu1->knotsu = NULL; + } - BKE_nurb_order_clamp_u(nu1); - BKE_nurb_knot_calc_u(nu1); + bp1 = &nu->bp[nu->pntsu - 1]; + bp2 = &nu->bp[nu->pntsu - 2]; + if ((bp1->f1 & SELECT) && (bp2->f1 & SELECT)) { + nu1 = ED_curve_nurbcpy(nu, 1); + ED_curve_bpcpy(editnurb, nu1->bp, bp1, 1); + BLI_addtail(&newnurb, nu1); + nu1->knotsu = NULL; + } } } } - } - else if (type == 2) { - cu->actnu = -1; - keyIndex_delNurbList(editnurb, nubase); + BKE_nurbList_free(nubase); + BLI_movelisttolist(nubase, &newnurb); + } + else { + BLI_assert(0); } - if (ED_curve_updateAnimPaths(obedit->data)) - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); - - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); - return OPERATOR_FINISHED; } -static int delete_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int curve_delete_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); - uiPopupMenu *pup; - uiLayout *layout; + eCurveElem_Types type = RNA_enum_get(op->ptr, "type"); + int retval = curve_delete_selected(obedit, type, false); + + if (retval == OPERATOR_FINISHED) { + if (ED_curve_updateAnimPaths(obedit->data)) WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DAG_id_tag_update(obedit->data, 0); + + return retval; + } + + return retval; +} + +static EnumPropertyItem curve_delete_type_items[] = { + {CURVE_VERTEX, "VERT", 0, "Vertices", ""}, + {CURVE_SEGMENT, "SEGMENT", 0, "Segments", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem *rna_curve_delete_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), int *free) +{ + Object *obedit; + EnumPropertyItem *item = NULL; + int totitem = 0; + + + if (!C) /* needed for docs and i18n tools */ + return curve_delete_type_items; + + obedit = CTX_data_edit_object(C); if (obedit->type == OB_SURF) { - pup = uiPupMenuBegin(C, IFACE_("Delete"), ICON_NONE); - layout = uiPupMenuLayout(pup); - uiItemEnumO_ptr(layout, op->type, NULL, 0, "type", 0); - uiItemEnumO_ptr(layout, op->type, NULL, 0, "type", 2); - uiPupMenuEnd(C, pup); + RNA_enum_items_add_value(&item, &totitem, curve_delete_type_items, CURVE_VERTEX); } else { - pup = uiPupMenuBegin(C, IFACE_("Delete"), ICON_NONE); - layout = uiPupMenuLayout(pup); - uiItemsEnumO(layout, op->type->idname, "type"); - uiPupMenuEnd(C, pup); + RNA_enum_items_add_value(&item, &totitem, curve_delete_type_items, CURVE_VERTEX); + RNA_enum_items_add_value(&item, &totitem, curve_delete_type_items, CURVE_SEGMENT); } - return OPERATOR_CANCELLED; + RNA_enum_item_end(&item, &totitem); + *free = true; + + return item; } void CURVE_OT_delete(wmOperatorType *ot) { - static EnumPropertyItem type_items[] = { - {0, "SELECTED", 0, "Select", ""}, - {1, "SEGMENT", 0, "Segment", ""}, - {2, "ALL", 0, "All", ""}, - {0, NULL, 0, NULL, NULL} - }; + PropertyRNA *prop; /* identifiers */ ot->name = "Delete"; @@ -6066,15 +6243,18 @@ void CURVE_OT_delete(wmOperatorType *ot) ot->idname = "CURVE_OT_delete"; /* api callbacks */ - ot->exec = delete_exec; - ot->invoke = delete_invoke; + ot->exec = curve_delete_exec; + ot->invoke = WM_menu_invoke; ot->poll = ED_operator_editsurfcurve; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Which elements to delete"); + prop = RNA_def_enum(ot->srna, "type", curve_delete_type_items, 0, "Type", "Which elements to delete"); + RNA_def_enum_funcs(prop, rna_curve_delete_type_itemf); + + ot->prop = prop; } /********************** shade smooth/flat operator *********************/ @@ -6230,729 +6410,6 @@ int join_curve_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -/************ add primitive, used by object/ module ****************/ - -static const char *get_curve_defname(int type) -{ - int stype = type & CU_PRIMITIVE; - - if ((type & CU_TYPE) == CU_BEZIER) { - switch (stype) { - case CU_PRIM_CURVE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "BezierCurve"); - case CU_PRIM_CIRCLE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "BezierCircle"); - case CU_PRIM_PATH: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "CurvePath"); - default: - return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "Curve"); - } - } - else { - switch (stype) { - case CU_PRIM_CURVE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "NurbsCurve"); - case CU_PRIM_CIRCLE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "NurbsCircle"); - case CU_PRIM_PATH: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "NurbsPath"); - default: - return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "Curve"); - } - } -} - -static const char *get_surf_defname(int type) -{ - int stype = type & CU_PRIMITIVE; - - switch (stype) { - case CU_PRIM_CURVE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfCurve"); - case CU_PRIM_CIRCLE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfCircle"); - case CU_PRIM_PATCH: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfPatch"); - case CU_PRIM_SPHERE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfSphere"); - case CU_PRIM_DONUT: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfTorus"); - default: - return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "Surface"); - } -} - - -Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type, int newob) -{ - static int xzproj = 0; /* this function calls itself... */ - ListBase *editnurb = object_editcurve_get(obedit); - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = ED_view3d_context_rv3d(C); - Nurb *nu = NULL; - BezTriple *bezt; - BPoint *bp; - Curve *cu = (Curve *)obedit->data; - float vec[3], zvec[3] = {0.0f, 0.0f, 1.0f}; - float umat[4][4] = MAT4_UNITY, viewmat[4][4] = MAT4_UNITY; - float fac; - int a, b; - const float grid = v3d ? v3d->grid : 1.0f; - const int cutype = (type & CU_TYPE); // poly, bezier, nurbs, etc - const int stype = (type & CU_PRIMITIVE); - const int force_3d = ((Curve *)obedit->data)->flag & CU_3D; /* could be adding to an existing 3D curve */ - - if (rv3d) { - copy_m4_m4(viewmat, rv3d->viewmat); - copy_v3_v3(zvec, rv3d->viewinv[2]); - } - - setflagsNurb(editnurb, 0); - - /* these types call this function to return a Nurb */ - if (stype != CU_PRIM_TUBE && stype != CU_PRIM_DONUT) { - nu = (Nurb *)MEM_callocN(sizeof(Nurb), "addNurbprim"); - nu->type = cutype; - nu->resolu = cu->resolu; - nu->resolv = cu->resolv; - } - - switch (stype) { - case CU_PRIM_CURVE: /* curve */ - nu->resolu = cu->resolu; - if (cutype == CU_BEZIER) { - if (!force_3d) nu->flag |= CU_2D; - nu->pntsu = 2; - nu->bezt = (BezTriple *)MEM_callocN(2 * sizeof(BezTriple), "addNurbprim1"); - bezt = nu->bezt; - bezt->h1 = bezt->h2 = HD_ALIGN; - bezt->f1 = bezt->f2 = bezt->f3 = SELECT; - bezt->radius = 1.0; - - bezt->vec[1][0] += -grid; - bezt->vec[0][0] += -1.5f * grid; - bezt->vec[0][1] += -0.5f * grid; - bezt->vec[2][0] += -0.5f * grid; - bezt->vec[2][1] += 0.5f * grid; - for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); - - bezt++; - bezt->h1 = bezt->h2 = HD_ALIGN; - bezt->f1 = bezt->f2 = bezt->f3 = SELECT; - bezt->radius = bezt->weight = 1.0; - - bezt->vec[0][0] = 0; - bezt->vec[0][1] = 0; - bezt->vec[1][0] = grid; - bezt->vec[1][1] = 0; - bezt->vec[2][0] = grid * 2; - bezt->vec[2][1] = 0; - for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); - - BKE_nurb_handles_calc(nu); - } - else { - - nu->pntsu = 4; - nu->pntsv = 1; - nu->orderu = 4; - nu->bp = CALLOC_STRUCT_N(BPoint, 4, "addNurbprim3"); - - bp = nu->bp; - for (a = 0; a < 4; a++, bp++) { - bp->vec[3] = 1.0; - bp->f1 = SELECT; - bp->radius = bp->weight = 1.0; - } - - bp = nu->bp; - bp->vec[0] += -1.5f * grid; - bp++; - bp->vec[0] += -grid; - bp->vec[1] += grid; - bp++; - bp->vec[0] += grid; - bp->vec[1] += grid; - bp++; - bp->vec[0] += 1.5f * grid; - - bp = nu->bp; - for (a = 0; a < 4; a++, bp++) mul_m4_v3(mat, bp->vec); - - if (cutype == CU_NURBS) { - nu->knotsu = NULL; /* nurbs_knot_calc_u allocates */ - BKE_nurb_knot_calc_u(nu); - } - - } - break; - case CU_PRIM_PATH: /* 5 point path */ - nu->pntsu = 5; - nu->pntsv = 1; - nu->orderu = 5; - nu->flagu = CU_NURB_ENDPOINT; /* endpoint */ - nu->resolu = cu->resolu; - nu->bp = CALLOC_STRUCT_N(BPoint, 5, "addNurbprim3"); - - bp = nu->bp; - for (a = 0; a < 5; a++, bp++) { - bp->vec[3] = 1.0; - bp->f1 = SELECT; - bp->radius = bp->weight = 1.0; - } - - bp = nu->bp; - bp->vec[0] += -2.0f * grid; - bp++; - bp->vec[0] += -grid; - bp++; bp++; - bp->vec[0] += grid; - bp++; - bp->vec[0] += 2.0f * grid; - - bp = nu->bp; - for (a = 0; a < 5; a++, bp++) mul_m4_v3(mat, bp->vec); - - if (cutype == CU_NURBS) { - nu->knotsu = NULL; /* nurbs_knot_calc_u allocates */ - BKE_nurb_knot_calc_u(nu); - } - - break; - case CU_PRIM_CIRCLE: /* circle */ - nu->resolu = cu->resolu; - - if (cutype == CU_BEZIER) { - if (!force_3d) nu->flag |= CU_2D; - nu->pntsu = 4; - nu->bezt = CALLOC_STRUCT_N(BezTriple, 4, "addNurbprim1"); - nu->flagu = CU_NURB_CYCLIC; - bezt = nu->bezt; - - bezt->h1 = bezt->h2 = HD_AUTO; - bezt->f1 = bezt->f2 = bezt->f3 = SELECT; - bezt->vec[1][0] += -grid; - for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); - bezt->radius = bezt->weight = 1.0; - - bezt++; - bezt->h1 = bezt->h2 = HD_AUTO; - bezt->f1 = bezt->f2 = bezt->f3 = SELECT; - bezt->vec[1][1] += grid; - for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); - bezt->radius = bezt->weight = 1.0; - - bezt++; - bezt->h1 = bezt->h2 = HD_AUTO; - bezt->f1 = bezt->f2 = bezt->f3 = SELECT; - bezt->vec[1][0] += grid; - for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); - bezt->radius = bezt->weight = 1.0; - - bezt++; - bezt->h1 = bezt->h2 = HD_AUTO; - bezt->f1 = bezt->f2 = bezt->f3 = SELECT; - bezt->vec[1][1] += -grid; - for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); - bezt->radius = bezt->weight = 1.0; - - BKE_nurb_handles_calc(nu); - } - else if (cutype == CU_NURBS) { /* nurb */ - nu->pntsu = 8; - nu->pntsv = 1; - nu->orderu = 4; - nu->bp = CALLOC_STRUCT_N(BPoint, 8, "addNurbprim6"); - nu->flagu = CU_NURB_CYCLIC; - bp = nu->bp; - - for (a = 0; a < 8; a++) { - bp->f1 = SELECT; - if (xzproj == 0) { - bp->vec[0] += nurbcircle[a][0] * grid; - bp->vec[1] += nurbcircle[a][1] * grid; - } - else { - bp->vec[0] += 0.25f * nurbcircle[a][0] * grid - 0.75f * grid; - bp->vec[2] += 0.25f * nurbcircle[a][1] * grid; - } - if (a & 1) bp->vec[3] = 0.25 * M_SQRT2; - else bp->vec[3] = 1.0; - mul_m4_v3(mat, bp->vec); - bp->radius = bp->weight = 1.0; - - bp++; - } - - BKE_nurb_knot_calc_u(nu); - } - break; - case CU_PRIM_PATCH: /* 4x4 patch */ - if (cutype == CU_NURBS) { /* nurb */ - - nu->pntsu = 4; - nu->pntsv = 4; - nu->orderu = 4; - nu->orderv = 4; - nu->flag = CU_SMOOTH; - nu->bp = CALLOC_STRUCT_N(BPoint, 4 * 4, "addNurbprim6"); - nu->flagu = 0; - nu->flagv = 0; - bp = nu->bp; - - for (a = 0; a < 4; a++) { - for (b = 0; b < 4; b++) { - bp->f1 = SELECT; - fac = (float)a - 1.5f; - bp->vec[0] += fac * grid; - fac = (float)b - 1.5f; - bp->vec[1] += fac * grid; - if ((a == 1 || a == 2) && (b == 1 || b == 2)) { - bp->vec[2] += grid; - } - mul_m4_v3(mat, bp->vec); - bp->vec[3] = 1.0; - bp++; - } - } - - BKE_nurb_knot_calc_u(nu); - BKE_nurb_knot_calc_v(nu); - } - break; - case CU_PRIM_TUBE: /* Cylinder */ - if (cutype == CU_NURBS) { - nu = add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */ - nu->resolu = cu->resolu; - nu->flag = CU_SMOOTH; - BLI_addtail(editnurb, nu); /* temporal for extrude and translate */ - vec[0] = vec[1] = 0.0; - vec[2] = -grid; - - mul_mat3_m4_v3(mat, vec); - - translateflagNurb(editnurb, 1, vec); - extrudeflagNurb(cu->editnurb, 1); - mul_v3_fl(vec, -2.0f); - translateflagNurb(editnurb, 1, vec); - - BLI_remlink(editnurb, nu); - - a = nu->pntsu * nu->pntsv; - bp = nu->bp; - while (a-- > 0) { - bp->f1 |= SELECT; - bp++; - } - } - break; - case CU_PRIM_SPHERE: /* sphere */ - if (cutype == CU_NURBS) { - float tmp_cent[3] = {0.f, 0.f, 0.f}; - float tmp_vec[3] = {0.f, 0.f, 1.f}; - - nu->pntsu = 5; - nu->pntsv = 1; - nu->orderu = 3; - nu->resolu = cu->resolu; - nu->resolv = cu->resolv; - nu->flag = CU_SMOOTH; - nu->bp = CALLOC_STRUCT_N(BPoint, 5, "addNurbprim6"); - nu->flagu = 0; - bp = nu->bp; - - for (a = 0; a < 5; a++) { - bp->f1 = SELECT; - bp->vec[0] += nurbcircle[a][0] * grid; - bp->vec[2] += nurbcircle[a][1] * grid; - if (a & 1) bp->vec[3] = 0.5 * M_SQRT2; - else bp->vec[3] = 1.0; - mul_m4_v3(mat, bp->vec); - bp++; - } - nu->flagu = CU_NURB_BEZIER; - BKE_nurb_knot_calc_u(nu); - - BLI_addtail(editnurb, nu); /* temporal for spin */ - - if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0) spin_nurb(umat, obedit, tmp_vec, tmp_cent); - else if ((U.flag & USER_ADD_VIEWALIGNED)) spin_nurb(viewmat, obedit, zvec, mat[3]); - else spin_nurb(umat, obedit, tmp_vec, mat[3]); - - BKE_nurb_knot_calc_v(nu); - - a = nu->pntsu * nu->pntsv; - bp = nu->bp; - while (a-- > 0) { - bp->f1 |= SELECT; - bp++; - } - BLI_remlink(editnurb, nu); - } - break; - case CU_PRIM_DONUT: /* torus */ - if (cutype == CU_NURBS) { - float tmp_cent[3] = {0.f, 0.f, 0.f}; - float tmp_vec[3] = {0.f, 0.f, 1.f}; - - xzproj = 1; - nu = add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */ - xzproj = 0; - nu->resolu = cu->resolu; - nu->resolv = cu->resolv; - nu->flag = CU_SMOOTH; - BLI_addtail(editnurb, nu); /* temporal for spin */ - - /* same as above */ - if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0) spin_nurb(umat, obedit, tmp_vec, tmp_cent); - else if ((U.flag & USER_ADD_VIEWALIGNED)) spin_nurb(viewmat, obedit, zvec, mat[3]); - else spin_nurb(umat, obedit, tmp_vec, mat[3]); - - - BLI_remlink(editnurb, nu); - - a = nu->pntsu * nu->pntsv; - bp = nu->bp; - while (a-- > 0) { - bp->f1 |= SELECT; - bp++; - } - - } - break; - - default: /* should never happen */ - BLI_assert(!"invalid nurbs type"); - return NULL; - } - - BLI_assert(nu != NULL); - - if (nu) { /* should always be set */ - nu->flag |= CU_SMOOTH; - - BKE_nurb_test2D(nu); - } - - return nu; -} - -static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf) -{ - Object *obedit = CTX_data_edit_object(C); - ListBase *editnurb; - Nurb *nu; - bool newob = false; - bool enter_editmode, is_view_aligned; - unsigned int layer; - float loc[3], rot[3]; - float mat[4][4]; - - if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, &is_view_aligned)) - return OPERATOR_CANCELLED; - - if (!isSurf) { /* adding curve */ - if (obedit == NULL || obedit->type != OB_CURVE) { - Curve *cu; - - obedit = ED_object_add_type(C, OB_CURVE, loc, rot, TRUE, layer); - newob = true; - - cu = (Curve *)obedit->data; - cu->flag |= CU_DEFORM_FILL; - - if (type & CU_PRIM_PATH) - cu->flag |= CU_PATH | CU_3D; - } - else { - DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); - } - } - else { /* adding surface */ - if (obedit == NULL || obedit->type != OB_SURF) { - obedit = ED_object_add_type(C, OB_SURF, loc, rot, TRUE, layer); - newob = true; - } - else { - DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); - } - } - - /* rename here, the undo stack checks name for valid undo pushes */ - if (newob) { - if (obedit->type == OB_CURVE) { - rename_id((ID *)obedit, get_curve_defname(type)); - rename_id((ID *)obedit->data, get_curve_defname(type)); - } - else { - rename_id((ID *)obedit, get_surf_defname(type)); - rename_id((ID *)obedit->data, get_surf_defname(type)); - } - } - - /* ED_object_add_type doesnt do an undo, is needed for redo operator on primitive */ - if (newob && enter_editmode) - ED_undo_push(C, "Enter Editmode"); - - ED_object_new_primitive_matrix(C, obedit, loc, rot, mat, TRUE); - - nu = add_nurbs_primitive(C, obedit, mat, type, newob); - editnurb = object_editcurve_get(obedit); - BLI_addtail(editnurb, nu); - - /* userdef */ - if (newob && !enter_editmode) { - ED_object_editmode_exit(C, EM_FREEDATA); - } - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); - - return OPERATOR_FINISHED; -} - -static int curve_prim_add(bContext *C, wmOperator *op, int type) -{ - return curvesurf_prim_add(C, op, type, 0); -} - -static int surf_prim_add(bContext *C, wmOperator *op, int type) -{ - return curvesurf_prim_add(C, op, type, 1); -} - -/* ******************** Curves ******************* */ - -static int add_primitive_bezier_exec(bContext *C, wmOperator *op) -{ - return curve_prim_add(C, op, CU_BEZIER | CU_PRIM_CURVE); -} - -void CURVE_OT_primitive_bezier_curve_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Bezier"; - ot->description = "Construct a Bezier Curve"; - ot->idname = "CURVE_OT_primitive_bezier_curve_add"; - - /* api callbacks */ - ot->exec = add_primitive_bezier_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_bezier_circle_exec(bContext *C, wmOperator *op) -{ - return curve_prim_add(C, op, CU_BEZIER | CU_PRIM_CIRCLE); -} - -void CURVE_OT_primitive_bezier_circle_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Bezier Circle"; - ot->description = "Construct a Bezier Circle"; - ot->idname = "CURVE_OT_primitive_bezier_circle_add"; - - /* api callbacks */ - ot->exec = add_primitive_bezier_circle_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_nurbs_curve_exec(bContext *C, wmOperator *op) -{ - return curve_prim_add(C, op, CU_NURBS | CU_PRIM_CURVE); -} - -void CURVE_OT_primitive_nurbs_curve_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Nurbs Curve"; - ot->description = "Construct a Nurbs Curve"; - ot->idname = "CURVE_OT_primitive_nurbs_curve_add"; - - /* api callbacks */ - ot->exec = add_primitive_nurbs_curve_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_nurbs_circle_exec(bContext *C, wmOperator *op) -{ - return curve_prim_add(C, op, CU_NURBS | CU_PRIM_CIRCLE); -} - -void CURVE_OT_primitive_nurbs_circle_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Nurbs Circle"; - ot->description = "Construct a Nurbs Circle"; - ot->idname = "CURVE_OT_primitive_nurbs_circle_add"; - - /* api callbacks */ - ot->exec = add_primitive_nurbs_circle_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_curve_path_exec(bContext *C, wmOperator *op) -{ - return curve_prim_add(C, op, CU_NURBS | CU_PRIM_PATH); -} - -void CURVE_OT_primitive_nurbs_path_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Path"; - ot->description = "Construct a Path"; - ot->idname = "CURVE_OT_primitive_nurbs_path_add"; - - /* api callbacks */ - ot->exec = add_primitive_curve_path_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - -/* **************** NURBS surfaces ********************** */ -static int add_primitive_nurbs_surface_curve_exec(bContext *C, wmOperator *op) -{ - return surf_prim_add(C, op, CU_PRIM_CURVE | CU_NURBS); -} - -void SURFACE_OT_primitive_nurbs_surface_curve_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Surface Curve"; - ot->description = "Construct a Nurbs surface Curve"; - ot->idname = "SURFACE_OT_primitive_nurbs_surface_curve_add"; - - /* api callbacks */ - ot->exec = add_primitive_nurbs_surface_curve_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_nurbs_surface_circle_exec(bContext *C, wmOperator *op) -{ - return surf_prim_add(C, op, CU_PRIM_CIRCLE | CU_NURBS); -} - -void SURFACE_OT_primitive_nurbs_surface_circle_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Surface Circle"; - ot->description = "Construct a Nurbs surface Circle"; - ot->idname = "SURFACE_OT_primitive_nurbs_surface_circle_add"; - - /* api callbacks */ - ot->exec = add_primitive_nurbs_surface_circle_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_nurbs_surface_surface_exec(bContext *C, wmOperator *op) -{ - return surf_prim_add(C, op, CU_PRIM_PATCH | CU_NURBS); -} - -void SURFACE_OT_primitive_nurbs_surface_surface_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Surface Patch"; - ot->description = "Construct a Nurbs surface Patch"; - ot->idname = "SURFACE_OT_primitive_nurbs_surface_surface_add"; - - /* api callbacks */ - ot->exec = add_primitive_nurbs_surface_surface_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_nurbs_surface_cylinder_exec(bContext *C, wmOperator *op) -{ - return surf_prim_add(C, op, CU_PRIM_TUBE | CU_NURBS); -} - -void SURFACE_OT_primitive_nurbs_surface_cylinder_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Surface Cylinder"; - ot->description = "Construct a Nurbs surface Cylinder"; - ot->idname = "SURFACE_OT_primitive_nurbs_surface_cylinder_add"; - - /* api callbacks */ - ot->exec = add_primitive_nurbs_surface_cylinder_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_nurbs_surface_sphere_exec(bContext *C, wmOperator *op) -{ - return surf_prim_add(C, op, CU_PRIM_SPHERE | CU_NURBS); -} - -void SURFACE_OT_primitive_nurbs_surface_sphere_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Surface Sphere"; - ot->description = "Construct a Nurbs surface Sphere"; - ot->idname = "SURFACE_OT_primitive_nurbs_surface_sphere_add"; - - /* api callbacks */ - ot->exec = add_primitive_nurbs_surface_sphere_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_nurbs_surface_torus_exec(bContext *C, wmOperator *op) -{ - return surf_prim_add(C, op, CU_PRIM_DONUT | CU_NURBS); -} - -void SURFACE_OT_primitive_nurbs_surface_torus_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Surface Torus"; - ot->description = "Construct a Nurbs surface Torus"; - ot->idname = "SURFACE_OT_primitive_nurbs_surface_torus_add"; - - /* api callbacks */ - ot->exec = add_primitive_nurbs_surface_torus_exec; - ot->poll = ED_operator_scene_editable; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} /***************** clear tilt operator ********************/ @@ -7158,6 +6615,22 @@ void ED_curve_bpcpy(EditNurb *editnurb, BPoint *dst, BPoint *src, int count) keyIndex_updateBP(editnurb, src, dst, count); } +Nurb *ED_curve_nurbcpy(Nurb *src, int count) +{ + Nurb *newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "copyNurb"); + memcpy(newnu, src, sizeof(Nurb)); + newnu->pntsu = count; + + if (src->bezt) { + newnu->bezt = (BezTriple *)MEM_mallocN(count * sizeof(BezTriple), "copyNurb2"); + } + else { + newnu->bp = (BPoint *)MEM_mallocN(count * sizeof(BPoint), "copyNurb3"); + } + + return newnu; +} + int ED_curve_actSelection(Curve *cu, float center[3]) { Nurb *nu = get_lastsel_nurb(cu); diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c new file mode 100644 index 00000000000..0bcb550b930 --- /dev/null +++ b/source/blender/editors/curve/editcurve_add.c @@ -0,0 +1,812 @@ +/* + * ***** 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/curve/editcurve_add.c + * \ingroup edcurve + */ + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_anim_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" + +#include "BLF_translation.h" + +#include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_depsgraph.h" +#include "BKE_library.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_util.h" +#include "ED_view3d.h" +#include "ED_curve.h" + +#include "curve_intern.h" + +static float nurbcircle[8][2] = { + {0.0, -1.0}, {-1.0, -1.0}, {-1.0, 0.0}, {-1.0, 1.0}, + {0.0, 1.0}, { 1.0, 1.0}, { 1.0, 0.0}, { 1.0, -1.0} +}; + +/************ add primitive, used by object/ module ****************/ + +static const char *get_curve_defname(int type) +{ + int stype = type & CU_PRIMITIVE; + + if ((type & CU_TYPE) == CU_BEZIER) { + switch (stype) { + case CU_PRIM_CURVE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "BezierCurve"); + case CU_PRIM_CIRCLE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "BezierCircle"); + case CU_PRIM_PATH: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "CurvePath"); + default: + return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "Curve"); + } + } + else { + switch (stype) { + case CU_PRIM_CURVE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "NurbsCurve"); + case CU_PRIM_CIRCLE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "NurbsCircle"); + case CU_PRIM_PATH: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "NurbsPath"); + default: + return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "Curve"); + } + } +} + +static const char *get_surf_defname(int type) +{ + int stype = type & CU_PRIMITIVE; + + switch (stype) { + case CU_PRIM_CURVE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfCurve"); + case CU_PRIM_CIRCLE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfCircle"); + case CU_PRIM_PATCH: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfPatch"); + case CU_PRIM_SPHERE: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfSphere"); + case CU_PRIM_DONUT: return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "SurfTorus"); + default: + return CTX_DATA_(BLF_I18NCONTEXT_ID_CURVE, "Surface"); + } +} + + +Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type, int newob) +{ + static int xzproj = 0; /* this function calls itself... */ + ListBase *editnurb = object_editcurve_get(obedit); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = ED_view3d_context_rv3d(C); + Nurb *nu = NULL; + BezTriple *bezt; + BPoint *bp; + Curve *cu = (Curve *)obedit->data; + float vec[3], zvec[3] = {0.0f, 0.0f, 1.0f}; + float umat[4][4] = MAT4_UNITY, viewmat[4][4] = MAT4_UNITY; + float fac; + int a, b; + const float grid = v3d ? v3d->grid : 1.0f; + const int cutype = (type & CU_TYPE); // poly, bezier, nurbs, etc + const int stype = (type & CU_PRIMITIVE); + const int force_3d = ((Curve *)obedit->data)->flag & CU_3D; /* could be adding to an existing 3D curve */ + + if (rv3d) { + copy_m4_m4(viewmat, rv3d->viewmat); + copy_v3_v3(zvec, rv3d->viewinv[2]); + } + + BKE_nurbList_flag_set(editnurb, 0); + + /* these types call this function to return a Nurb */ + if (stype != CU_PRIM_TUBE && stype != CU_PRIM_DONUT) { + nu = (Nurb *)MEM_callocN(sizeof(Nurb), "addNurbprim"); + nu->type = cutype; + nu->resolu = cu->resolu; + nu->resolv = cu->resolv; + } + + switch (stype) { + case CU_PRIM_CURVE: /* curve */ + nu->resolu = cu->resolu; + if (cutype == CU_BEZIER) { + if (!force_3d) nu->flag |= CU_2D; + nu->pntsu = 2; + nu->bezt = (BezTriple *)MEM_callocN(2 * sizeof(BezTriple), "addNurbprim1"); + bezt = nu->bezt; + bezt->h1 = bezt->h2 = HD_ALIGN; + bezt->f1 = bezt->f2 = bezt->f3 = SELECT; + bezt->radius = 1.0; + + bezt->vec[1][0] += -grid; + bezt->vec[0][0] += -1.5f * grid; + bezt->vec[0][1] += -0.5f * grid; + bezt->vec[2][0] += -0.5f * grid; + bezt->vec[2][1] += 0.5f * grid; + for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); + + bezt++; + bezt->h1 = bezt->h2 = HD_ALIGN; + bezt->f1 = bezt->f2 = bezt->f3 = SELECT; + bezt->radius = bezt->weight = 1.0; + + bezt->vec[0][0] = 0; + bezt->vec[0][1] = 0; + bezt->vec[1][0] = grid; + bezt->vec[1][1] = 0; + bezt->vec[2][0] = grid * 2; + bezt->vec[2][1] = 0; + for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); + + BKE_nurb_handles_calc(nu); + } + else { + + nu->pntsu = 4; + nu->pntsv = 1; + nu->orderu = 4; + nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 4, "addNurbprim3"); + + bp = nu->bp; + for (a = 0; a < 4; a++, bp++) { + bp->vec[3] = 1.0; + bp->f1 = SELECT; + bp->radius = bp->weight = 1.0; + } + + bp = nu->bp; + bp->vec[0] += -1.5f * grid; + bp++; + bp->vec[0] += -grid; + bp->vec[1] += grid; + bp++; + bp->vec[0] += grid; + bp->vec[1] += grid; + bp++; + bp->vec[0] += 1.5f * grid; + + bp = nu->bp; + for (a = 0; a < 4; a++, bp++) mul_m4_v3(mat, bp->vec); + + if (cutype == CU_NURBS) { + nu->knotsu = NULL; /* nurbs_knot_calc_u allocates */ + BKE_nurb_knot_calc_u(nu); + } + + } + break; + case CU_PRIM_PATH: /* 5 point path */ + nu->pntsu = 5; + nu->pntsv = 1; + nu->orderu = 5; + nu->flagu = CU_NURB_ENDPOINT; /* endpoint */ + nu->resolu = cu->resolu; + nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 5, "addNurbprim3"); + + bp = nu->bp; + for (a = 0; a < 5; a++, bp++) { + bp->vec[3] = 1.0; + bp->f1 = SELECT; + bp->radius = bp->weight = 1.0; + } + + bp = nu->bp; + bp->vec[0] += -2.0f * grid; + bp++; + bp->vec[0] += -grid; + bp++; bp++; + bp->vec[0] += grid; + bp++; + bp->vec[0] += 2.0f * grid; + + bp = nu->bp; + for (a = 0; a < 5; a++, bp++) mul_m4_v3(mat, bp->vec); + + if (cutype == CU_NURBS) { + nu->knotsu = NULL; /* nurbs_knot_calc_u allocates */ + BKE_nurb_knot_calc_u(nu); + } + + break; + case CU_PRIM_CIRCLE: /* circle */ + nu->resolu = cu->resolu; + + if (cutype == CU_BEZIER) { + if (!force_3d) nu->flag |= CU_2D; + nu->pntsu = 4; + nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * 4, "addNurbprim1"); + nu->flagu = CU_NURB_CYCLIC; + bezt = nu->bezt; + + bezt->h1 = bezt->h2 = HD_AUTO; + bezt->f1 = bezt->f2 = bezt->f3 = SELECT; + bezt->vec[1][0] += -grid; + for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); + bezt->radius = bezt->weight = 1.0; + + bezt++; + bezt->h1 = bezt->h2 = HD_AUTO; + bezt->f1 = bezt->f2 = bezt->f3 = SELECT; + bezt->vec[1][1] += grid; + for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); + bezt->radius = bezt->weight = 1.0; + + bezt++; + bezt->h1 = bezt->h2 = HD_AUTO; + bezt->f1 = bezt->f2 = bezt->f3 = SELECT; + bezt->vec[1][0] += grid; + for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); + bezt->radius = bezt->weight = 1.0; + + bezt++; + bezt->h1 = bezt->h2 = HD_AUTO; + bezt->f1 = bezt->f2 = bezt->f3 = SELECT; + bezt->vec[1][1] += -grid; + for (a = 0; a < 3; a++) mul_m4_v3(mat, bezt->vec[a]); + bezt->radius = bezt->weight = 1.0; + + BKE_nurb_handles_calc(nu); + } + else if (cutype == CU_NURBS) { /* nurb */ + nu->pntsu = 8; + nu->pntsv = 1; + nu->orderu = 4; + nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 8, "addNurbprim6"); + nu->flagu = CU_NURB_CYCLIC; + bp = nu->bp; + + for (a = 0; a < 8; a++) { + bp->f1 = SELECT; + if (xzproj == 0) { + bp->vec[0] += nurbcircle[a][0] * grid; + bp->vec[1] += nurbcircle[a][1] * grid; + } + else { + bp->vec[0] += 0.25f * nurbcircle[a][0] * grid - 0.75f * grid; + bp->vec[2] += 0.25f * nurbcircle[a][1] * grid; + } + if (a & 1) bp->vec[3] = 0.25 * M_SQRT2; + else bp->vec[3] = 1.0; + mul_m4_v3(mat, bp->vec); + bp->radius = bp->weight = 1.0; + + bp++; + } + + BKE_nurb_knot_calc_u(nu); + } + break; + case CU_PRIM_PATCH: /* 4x4 patch */ + if (cutype == CU_NURBS) { /* nurb */ + + nu->pntsu = 4; + nu->pntsv = 4; + nu->orderu = 4; + nu->orderv = 4; + nu->flag = CU_SMOOTH; + nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * (4 * 4), "addNurbprim6"); + nu->flagu = 0; + nu->flagv = 0; + bp = nu->bp; + + for (a = 0; a < 4; a++) { + for (b = 0; b < 4; b++) { + bp->f1 = SELECT; + fac = (float)a - 1.5f; + bp->vec[0] += fac * grid; + fac = (float)b - 1.5f; + bp->vec[1] += fac * grid; + if ((a == 1 || a == 2) && (b == 1 || b == 2)) { + bp->vec[2] += grid; + } + mul_m4_v3(mat, bp->vec); + bp->vec[3] = 1.0; + bp++; + } + } + + BKE_nurb_knot_calc_u(nu); + BKE_nurb_knot_calc_v(nu); + } + break; + case CU_PRIM_TUBE: /* Cylinder */ + if (cutype == CU_NURBS) { + nu = add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */ + nu->resolu = cu->resolu; + nu->flag = CU_SMOOTH; + BLI_addtail(editnurb, nu); /* temporal for extrude and translate */ + vec[0] = vec[1] = 0.0; + vec[2] = -grid; + + mul_mat3_m4_v3(mat, vec); + + ed_editnurb_translate_flag(editnurb, 1, vec); + ed_editnurb_extrude_flag(cu->editnurb, 1); + mul_v3_fl(vec, -2.0f); + ed_editnurb_translate_flag(editnurb, 1, vec); + + BLI_remlink(editnurb, nu); + + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + while (a-- > 0) { + bp->f1 |= SELECT; + bp++; + } + } + break; + case CU_PRIM_SPHERE: /* sphere */ + if (cutype == CU_NURBS) { + float tmp_cent[3] = {0.f, 0.f, 0.f}; + float tmp_vec[3] = {0.f, 0.f, 1.f}; + + nu->pntsu = 5; + nu->pntsv = 1; + nu->orderu = 3; + nu->resolu = cu->resolu; + nu->resolv = cu->resolv; + nu->flag = CU_SMOOTH; + nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * 5, "addNurbprim6"); + nu->flagu = 0; + bp = nu->bp; + + for (a = 0; a < 5; a++) { + bp->f1 = SELECT; + bp->vec[0] += nurbcircle[a][0] * grid; + bp->vec[2] += nurbcircle[a][1] * grid; + if (a & 1) bp->vec[3] = 0.5 * M_SQRT2; + else bp->vec[3] = 1.0; + mul_m4_v3(mat, bp->vec); + bp++; + } + nu->flagu = CU_NURB_BEZIER; + BKE_nurb_knot_calc_u(nu); + + BLI_addtail(editnurb, nu); /* temporal for spin */ + + if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0) + ed_editnurb_spin(umat, obedit, tmp_vec, tmp_cent); + else if ((U.flag & USER_ADD_VIEWALIGNED)) + ed_editnurb_spin(viewmat, obedit, zvec, mat[3]); + else + ed_editnurb_spin(umat, obedit, tmp_vec, mat[3]); + + BKE_nurb_knot_calc_v(nu); + + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + while (a-- > 0) { + bp->f1 |= SELECT; + bp++; + } + BLI_remlink(editnurb, nu); + } + break; + case CU_PRIM_DONUT: /* torus */ + if (cutype == CU_NURBS) { + float tmp_cent[3] = {0.f, 0.f, 0.f}; + float tmp_vec[3] = {0.f, 0.f, 1.f}; + + xzproj = 1; + nu = add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */ + xzproj = 0; + nu->resolu = cu->resolu; + nu->resolv = cu->resolv; + nu->flag = CU_SMOOTH; + BLI_addtail(editnurb, nu); /* temporal for spin */ + + /* same as above */ + if (newob && (U.flag & USER_ADD_VIEWALIGNED) == 0) + ed_editnurb_spin(umat, obedit, tmp_vec, tmp_cent); + else if ((U.flag & USER_ADD_VIEWALIGNED)) + ed_editnurb_spin(viewmat, obedit, zvec, mat[3]); + else + ed_editnurb_spin(umat, obedit, tmp_vec, mat[3]); + + + BLI_remlink(editnurb, nu); + + a = nu->pntsu * nu->pntsv; + bp = nu->bp; + while (a-- > 0) { + bp->f1 |= SELECT; + bp++; + } + + } + break; + + default: /* should never happen */ + BLI_assert(!"invalid nurbs type"); + return NULL; + } + + BLI_assert(nu != NULL); + + if (nu) { /* should always be set */ + nu->flag |= CU_SMOOTH; + + BKE_nurb_test2D(nu); + } + + return nu; +} + +static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf) +{ + Object *obedit = CTX_data_edit_object(C); + ListBase *editnurb; + Nurb *nu; + bool newob = false; + bool enter_editmode, is_view_aligned; + unsigned int layer; + float dia; + float loc[3], rot[3]; + float mat[4][4]; + + WM_operator_view3d_unit_defaults(C, op); + + if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, &is_view_aligned)) + return OPERATOR_CANCELLED; + + if (!isSurf) { /* adding curve */ + if (obedit == NULL || obedit->type != OB_CURVE) { + Curve *cu; + + obedit = ED_object_add_type(C, OB_CURVE, loc, rot, true, layer); + newob = true; + + cu = (Curve *)obedit->data; + cu->flag |= CU_DEFORM_FILL; + + if (type & CU_PRIM_PATH) + cu->flag |= CU_PATH | CU_3D; + } + else { + DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + } + } + else { /* adding surface */ + if (obedit == NULL || obedit->type != OB_SURF) { + obedit = ED_object_add_type(C, OB_SURF, loc, rot, true, layer); + newob = true; + } + else { + DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + } + } + + /* rename here, the undo stack checks name for valid undo pushes */ + if (newob) { + if (obedit->type == OB_CURVE) { + rename_id((ID *)obedit, get_curve_defname(type)); + rename_id((ID *)obedit->data, get_curve_defname(type)); + } + else { + rename_id((ID *)obedit, get_surf_defname(type)); + rename_id((ID *)obedit->data, get_surf_defname(type)); + } + } + + /* ED_object_add_type doesnt do an undo, is needed for redo operator on primitive */ + if (newob && enter_editmode) + ED_undo_push(C, "Enter Editmode"); + + ED_object_new_primitive_matrix(C, obedit, loc, rot, mat, false); + dia = RNA_float_get(op->ptr, "radius"); + mat[0][0] *= dia; + mat[1][1] *= dia; + mat[2][2] *= dia; + + nu = add_nurbs_primitive(C, obedit, mat, type, newob); + editnurb = object_editcurve_get(obedit); + BLI_addtail(editnurb, nu); + + /* userdef */ + if (newob && !enter_editmode) { + ED_object_editmode_exit(C, EM_FREEDATA); + } + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); + + return OPERATOR_FINISHED; +} + +static int curve_prim_add(bContext *C, wmOperator *op, int type) +{ + return curvesurf_prim_add(C, op, type, 0); +} + +static int surf_prim_add(bContext *C, wmOperator *op, int type) +{ + return curvesurf_prim_add(C, op, type, 1); +} + +/* ******************** Curves ******************* */ + +static int add_primitive_bezier_exec(bContext *C, wmOperator *op) +{ + return curve_prim_add(C, op, CU_BEZIER | CU_PRIM_CURVE); +} + +void CURVE_OT_primitive_bezier_curve_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Bezier"; + ot->description = "Construct a Bezier Curve"; + ot->idname = "CURVE_OT_primitive_bezier_curve_add"; + + /* api callbacks */ + ot->exec = add_primitive_bezier_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ED_object_add_unit_props(ot); + ED_object_add_generic_props(ot, true); +} + +static int add_primitive_bezier_circle_exec(bContext *C, wmOperator *op) +{ + return curve_prim_add(C, op, CU_BEZIER | CU_PRIM_CIRCLE); +} + +void CURVE_OT_primitive_bezier_circle_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Bezier Circle"; + ot->description = "Construct a Bezier Circle"; + ot->idname = "CURVE_OT_primitive_bezier_circle_add"; + + /* api callbacks */ + ot->exec = add_primitive_bezier_circle_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ED_object_add_unit_props(ot); + ED_object_add_generic_props(ot, true); +} + +static int add_primitive_nurbs_curve_exec(bContext *C, wmOperator *op) +{ + return curve_prim_add(C, op, CU_NURBS | CU_PRIM_CURVE); +} + +void CURVE_OT_primitive_nurbs_curve_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Nurbs Curve"; + ot->description = "Construct a Nurbs Curve"; + ot->idname = "CURVE_OT_primitive_nurbs_curve_add"; + + /* api callbacks */ + ot->exec = add_primitive_nurbs_curve_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ED_object_add_unit_props(ot); + ED_object_add_generic_props(ot, true); +} + +static int add_primitive_nurbs_circle_exec(bContext *C, wmOperator *op) +{ + return curve_prim_add(C, op, CU_NURBS | CU_PRIM_CIRCLE); +} + +void CURVE_OT_primitive_nurbs_circle_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Nurbs Circle"; + ot->description = "Construct a Nurbs Circle"; + ot->idname = "CURVE_OT_primitive_nurbs_circle_add"; + + /* api callbacks */ + ot->exec = add_primitive_nurbs_circle_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ED_object_add_unit_props(ot); + ED_object_add_generic_props(ot, true); +} + +static int add_primitive_curve_path_exec(bContext *C, wmOperator *op) +{ + return curve_prim_add(C, op, CU_NURBS | CU_PRIM_PATH); +} + +void CURVE_OT_primitive_nurbs_path_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Path"; + ot->description = "Construct a Path"; + ot->idname = "CURVE_OT_primitive_nurbs_path_add"; + + /* api callbacks */ + ot->exec = add_primitive_curve_path_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ED_object_add_unit_props(ot); + ED_object_add_generic_props(ot, true); +} + +/* **************** NURBS surfaces ********************** */ +static int add_primitive_nurbs_surface_curve_exec(bContext *C, wmOperator *op) +{ + return surf_prim_add(C, op, CU_PRIM_CURVE | CU_NURBS); +} + +void SURFACE_OT_primitive_nurbs_surface_curve_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Surface Curve"; + ot->description = "Construct a Nurbs surface Curve"; + ot->idname = "SURFACE_OT_primitive_nurbs_surface_curve_add"; + + /* api callbacks */ + ot->exec = add_primitive_nurbs_surface_curve_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ED_object_add_unit_props(ot); + ED_object_add_generic_props(ot, true); +} + +static int add_primitive_nurbs_surface_circle_exec(bContext *C, wmOperator *op) +{ + return surf_prim_add(C, op, CU_PRIM_CIRCLE | CU_NURBS); +} + +void SURFACE_OT_primitive_nurbs_surface_circle_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Surface Circle"; + ot->description = "Construct a Nurbs surface Circle"; + ot->idname = "SURFACE_OT_primitive_nurbs_surface_circle_add"; + + /* api callbacks */ + ot->exec = add_primitive_nurbs_surface_circle_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ED_object_add_unit_props(ot); + ED_object_add_generic_props(ot, true); +} + +static int add_primitive_nurbs_surface_surface_exec(bContext *C, wmOperator *op) +{ + return surf_prim_add(C, op, CU_PRIM_PATCH | CU_NURBS); +} + +void SURFACE_OT_primitive_nurbs_surface_surface_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Surface Patch"; + ot->description = "Construct a Nurbs surface Patch"; + ot->idname = "SURFACE_OT_primitive_nurbs_surface_surface_add"; + + /* api callbacks */ + ot->exec = add_primitive_nurbs_surface_surface_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ED_object_add_unit_props(ot); + ED_object_add_generic_props(ot, true); +} + +static int add_primitive_nurbs_surface_cylinder_exec(bContext *C, wmOperator *op) +{ + return surf_prim_add(C, op, CU_PRIM_TUBE | CU_NURBS); +} + +void SURFACE_OT_primitive_nurbs_surface_cylinder_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Surface Cylinder"; + ot->description = "Construct a Nurbs surface Cylinder"; + ot->idname = "SURFACE_OT_primitive_nurbs_surface_cylinder_add"; + + /* api callbacks */ + ot->exec = add_primitive_nurbs_surface_cylinder_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ED_object_add_unit_props(ot); + ED_object_add_generic_props(ot, true); +} + +static int add_primitive_nurbs_surface_sphere_exec(bContext *C, wmOperator *op) +{ + return surf_prim_add(C, op, CU_PRIM_SPHERE | CU_NURBS); +} + +void SURFACE_OT_primitive_nurbs_surface_sphere_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Surface Sphere"; + ot->description = "Construct a Nurbs surface Sphere"; + ot->idname = "SURFACE_OT_primitive_nurbs_surface_sphere_add"; + + /* api callbacks */ + ot->exec = add_primitive_nurbs_surface_sphere_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ED_object_add_unit_props(ot); + ED_object_add_generic_props(ot, true); +} + +static int add_primitive_nurbs_surface_torus_exec(bContext *C, wmOperator *op) +{ + return surf_prim_add(C, op, CU_PRIM_DONUT | CU_NURBS); +} + +void SURFACE_OT_primitive_nurbs_surface_torus_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Surface Torus"; + ot->description = "Construct a Nurbs surface Torus"; + ot->idname = "SURFACE_OT_primitive_nurbs_surface_torus_add"; + + /* api callbacks */ + ot->exec = add_primitive_nurbs_surface_torus_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ED_object_add_unit_props(ot); + ED_object_add_generic_props(ot, true); +} diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index b9759e16f20..ac9c338e431 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -981,7 +981,7 @@ void FONT_OT_move_select(wmOperatorType *ot) { /* identifiers */ ot->name = "Move Select"; - ot->description = "Make selection from current cursor position to new cursor position type"; + ot->description = "Move the cursor while selecting"; ot->idname = "FONT_OT_move_select"; /* api callbacks */ diff --git a/source/blender/editors/curve/lorem.c b/source/blender/editors/curve/lorem.c index 52f5101f58a..59bf3f50dbc 100644 --- a/source/blender/editors/curve/lorem.c +++ b/source/blender/editors/curve/lorem.c @@ -23,6 +23,7 @@ */ +#include "BLI_sys_types.h" #include "curve_intern.h" const char ED_lorem[] = { diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 8d108644470..6adc500baa4 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -47,8 +47,18 @@ if(WITH_BLENDER) # images data_to_c_simple(../../../../release/datafiles/splash.png SRC) + # XXX These are handy, but give nasty "false changes" in svn :/ + #svg_to_png(../../../../release/datafiles/blender_icons.svg + #../../../../release/datafiles/blender_icons16.png + #90 SRC) data_to_c_simple(../../../../release/datafiles/blender_icons16.png SRC) + #svg_to_png(../../../../release/datafiles/blender_icons.svg + #../../../../release/datafiles/blender_icons32.png + #180 SRC) data_to_c_simple(../../../../release/datafiles/blender_icons32.png SRC) + #svg_to_png(../../../../release/datafiles/prvicons.svg + #../../../../release/datafiles/prvicons.png + #90 SRC) data_to_c_simple(../../../../release/datafiles/prvicons.png SRC) # brushes diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 99157b074fd..c5dc8654e9d 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -106,8 +106,8 @@ bGPdata **gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr) /* TODO: we can include other data-types such as bones later if need be... */ - /* just in case no active object */ - if (ob) { + /* 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; @@ -192,7 +192,14 @@ bGPdata *gpencil_data_get_active(const bContext *C) /* needed for offscreen rendering */ bGPdata *gpencil_data_get_active_v3d(Scene *scene) { - bGPdata *gpd = scene->basact ? scene->basact->object->gpd : NULL; + Base *base = scene->basact; + bGPdata *gpd = NULL; + /* We have to make sure active object is actually visible and selected, else we must use default scene gpd, + * to be consistent with gpencil_data_get_active's behavior. + */ + if (base && (scene->lay & base->lay) && (base->object->flag & SELECT)) { + gpd = base->object->gpd; + } return gpd ? gpd : scene->gpd; } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 4c5727f16ed..255f0b7cfba 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1431,7 +1431,7 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op) gpencil_undo_finish(); /* restore cursor to indicate end of drawing */ - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); /* don't assume that operator data exists at all */ if (p) { @@ -1679,7 +1679,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) /* loop over the stroke RNA elements recorded (i.e. progress of mouse movement), * setting the relevant values in context at each step, then applying */ - RNA_BEGIN(op->ptr, itemptr, "stroke") + RNA_BEGIN (op->ptr, itemptr, "stroke") { float mousef[2]; @@ -1764,9 +1764,9 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event /* set cursor */ if (p->paintmode == GP_PAINTMODE_ERASER) - WM_cursor_modal(win, BC_CROSSCURSOR); /* XXX need a better cursor */ + WM_cursor_modal_set(win, BC_CROSSCURSOR); /* XXX need a better cursor */ else - WM_cursor_modal(win, BC_PAINTBRUSHCURSOR); + 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 diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index 352a74cf172..dd1995a5428 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -221,8 +221,5 @@ void glaDrawImBuf_glsl(struct ImBuf *ibuf, float x, float y, int zoomfilter, /* Draw imbuf on a screen, preferably using GLSL display transform */ void glaDrawImBuf_glsl_ctx(const struct bContext *C, struct ImBuf *ibuf, float x, float y, int zoomfilter); -/* Transform buffer from role to scene linear space using GLSL OCIO conversion */ -int glaBufferTransformFromRole_glsl(float *buffer, int width, int height, int role); - #endif /* __BIF_GLUTIL_H__ */ diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 1de1731b515..61f9cec15d9 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -233,29 +233,29 @@ typedef enum eAnimFilter_Flags { /* Dopesheet only */ /* 'Scene' channels */ -#define SEL_SCEC(sce) (CHECK_TYPE_INLINE(sce, Scene), ((sce->flag & SCE_DS_SELECTED))) -#define EXPANDED_SCEC(sce) (CHECK_TYPE_INLINE(sce, Scene), ((sce->flag & SCE_DS_COLLAPSED) == 0)) +#define SEL_SCEC(sce) (CHECK_TYPE_INLINE(sce, Scene *), ((sce->flag & SCE_DS_SELECTED))) +#define EXPANDED_SCEC(sce) (CHECK_TYPE_INLINE(sce, Scene *), ((sce->flag & SCE_DS_COLLAPSED) == 0)) /* 'Sub-Scene' channels (flags stored in Data block) */ -#define FILTER_WOR_SCED(wo) (CHECK_TYPE_INLINE(wo, World), (wo->flag & WO_DS_EXPAND)) +#define FILTER_WOR_SCED(wo) (CHECK_TYPE_INLINE(wo, World *), (wo->flag & WO_DS_EXPAND)) #define FILTER_LS_SCED(linestyle) ((linestyle->flag & LS_DS_EXPAND)) /* 'Object' channels */ -#define SEL_OBJC(base) (CHECK_TYPE_INLINE(base, Base), ((base->flag & SELECT))) -#define EXPANDED_OBJC(ob) (CHECK_TYPE_INLINE(ob, Object), ((ob->nlaflag & OB_ADS_COLLAPSED) == 0)) +#define SEL_OBJC(base) (CHECK_TYPE_INLINE(base, Base *), ((base->flag & SELECT))) +#define EXPANDED_OBJC(ob) (CHECK_TYPE_INLINE(ob, Object *), ((ob->nlaflag & OB_ADS_COLLAPSED) == 0)) /* 'Sub-object' channels (flags stored in Data block) */ -#define FILTER_SKE_OBJD(key) (CHECK_TYPE_INLINE(key, Key), ((key->flag & KEY_DS_EXPAND))) -#define FILTER_MAT_OBJD(ma) (CHECK_TYPE_INLINE(ma, Material), ((ma->flag & MA_DS_EXPAND))) -#define FILTER_LAM_OBJD(la) (CHECK_TYPE_INLINE(la, Lamp), ((la->flag & LA_DS_EXPAND))) -#define FILTER_CAM_OBJD(ca) (CHECK_TYPE_INLINE(ca, Camera), ((ca->flag & CAM_DS_EXPAND))) -#define FILTER_CUR_OBJD(cu) (CHECK_TYPE_INLINE(cu, Curve), ((cu->flag & CU_DS_EXPAND))) -#define FILTER_PART_OBJD(part) (CHECK_TYPE_INLINE(part, ParticleSettings), ((part->flag & PART_DS_EXPAND))) -#define FILTER_MBALL_OBJD(mb) (CHECK_TYPE_INLINE(mb, MetaBall), ((mb->flag2 & MB_DS_EXPAND))) -#define FILTER_ARM_OBJD(arm) (CHECK_TYPE_INLINE(arm, bArmature), ((arm->flag & ARM_DS_EXPAND))) -#define FILTER_MESH_OBJD(me) (CHECK_TYPE_INLINE(me, Mesh), ((me->flag & ME_DS_EXPAND))) -#define FILTER_LATTICE_OBJD(lt) (CHECK_TYPE_INLINE(lt, Lattice), ((lt->flag & LT_DS_EXPAND))) -#define FILTER_SPK_OBJD(spk) (CHECK_TYPE_INLINE(spk, Speaker), ((spk->flag & SPK_DS_EXPAND))) +#define FILTER_SKE_OBJD(key) (CHECK_TYPE_INLINE(key, Key *), ((key->flag & KEY_DS_EXPAND))) +#define FILTER_MAT_OBJD(ma) (CHECK_TYPE_INLINE(ma, Material *), ((ma->flag & MA_DS_EXPAND))) +#define FILTER_LAM_OBJD(la) (CHECK_TYPE_INLINE(la, Lamp *), ((la->flag & LA_DS_EXPAND))) +#define FILTER_CAM_OBJD(ca) (CHECK_TYPE_INLINE(ca, Camera *), ((ca->flag & CAM_DS_EXPAND))) +#define FILTER_CUR_OBJD(cu) (CHECK_TYPE_INLINE(cu, Curve *), ((cu->flag & CU_DS_EXPAND))) +#define FILTER_PART_OBJD(part) (CHECK_TYPE_INLINE(part, ParticleSettings *), ((part->flag & PART_DS_EXPAND))) +#define FILTER_MBALL_OBJD(mb) (CHECK_TYPE_INLINE(mb, MetaBall *), ((mb->flag2 & MB_DS_EXPAND))) +#define FILTER_ARM_OBJD(arm) (CHECK_TYPE_INLINE(arm, bArmature *), ((arm->flag & ARM_DS_EXPAND))) +#define FILTER_MESH_OBJD(me) (CHECK_TYPE_INLINE(me, Mesh *), ((me->flag & ME_DS_EXPAND))) +#define FILTER_LATTICE_OBJD(lt) (CHECK_TYPE_INLINE(lt, Lattice *), ((lt->flag & LT_DS_EXPAND))) +#define FILTER_SPK_OBJD(spk) (CHECK_TYPE_INLINE(spk, Speaker *), ((spk->flag & SPK_DS_EXPAND))) /* Variable use expanders */ -#define FILTER_NTREE_DATA(ntree) (CHECK_TYPE_INLINE(ntree, bNodeTree), ((ntree->flag & NTREE_DS_EXPAND))) -#define FILTER_TEX_DATA(tex) (CHECK_TYPE_INLINE(tex, Tex), ((tex->flag & TEX_DS_EXPAND))) +#define FILTER_NTREE_DATA(ntree) (CHECK_TYPE_INLINE(ntree, bNodeTree *), ((ntree->flag & NTREE_DS_EXPAND))) +#define FILTER_TEX_DATA(tex) (CHECK_TYPE_INLINE(tex, Tex *), ((tex->flag & TEX_DS_EXPAND))) /* 'Sub-object/Action' channels (flags stored in Action) */ #define SEL_ACTC(actc) ((actc->flag & ACT_SELECTED)) diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index fab179da7bc..225d8a0e5a3 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -94,15 +94,15 @@ typedef struct EditBone { /* useful macros */ #define EBONE_VISIBLE(arm, ebone) ( \ - CHECK_TYPE_INLINE(arm, bArmature), \ - CHECK_TYPE_INLINE(ebone, EditBone), \ + CHECK_TYPE_INLINE(arm, bArmature *), \ + CHECK_TYPE_INLINE(ebone, EditBone *), \ (((arm)->layer & (ebone)->layer) && !((ebone)->flag & BONE_HIDDEN_A)) \ ) #define EBONE_SELECTABLE(arm, ebone) (EBONE_VISIBLE(arm, ebone) && !(ebone->flag & BONE_UNSELECTABLE)) #define EBONE_EDITABLE(ebone) ( \ - CHECK_TYPE_INLINE(ebone, EditBone), \ + CHECK_TYPE_INLINE(ebone, EditBone *), \ (((ebone)->flag & BONE_SELECTED) && !((ebone)->flag & BONE_EDITMODE_LOCKED)) \ ) @@ -167,7 +167,6 @@ void ED_armature_ebone_selectflag_disable(EditBone *ebone, int flag); /* poseobject.c */ void ED_armature_exit_posemode(struct bContext *C, struct Base *base); void ED_armature_enter_posemode(struct bContext *C, struct Base *base); -int ED_pose_channel_in_IK_chain(struct Object *ob, struct bPoseChannel *pchan); void ED_pose_deselectall(struct Object *ob, int test); void ED_pose_recalculate_paths(struct Scene *scene, struct Object *ob); struct Object *ED_pose_object_from_context(struct bContext *C); diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h index 541956136bd..27e62928f1b 100644 --- a/source/blender/editors/include/ED_clip.h +++ b/source/blender/editors/include/ED_clip.h @@ -63,18 +63,18 @@ int ED_space_clip_get_clip_frame_number(struct SpaceClip *sc); struct ImBuf *ED_space_clip_get_buffer(struct SpaceClip *sc); struct ImBuf *ED_space_clip_get_stable_buffer(struct SpaceClip *sc, float loc[2], float *scale, float *angle); -int ED_space_clip_color_sample(struct SpaceClip *sc, struct ARegion *ar, int mval[2], float r_col[3]); +bool ED_space_clip_color_sample(struct SpaceClip *sc, struct ARegion *ar, int mval[2], float r_col[3]); void ED_clip_update_frame(const struct Main *mainp, int cfra); -int ED_clip_view_selection(const struct bContext *C, struct ARegion *ar, int fit); +bool ED_clip_view_selection(const struct bContext *C, struct ARegion *ar, bool fit); void ED_clip_point_undistorted_pos(struct SpaceClip *sc, const float co[2], float r_co[2]); void ED_clip_point_stable_pos(struct SpaceClip *sc, struct ARegion *ar, float x, float y, float *xr, float *yr); void ED_clip_point_stable_pos__reverse(struct SpaceClip *sc, struct ARegion *ar, const float co[2], float r_co[2]); void ED_clip_mouse_pos(struct SpaceClip *sc, struct ARegion *ar, const int mval[2], float co[2]); -int ED_space_clip_check_show_trackedit(struct SpaceClip *sc); -int ED_space_clip_check_show_maskedit(struct SpaceClip *sc); +bool ED_space_clip_check_show_trackedit(struct SpaceClip *sc); +bool ED_space_clip_check_show_maskedit(struct SpaceClip *sc); struct MovieClip *ED_space_clip_get_clip(struct SpaceClip *sc); void ED_space_clip_set_clip(struct bContext *C, struct bScreen *screen, struct SpaceClip *sc, struct MovieClip *clip); diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index 1d26204095c..571788f4f8f 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -83,6 +83,7 @@ int CU_select_nth(struct Object *obedit, int nth); void ED_curve_beztcpy(struct EditNurb *editnurb, struct BezTriple *dst, struct BezTriple *src, int count); void ED_curve_bpcpy(struct EditNurb *editnurb, struct BPoint *dst, struct BPoint *src, int count); +struct Nurb *ED_curve_nurbcpy(struct Nurb *src, int count); int ED_curve_updateAnimPaths(struct Curve *cu); diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 95fad17274e..dc40efc748b 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -222,6 +222,7 @@ short ANIM_keyingset_context_ok_poll(struct bContext *C, struct KeyingSet *ks); /* Flags for use by driver creation calls */ typedef enum eCreateDriverFlags { CREATEDRIVER_WITH_DEFAULT_DVAR = (1 << 0), /* create drivers with a default variable for nicer UI */ + CREATEDRIVER_WITH_FMODIFIER = (1 << 1), /* create drivers with Generator FModifier (for backwards compat) */ } eCreateDriverFlags; /* -------- */ diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h index 15e5c3dba8f..6fe1524cb6d 100644 --- a/source/blender/editors/include/ED_lattice.h +++ b/source/blender/editors/include/ED_lattice.h @@ -28,8 +28,13 @@ * \ingroup editors */ +#ifndef __ED_LATTICE_H__ +#define __ED_LATTICE_H__ + struct Object; void free_editLatt(struct Object *ob); void make_editLatt(struct Object *obedit); void load_editLatt(struct Object *obedit); + +#endif /* __ED_LATTICE_H__ */ diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h index 420ab24e5e9..3e2dbe255df 100644 --- a/source/blender/editors/include/ED_mask.h +++ b/source/blender/editors/include/ED_mask.h @@ -48,6 +48,8 @@ void ED_mask_point_pos(struct ScrArea *sa, struct ARegion *ar, float x, float y, void ED_mask_point_pos__reverse(struct ScrArea *sa, struct ARegion *ar, float x, float y, float *xr, float *yr); +void ED_mask_cursor_location_get(struct ScrArea *sa, float cursor[2]); + void ED_operatortypes_mask(void); void ED_keymap_mask(struct wmKeyConfig *keyconf); void ED_operatormacros_mask(void); diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h index da96aba011e..1842b84a3f5 100644 --- a/source/blender/editors/include/ED_mball.h +++ b/source/blender/editors/include/ED_mball.h @@ -39,7 +39,7 @@ struct wmKeyConfig; void ED_operatortypes_metaball(void); void ED_keymap_metaball(struct wmKeyConfig *keyconf); -struct MetaElem *add_metaball_primitive(struct bContext *C, struct Object *obedit, float mat[4][4], float dia, int type, int newname); +struct MetaElem *add_metaball_primitive(struct bContext *C, struct Object *obedit, float mat[4][4], float dia, int type); bool mouse_mball(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index f24f9098fcd..b7fd181883b 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -242,8 +242,18 @@ 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_give_array(struct ID *id, struct MDeformVert **dvert_arr, int *dvert_tot); -bool ED_vgroup_copy_array(struct Object *ob, struct Object *ob_from); +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); +void ED_vgroup_parray_mirror_sync(struct Object *ob, + struct MDeformVert **dvert_array, const int dvert_tot, + const bool *vgroup_validmap, const int vgroup_tot); +void ED_vgroup_parray_mirror_assign(struct Object *ob, + struct MDeformVert **dvert_array, const int dvert_tot); +void ED_vgroup_parray_remove_zero(struct MDeformVert **dvert_array, const int dvert_tot, + const bool *vgroup_validmap, const int vgroup_tot, + const float epsilon, const bool keep_single); void ED_vgroup_mirror(struct Object *ob, const bool mirror_weights, const bool flip_vgroups, const bool all_vgroups, const bool use_topology, @@ -317,6 +327,8 @@ struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh int index, const bool use_topology); int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em); +int ED_mesh_mirror_get_vert(struct Object *ob, int index); + bool ED_mesh_pick_vert(struct bContext *C, struct Object *ob, const int mval[2], unsigned int *index, int size, bool use_zbuf); bool ED_mesh_pick_face(struct bContext *C, struct Object *ob, const int mval[2], unsigned int *index, int size); bool ED_mesh_pick_face_vert(struct bContext *C, struct Object *ob, const int mval[2], unsigned int *index, int size); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 90b131e5acc..eae2141e527 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -92,7 +92,7 @@ typedef enum eParentType { PAR_PATH_CONST, PAR_LATTICE, PAR_VERTEX, - PAR_TRIA + PAR_VERTEX_TRI } eParentType; #ifdef __RNA_TYPES_H__ @@ -101,7 +101,7 @@ extern struct EnumPropertyItem prop_make_parent_types[]; #endif int ED_object_parent_set(struct ReportList *reports, struct Main *bmain, struct Scene *scene, struct Object *ob, - struct Object *par, int partype, int xmirror, int keep_transform); + struct Object *par, int partype, bool xmirror, bool keep_transform, const int vert_par[3]); void ED_object_parent_clear(struct Object *ob, int type); struct Base *ED_object_scene_link(struct Scene *scene, struct Object *ob); @@ -123,6 +123,7 @@ struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, st void ED_object_parent(struct Object *ob, struct Object *parent, int type, const char *substr); +bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, int mode, struct ReportList *reports); void ED_object_toggle_modes(struct bContext *C, int mode); /* bitflags for enter/exit editmode */ @@ -140,14 +141,15 @@ void ED_object_rotation_from_view(struct bContext *C, float rot[3]); void ED_object_base_init_transform(struct bContext *C, struct Base *base, const float loc[3], const float rot[3]); float ED_object_new_primitive_matrix(struct bContext *C, struct Object *editob, const float loc[3], const float rot[3], float primmat[4][4], - int apply_diameter); + bool apply_diameter); -void ED_object_add_generic_props(struct wmOperatorType *ot, int do_editmode); -int ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, float loc[3], float rot[3], - bool *enter_editmode, unsigned int *layer, bool *is_view_aligned); +void ED_object_add_unit_props(struct wmOperatorType *ot); +void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode); +bool ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, float loc[3], float rot[3], + bool *enter_editmode, unsigned int *layer, bool *is_view_aligned); struct Object *ED_object_add_type(struct bContext *C, int type, const float loc[3], const float rot[3], - int enter_editmode, unsigned int layer); + bool enter_editmode, unsigned int layer); void ED_object_single_users(struct Main *bmain, struct Scene *scene, bool full, bool copy_groups); void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Object *ob); @@ -206,6 +208,8 @@ 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, diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index bdfbbbb9c74..518bee665ae 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -40,6 +40,7 @@ struct Scene; struct ScrArea; struct RegionView3D; struct RenderEngine; +struct View3D; /* render_ops.c */ @@ -51,6 +52,7 @@ void ED_render_id_flush_update(struct Main *bmain, struct ID *id); 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_render_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa); void ED_viewport_render_kill_jobs(const struct bContext *C, bool free_database); diff --git a/source/blender/editors/include/ED_screen_types.h b/source/blender/editors/include/ED_screen_types.h index 9f42fd042c3..2b02606c6d9 100644 --- a/source/blender/editors/include/ED_screen_types.h +++ b/source/blender/editors/include/ED_screen_types.h @@ -79,7 +79,7 @@ typedef enum { AE_RIGHT_TO_TOPLEFT, /* Region located on the left, _right_ edge is action zone. Region minimized to the top left */ AE_LEFT_TO_TOPRIGHT, /* Region located on the right, _left_ edge is action zone. Region minimized to the top right */ AE_TOP_TO_BOTTOMRIGHT, /* Region located at the bottom, _top_ edge is action zone. Region minimized to the bottom right */ - AE_BOTTOM_TO_TOPLEFT /* Region located at the top, _bottom_edge is action zone. Region minimized to the top left */ + AE_BOTTOM_TO_TOPLEFT /* Region located at the top, _bottom_ edge is action zone. Region minimized to the top left */ } AZEdge; /* for editing areas/regions */ @@ -87,10 +87,8 @@ typedef struct AZone { struct AZone *next, *prev; ARegion *ar; int type; - /* region-azone, which of the edges */ + /* region-azone, which of the edges (only for AZONE_REGION) */ AZEdge edge; - /* internal */ - short do_draw; /* for draw */ short x1, y1, x2, y2; /* for clip */ diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index 67f790f0b46..7f642db9fbd 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -78,9 +78,9 @@ void undo_editmode_push(struct bContext *C, const char *name, void undo_editmode_clear(void); /* crazyspace.c */ -float *crazyspace_get_mapped_editverts(struct Scene *scene, struct Object *obedit); -void crazyspace_set_quats_editmesh(struct BMEditMesh *em, float *origcos, float *mappedcos, float *quats); -void crazyspace_set_quats_mesh(struct Mesh *me, float *origcos, float *mappedcos, float *quats); +float (*crazyspace_get_mapped_editverts(struct Scene *scene, struct Object *obedit))[3]; +void crazyspace_set_quats_editmesh(struct BMEditMesh *em, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4]); +void crazyspace_set_quats_mesh(struct Mesh *me, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4]); int sculpt_get_first_deform_matrices(struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]); void crazyspace_build_sculpt(struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]); diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index ffc9e6651bc..735227ae9b5 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -102,7 +102,7 @@ void ED_uvedit_live_unwrap(struct Scene *scene, struct Object *obedit); void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel); /* uvedit_draw.c */ -void draw_image_cursor(struct SpaceImage *sima, struct ARegion *ar); +void draw_image_cursor(struct ARegion *ar, const float cursor[2]); void draw_uvedit_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct Object *obedit, struct Object *obact); /* uvedit_buttons.c */ diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index ef50a21c900..86abf29c308 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -248,7 +248,9 @@ unsigned int view3d_sample_backbuf_rect(struct ViewContext *vc, const int mval[2 unsigned int view3d_sample_backbuf(struct ViewContext *vc, int x, int y); /* draws and does a 4x4 sample */ -bool ED_view3d_autodist(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, const int mval[2], float mouse_worldloc[3], bool alphaoverride); +bool ED_view3d_autodist(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, + const int mval[2], float mouse_worldloc[3], + bool alphaoverride, const float fallback_depth_pt[3]); /* only draw so ED_view3d_autodist_simple can be called many times after */ void ED_view3d_autodist_init(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, int mode); @@ -334,4 +336,7 @@ void ED_view3d_operator_properties_viewmat_set(struct bContext *C, struct wmOper void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op, int *winx, int *winy, float persmat[4][4]); #endif +/* render */ +void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa); + #endif /* __ED_VIEW3D_H__ */ diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 3929cf9788c..f8e1bbb2413 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -49,9 +49,7 @@ DEF_ICON(RADIOBUT_OFF) DEF_ICON(RADIOBUT_ON) DEF_ICON(MENU_PANEL) DEF_ICON(BLENDER) -#ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK003) -#endif +DEF_ICON(GRIP) DEF_ICON(DOT) #ifndef DEF_ICON_BLANK_SKIP DEF_ICON(BLANK004) @@ -75,9 +73,9 @@ DEF_ICON(VIEWZOOM) DEF_ICON(ZOOMIN) DEF_ICON(ZOOMOUT) DEF_ICON(PANEL_CLOSE) -DEF_ICON(COPY_ID) //ICON_BLANK009 +DEF_ICON(COPY_ID) DEF_ICON(EYEDROPPER) -DEF_ICON(LINK_AREA) //ICON_BLANK010 +DEF_ICON(LINK_AREA) DEF_ICON(AUTO) DEF_ICON(CHECKBOX_DEHLT) DEF_ICON(CHECKBOX_HLT) @@ -138,7 +136,7 @@ DEF_ICON(SCRIPT) DEF_ICON(PARTICLES) DEF_ICON(PHYSICS) DEF_ICON(SPEAKER) -DEF_ICON(TEXTURE_SHADED) //ICON_BLANK041 +DEF_ICON(TEXTURE_SHADED) #ifndef DEF_ICON_BLANK_SKIP DEF_ICON(BLANK042) DEF_ICON(BLANK043) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9a9cab9b46c..38aad640ee1 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -32,6 +32,7 @@ #ifndef __UI_INTERFACE_H__ #define __UI_INTERFACE_H__ +#include "BLI_compiler_attrs.h" #include "BLI_sys_types.h" /* size_t */ #include "RNA_types.h" #include "DNA_userdef_types.h" @@ -81,6 +82,10 @@ typedef struct uiLayout uiLayout; /* Defines */ +/* char for splitting strings, aligning shortcuts in menus, users never see */ +#define UI_SEP_CHAR '|' +#define UI_SEP_CHAR_S "|" + /* names */ #define UI_MAX_DRAW_STR 400 #define UI_MAX_NAME_STR 128 @@ -327,30 +332,14 @@ typedef void (*uiMenuHandleFunc)(struct bContext *C, void *arg, int event); typedef struct uiPopupMenu uiPopupMenu; -struct uiPopupMenu *uiPupMenuBegin(struct bContext *C, const char *title, int icon) -#ifdef __GNUC__ -__attribute__((nonnull)) -#endif -; +struct uiPopupMenu *uiPupMenuBegin(struct bContext *C, const char *title, int icon) ATTR_NONNULL(); void uiPupMenuEnd(struct bContext *C, struct uiPopupMenu *head); struct uiLayout *uiPupMenuLayout(uiPopupMenu *head); -void uiPupMenuOkee(struct bContext *C, const char *opname, const char *str, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 3, 4))) -#endif -; +void uiPupMenuOkee(struct bContext *C, const char *opname, const char *str, ...) ATTR_PRINTF_FORMAT(3, 4); void uiPupMenuSaveOver(struct bContext *C, struct wmOperator *op, const char *filename); -void uiPupMenuNotice(struct bContext *C, const char *str, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 2, 3))) -#endif -; -void uiPupMenuError(struct bContext *C, const char *str, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 2, 3))) -#endif -; +void uiPupMenuNotice(struct bContext *C, const char *str, ...) ATTR_PRINTF_FORMAT(2, 3); +void uiPupMenuError(struct bContext *C, const char *str, ...) ATTR_PRINTF_FORMAT(2, 3); void uiPupMenuReports(struct bContext *C, struct ReportList *reports); void uiPupMenuInvoke(struct bContext *C, const char *idname); /* popup registered menu */ @@ -550,11 +539,7 @@ typedef struct uiStringInfo { /* Note: Expects pointers to uiStringInfo structs as parameters. * Will fill them with translated strings, when possible. * Strings in uiStringInfo must be MEM_freeN'ed by caller. */ -void uiButGetStrInfo(struct bContext *C, uiBut *but, ...) -#ifdef __GNUC__ -__attribute__((sentinel)) -#endif -; +void uiButGetStrInfo(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0); /* Edit i18n stuff. */ /* Name of the main py op from i18n addon. */ @@ -845,7 +830,7 @@ void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color); #define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list" void uiTemplateList(uiLayout *layout, struct bContext *C, const char *listtype_name, const char *list_id, struct PointerRNA *dataptr, const char *propname, struct PointerRNA *active_dataptr, - const char *active_propname, int rows, int maxrows, int layout_type); + const char *active_propname, int rows, int maxrows, int layout_type, int columns); void uiTemplateNodeLink(uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input); void uiTemplateNodeView(uiLayout *layout, struct bContext *C, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input); void uiTemplateTextureUser(uiLayout *layout, struct bContext *C); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 42e9d892871..0c8a39a6714 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -210,6 +210,9 @@ enum { TH_STITCH_PREVIEW_UNSTITCHABLE, TH_STITCH_PREVIEW_ACTIVE, + TH_UV_SHADOW, + TH_UV_OTHERS, + TH_FREESTYLE_EDGE_MARK, TH_FREESTYLE_FACE_MARK, diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index e46334b06e7..c9a19ab4d8e 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -192,6 +192,7 @@ void UI_view2d_listview_visible_cells(struct View2D *v2d, float columnwidth, flo void UI_view2d_region_to_view(struct View2D *v2d, float x, float y, float *viewx, float *viewy); void UI_view2d_view_to_region(struct View2D *v2d, float x, float y, int *regionx, int *regiony); void UI_view2d_to_region_no_clip(struct View2D *v2d, float x, float y, int *regionx, int *region_y); +void UI_view2d_to_region_float(struct View2D *v2d, float x, float y, float *regionx, float *regiony); /* utilities */ struct View2D *UI_view2d_fromcontext(const struct bContext *C); @@ -215,7 +216,7 @@ void UI_view2d_operatortypes(void); void UI_view2d_keymap(struct wmKeyConfig *keyconf); void UI_view2d_smooth_view(struct bContext *C, struct ARegion *ar, - const struct rctf *cur); + const struct rctf *cur, const int smooth_viewtx); #endif /* __UI_VIEW2D_H__ */ diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index a8b8765a5c6..e13517adbb3 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -40,6 +40,7 @@ set(SRC interface.c interface_anim.c interface_draw.c + interface_eyedropper.c interface_handlers.c interface_icons.c interface_layout.c diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 21a63183c1a..e02cdf018c0 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -837,7 +837,7 @@ void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_str { if (do_strip) { - char *cpoin = strchr(but->str, '|'); + char *cpoin = strchr(but->str, UI_SEP_CHAR); if (cpoin) { *cpoin = '\0'; } @@ -855,7 +855,7 @@ void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_str } BLI_snprintf(but->strdata, sizeof(but->strdata), - "%s|%s", + "%s" UI_SEP_CHAR_S "%s", butstr_orig, shortcut_str); MEM_freeN(butstr_orig); but->str = but->strdata; @@ -962,10 +962,12 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but, data_path = BLI_sprintfN("scene.%s", path); MEM_freeN(path); } - /*else { - printf("ERROR in %s(): Couldn't get path for scene property - %s\n", +#if 0 + else { + printf("ERROR in %s(): Couldn't get path for scene property - %s\n", __func__, RNA_property_identifier(but->rnaprop)); - }*/ + } +#endif } } else { @@ -985,7 +987,7 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but, IDPropertyTemplate val = {0}; prop_path = IDP_New(IDP_GROUP, &val, __func__); - prop_path_value = IDP_NewString(data_path, "data_path", strlen(data_path) + 1); /* len + 1, or else will be truncated */ + prop_path_value = IDP_NewString(data_path, "data_path", strlen(data_path) + 1); IDP_AddToGroup(prop_path, prop_path_value); /* check each until one works... */ @@ -1644,19 +1646,19 @@ void ui_set_but_val(uiBut *but, double value) if (RNA_property_editable(&but->rnapoin, prop)) { switch (RNA_property_type(prop)) { case PROP_BOOLEAN: - if (RNA_property_array_length(&but->rnapoin, prop)) + if (RNA_property_array_check(prop)) RNA_property_boolean_set_index(&but->rnapoin, prop, but->rnaindex, value); else RNA_property_boolean_set(&but->rnapoin, prop, value); break; case PROP_INT: - if (RNA_property_array_length(&but->rnapoin, prop)) + if (RNA_property_array_check(prop)) RNA_property_int_set_index(&but->rnapoin, prop, but->rnaindex, (int)value); else RNA_property_int_set(&but->rnapoin, prop, (int)value); break; case PROP_FLOAT: - if (RNA_property_array_length(&but->rnapoin, prop)) + if (RNA_property_array_check(prop)) RNA_property_float_set_index(&but->rnapoin, prop, but->rnaindex, value); else RNA_property_float_set(&but->rnapoin, prop, value); @@ -1807,12 +1809,14 @@ static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double va static float ui_get_but_step_unit(uiBut *but, float step_default) { int unit_type = RNA_SUBTYPE_UNIT_VALUE(uiButGetUnitType(but)); - float step; + double step; step = bUnit_ClosestScalar(ui_get_but_scale_unit(but, step_default), but->block->unit->system, unit_type); - if (step > 0.0f) { /* -1 is an error value */ - return (float)((double)step / ui_get_but_scale_unit(but, 1.0)) * 100.0f; + /* -1 is an error value */ + if (step != -1.0) { + BLI_assert(step > 0.0); + return (float)(step / ui_get_but_scale_unit(but, 1.0)) * 100.0f; } else { return step_default; @@ -2047,13 +2051,14 @@ bool ui_set_but_string(bContext *C, uiBut *but, const char *str) return false; } -void ui_set_but_default(bContext *C, short all) +void ui_set_but_default(bContext *C, const bool all) { + const char *opstring = "UI_OT_reset_default_button"; PointerRNA ptr; - WM_operator_properties_create(&ptr, "UI_OT_reset_default_button"); + WM_operator_properties_create(&ptr, opstring); RNA_boolean_set(&ptr, "all", all); - WM_operator_name_call(C, "UI_OT_reset_default_button", WM_OP_EXEC_DEFAULT, &ptr); + WM_operator_name_call(C, opstring, WM_OP_EXEC_DEFAULT, &ptr); WM_operator_properties_free(&ptr); } @@ -2230,8 +2235,7 @@ void uiFreeBlock(const bContext *C, uiBlock *block) { uiBut *but; - while ( (but = block->buttons.first) ) { - BLI_remlink(&block->buttons, but); + while ((but = BLI_pophead(&block->buttons))) { ui_free_but(C, but); } @@ -2255,8 +2259,7 @@ void uiFreeBlocks(const bContext *C, ListBase *lb) { uiBlock *block; - while ( (block = lb->first) ) { - BLI_remlink(lb, block); + while ((block = BLI_pophead(lb))) { uiFreeBlock(C, block); } } @@ -3024,7 +3027,7 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s but->rnapoin = *ptr; but->rnaprop = prop; - if (RNA_property_array_length(&but->rnapoin, but->rnaprop)) + if (RNA_property_array_check(but->rnaprop)) but->rnaindex = index; else but->rnaindex = 0; diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 3feb563d3ee..5b6b889a6c6 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -144,7 +144,7 @@ int ui_but_anim_expression_create(uiBut *but, const char *str) return 0; } - if (RNA_property_array_length(&but->rnapoin, but->rnaprop) != 0) { + if (RNA_property_array_check(but->rnaprop) != 0) { if (but->rnaindex == -1) { if (G.debug & G_DEBUG) printf("ERROR: create expression failed - can't create expression for entire array\n"); diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index cd845da10c6..11062ea2bd2 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -1389,7 +1389,7 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc if (scopes->track_disabled) { glColor4f(0.7f, 0.3f, 0.3f, 0.3f); - uiSetRoundBox(15); + uiSetRoundBox(UI_CNR_ALL); uiDrawBox(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f); ok = 1; @@ -1437,7 +1437,7 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc if (scopes->use_track_mask) { glColor4f(0.0f, 0.0f, 0.0f, 0.3f); - uiSetRoundBox(15); + uiSetRoundBox(UI_CNR_ALL); uiDrawBox(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f); } @@ -1478,7 +1478,7 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc if (!ok) { glColor4f(0.f, 0.f, 0.f, 0.3f); - uiSetRoundBox(15); + uiSetRoundBox(UI_CNR_ALL); uiDrawBox(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f); } diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c new file mode 100644 index 00000000000..56dd18565dc --- /dev/null +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -0,0 +1,639 @@ +/* + * ***** 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) 2009 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_eyedropper.c + * \ingroup edinterface + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_space_types.h" +#include "DNA_screen_types.h" +#include "DNA_object_types.h" + +#include "BLI_blenlib.h" +#include "BLI_math_vector.h" + +#include "BKE_context.h" +#include "BKE_screen.h" +#include "BKE_report.h" +#include "BKE_idcode.h" + +#include "RNA_access.h" + +#include "BIF_gl.h" + +#include "UI_interface.h" + +#include "IMB_colormanagement.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "interface_intern.h" + +/* for HDR color sampling */ +#include "ED_image.h" +#include "ED_node.h" +#include "ED_clip.h" + +/* for ID data eyedropper */ +#include "ED_space_api.h" +#include "ED_screen.h" +#include "ED_view3d.h" + + +/* -------------------------------------------------------------------- */ +/* Eyedropper + */ + +/** \name Eyedropper (RGB Color) + * \{ */ + +typedef struct Eyedropper { + struct ColorManagedDisplay *display; + + PointerRNA ptr; + PropertyRNA *prop; + int index; + + int accum_start; /* has mouse been presed */ + float accum_col[3]; + int accum_tot; +} Eyedropper; + +static int eyedropper_init(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Eyedropper *eye; + + op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper"); + + uiContextActiveProperty(C, &eye->ptr, &eye->prop, &eye->index); + + if ((eye->ptr.data == NULL) || + (eye->prop == NULL) || + (RNA_property_editable(&eye->ptr, eye->prop) == FALSE) || + (RNA_property_array_length(&eye->ptr, eye->prop) < 3) || + (RNA_property_type(eye->prop) != PROP_FLOAT)) + { + return FALSE; + } + + if (RNA_property_subtype(eye->prop) == PROP_COLOR) { + const char *display_device; + + display_device = scene->display_settings.display_device; + eye->display = IMB_colormanagement_display_get_named(display_device); + } + + return TRUE; +} + +static void eyedropper_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + if (op->customdata) + MEM_freeN(op->customdata); + op->customdata = NULL; +} + +static int eyedropper_cancel(bContext *C, wmOperator *op) +{ + eyedropper_exit(C, op); + return OPERATOR_CANCELLED; +} + +/* *** eyedropper_color_ helper functions *** */ + +/** + * \brief get the color from the screen. + * + * Special check for image or nodes where we MAY have HDR pixels which don't display. + */ +static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int mx, int my, float r_col[3]) +{ + + /* we could use some clever */ + wmWindow *win = CTX_wm_window(C); + ScrArea *sa; + for (sa = win->screen->areabase.first; sa; sa = sa->next) { + if (BLI_rcti_isect_pt(&sa->totrct, mx, my)) { + if (sa->spacetype == SPACE_IMAGE) { + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { + SpaceImage *sima = sa->spacedata.first; + int mval[2] = {mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + + if (ED_space_image_color_sample(sima, ar, mval, r_col)) { + return; + } + } + } + else if (sa->spacetype == SPACE_NODE) { + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { + SpaceNode *snode = sa->spacedata.first; + int mval[2] = {mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + + if (ED_space_node_color_sample(snode, ar, mval, r_col)) { + return; + } + } + } + else if (sa->spacetype == SPACE_CLIP) { + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { + SpaceClip *sc = sa->spacedata.first; + int mval[2] = {mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + + if (ED_space_clip_color_sample(sc, ar, mval, r_col)) { + return; + } + } + } + } + } + + /* fallback to simple opengl picker */ + glReadBuffer(GL_FRONT); + glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col); + glReadBuffer(GL_BACK); +} + +/* sets the sample color RGB, maintaining A */ +static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3]) +{ + float col_conv[4]; + + /* to maintain alpha */ + RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv); + + /* convert from display space to linear rgb space */ + if (eye->display) { + copy_v3_v3(col_conv, col); + IMB_colormanagement_display_to_scene_linear_v3(col_conv, eye->display); + } + else { + copy_v3_v3(col_conv, col); + } + + RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv); + + RNA_property_update(C, &eye->ptr, eye->prop); +} + +/* set sample from accumulated values */ +static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye) +{ + float col[3]; + mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot); + eyedropper_color_set(C, eye, col); +} + +/* single point sample & set */ +static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my) +{ + float col[3]; + eyedropper_color_sample_fl(C, eye, mx, my, col); + eyedropper_color_set(C, eye, col); +} + +static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my) +{ + float col[3]; + eyedropper_color_sample_fl(C, eye, mx, my, col); + /* delay linear conversion */ + add_v3_v3(eye->accum_col, col); + eye->accum_tot++; +} + +/* main modal status check */ +static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + Eyedropper *eye = (Eyedropper *)op->customdata; + + switch (event->type) { + case ESCKEY: + case RIGHTMOUSE: + return eyedropper_cancel(C, op); + case LEFTMOUSE: + if (event->val == KM_RELEASE) { + if (eye->accum_tot == 0) { + eyedropper_color_sample(C, eye, event->x, event->y); + } + else { + eyedropper_color_set_accum(C, eye); + } + eyedropper_exit(C, op); + return OPERATOR_FINISHED; + } + else if (event->val == KM_PRESS) { + /* enable accum and make first sample */ + eye->accum_start = TRUE; + eyedropper_color_sample_accum(C, eye, event->x, event->y); + } + break; + case MOUSEMOVE: + if (eye->accum_start) { + /* button is pressed so keep sampling */ + eyedropper_color_sample_accum(C, eye, event->x, event->y); + eyedropper_color_set_accum(C, eye); + } + break; + case SPACEKEY: + if (event->val == KM_RELEASE) { + eye->accum_tot = 0; + zero_v3(eye->accum_col); + eyedropper_color_sample_accum(C, eye, event->x, event->y); + eyedropper_color_set_accum(C, eye); + } + break; + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (eyedropper_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 { + eyedropper_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int eyedropper_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (eyedropper_init(C, op)) { + + /* do something */ + + /* cleanup */ + eyedropper_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int eyedropper_poll(bContext *C) +{ + if (!CTX_wm_window(C)) return 0; + else return 1; +} + +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"; + + /* api callbacks */ + ot->invoke = eyedropper_invoke; + ot->modal = eyedropper_modal; + ot->cancel = eyedropper_cancel; + ot->exec = eyedropper_exec; + ot->poll = eyedropper_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING; + + /* properties */ +} +/** \} */ + + +/* -------------------------------------------------------------------- */ +/* Data Dropper + * + * note: datadropper is only internal name to avoid confusion in this file + */ + +/** \name Eyedropper (ID data-blocks) + * \{ */ + +typedef struct DataDropper { + PointerRNA ptr; + PropertyRNA *prop; + short idcode; + const char *idcode_name; + + ARegionType *art; + void *draw_handle_pixel; + char name[200]; +} 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_GetStringWidth(name); + x = x - ar->winrct.xmin; + y = y - ar->winrct.ymin; + + y += 20; + + glColor4ub(0, 0, 0, 50); + + uiSetRoundBox(UI_CNR_ALL | UI_RB_ALPHA); + uiRoundBox(x, y, x + width + 8, y + 15, 4); + + glColor4ub(255, 255, 255, 255); + UI_DrawString(x + 4, y + 4, name); +} + + +static int datadropper_init(bContext *C, wmOperator *op) +{ + DataDropper *ddr; + int index_dummy; + StructRNA *type; + + 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(DataDropper), "DataDropper"); + + uiContextActiveProperty(C, &ddr->ptr, &ddr->prop, &index_dummy); + + if ((ddr->ptr.data == NULL) || + (ddr->prop == NULL) || + (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || + (RNA_property_type(ddr->prop) != PROP_POINTER)) + { + return false; + } + + ddr->art = art; + ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL); + + type = RNA_property_pointer_type(&ddr->ptr, ddr->prop); + ddr->idcode = RNA_type_to_ID_code(type); + BLI_assert(ddr->idcode != 0); + ddr->idcode_name = BKE_idcode_to_name(ddr->idcode); + + return true; +} + +static void datadropper_exit(bContext *C, wmOperator *op) +{ + DataDropper *ddr = (DataDropper *)op->customdata; + + WM_cursor_modal_restore(CTX_wm_window(C)); + + ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel); + + if (op->customdata) + MEM_freeN(op->customdata); + op->customdata = NULL; +} + +static int datadropper_cancel(bContext *C, wmOperator *op) +{ + datadropper_exit(C, op); + return OPERATOR_CANCELLED; +} + +/* *** datadropper id helper functions *** */ +/** + * \brief get the ID from the screen. + * + */ +static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id) +{ + + /* we could use some clever */ + wmWindow *win = CTX_wm_window(C); + ScrArea *sa; + + 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)) { + int mval[2] = {mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + Base *base; + + 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); + + base = ED_view3d_give_base_under_cursor(C, mval); + if (base) { + Object *ob = base->object; + ID *id = NULL; + if (ddr->idcode == ID_OB) { + id = (ID *)ob; + } + else if (ob->data) { + if (GS(((ID *)ob->data)->name) == ddr->idcode) { + id = (ID *)ob->data; + } + else { + BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s", + ddr->idcode_name); + } + } + + if (id) { + BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s", + ddr->idcode_name, id->name + 2); + *r_id = id; + } + + break; + } + } + } + } + } + + CTX_wm_area_set(C, area_prev); + CTX_wm_region_set(C, ar_prev); +} + +/* sets the ID, returns success */ +static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id) +{ + PointerRNA ptr_value; + + RNA_id_pointer_create(id, &ptr_value); + + RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value); + + RNA_property_update(C, &ddr->ptr, ddr->prop); + + ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop); + + return (ptr_value.id.data == id); +} + +/* single point sample & set */ +static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my) +{ + ID *id = NULL; + + datadropper_id_sample_pt(C, ddr, mx, my, &id); + return datadropper_id_set(C, ddr, id); +} + +/* main modal status check */ +static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + DataDropper *ddr = (DataDropper *)op->customdata; + + switch (event->type) { + case ESCKEY: + case RIGHTMOUSE: + return datadropper_cancel(C, op); + case LEFTMOUSE: + if (event->val == KM_RELEASE) { + bool success; + + success = datadropper_id_sample(C, ddr, event->x, event->y); + datadropper_exit(C, op); + + if (success) { + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_WARNING, "Failed to set value"); + return OPERATOR_CANCELLED; + } + } + break; + case MOUSEMOVE: + { + ID *id = NULL; + datadropper_id_sample_pt(C, ddr, event->x, event->y, &id); + break; + } + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (datadropper_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 { + datadropper_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int datadropper_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (datadropper_init(C, op)) { + /* cleanup */ + datadropper_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int datadropper_poll(bContext *C) +{ + if (!CTX_wm_window(C)) return 0; + else return 1; +} + +void UI_OT_eyedropper_id(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper Datablock"; + ot->idname = "UI_OT_eyedropper_id"; + ot->description = "Sample a color from the Blender Window to store in a property"; + + /* api callbacks */ + ot->invoke = datadropper_invoke; + ot->modal = datadropper_modal; + ot->cancel = datadropper_cancel; + ot->exec = datadropper_exec; + ot->poll = datadropper_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 f9ee2b67e6b..c5faa99e067 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -152,7 +152,9 @@ typedef struct uiHandleButtonData { char *str, *origstr; double value, origvalue, startvalue; float vec[3], origvec[3]; +#if 0 /* UNUSED */ int togdual, togonly; +#endif ColorBand *coba; /* tooltip */ @@ -170,6 +172,7 @@ typedef struct uiHandleButtonData { /* coords are Window/uiBlock relative (depends on the button) */ int draglastx, draglasty; int dragstartx, dragstarty; + int draglastvalue; bool dragchange, draglock; int dragsel; float dragf, dragfstart; @@ -1978,7 +1981,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) ui_check_but(but); - WM_cursor_modal(CTX_wm_window(C), BC_TEXTEDITCURSOR); + WM_cursor_modal_set(CTX_wm_window(C), BC_TEXTEDITCURSOR); } static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) @@ -2010,7 +2013,7 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) but->pos = -1; } - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); } static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data) @@ -2094,10 +2097,12 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle break; case RIGHTMOUSE: case ESCKEY: - data->cancel = true; - data->escapecancel = true; - button_activate_state(C, but, BUTTON_STATE_EXIT); - retval = WM_UI_HANDLER_BREAK; + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + retval = WM_UI_HANDLER_BREAK; + } break; case LEFTMOUSE: { @@ -2217,13 +2222,21 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle case BACKSPACEKEY: changed = ui_textedit_delete(but, data, 0, - event->shift ? STRCUR_JUMP_ALL : (event->ctrl ? STRCUR_JUMP_DELIM : STRCUR_JUMP_NONE)); + event->ctrl ? STRCUR_JUMP_DELIM : STRCUR_JUMP_NONE); retval = WM_UI_HANDLER_BREAK; break; case AKEY: + /* Ctrl + A: Select all */ - if (event->ctrl && !(event->alt || event->shift || event->oskey)) { +#if defined(__APPLE__) + /* OSX uses cmd-a systemwide, so add it */ + if ((event->oskey && !(event->alt || event->shift || event->ctrl)) || + (event->ctrl && !(event->alt || event->shift || event->oskey))) +#else + if (event->ctrl && !(event->alt || event->shift || event->oskey)) +#endif + { ui_textedit_move(but, data, STRCUR_DIR_PREV, false, STRCUR_JUMP_ALL); ui_textedit_move(but, data, STRCUR_DIR_NEXT, @@ -2566,9 +2579,11 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data return WM_UI_HANDLER_BREAK; } else if (event->type == ESCKEY) { - data->cancel = true; - data->escapecancel = true; - button_activate_state(C, but, BUTTON_STATE_EXIT); + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } } } @@ -2606,7 +2621,10 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton { if (data->state == BUTTON_STATE_HIGHLIGHT) { if (ELEM4(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) { - if (but->dt == UI_EMBOSSN && !event->ctrl) { + if (ELEM(event->type, PADENTER, RETKEY) && (!ui_is_but_utf8(but))) { + /* pass - allow filesel, enter to execute */ + } + else if (but->dt == UI_EMBOSSN && !event->ctrl) { /* pass */ } else { @@ -2640,13 +2658,8 @@ static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHa BLI_rcti_rctf_copy(&rect, &but->rect); rect.xmin = rect.xmax - (BLI_rcti_size_y(&rect)); - if ( BLI_rcti_isect_pt(&rect, x, y) ) { - /* most likely NULL, but let's check, and give it temp zero string */ - if (data->str == NULL) - data->str = MEM_callocN(16, "temp str"); - data->str[0] = 0; - - ui_apply_but_TEX(C, but, data); + if (BLI_rcti_isect_pt(&rect, x, y)) { + ui_set_but_string(C, but, ""); button_activate_state(C, but, BUTTON_STATE_EXIT); return WM_UI_HANDLER_BREAK; @@ -2660,8 +2673,10 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons #ifdef USE_DRAG_TOGGLE if (data->state == BUTTON_STATE_HIGHLIGHT) { if (event->type == LEFTMOUSE && event->val == KM_PRESS && ui_is_but_bool(but)) { +#if 0 /* UNUSED */ data->togdual = event->ctrl; data->togonly = !event->shift; +#endif ui_apply_button(C, but->block, but, data, true); button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); data->dragstartx = event->x; @@ -2677,8 +2692,10 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons #endif if (data->state == BUTTON_STATE_HIGHLIGHT) { if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { +#if 0 /* UNUSED */ data->togdual = event->ctrl; data->togonly = !event->shift; +#endif button_activate_state(C, but, BUTTON_STATE_EXIT); return WM_UI_HANDLER_BREAK; } @@ -3007,9 +3024,11 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton } else if (data->state == BUTTON_STATE_NUM_EDITING) { if (event->type == ESCKEY || event->type == RIGHTMOUSE) { - data->cancel = true; - data->escapecancel = true; - button_activate_state(C, but, BUTTON_STATE_EXIT); + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } } else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { if (data->dragchange) @@ -3271,9 +3290,11 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton } else if (data->state == BUTTON_STATE_NUM_EDITING) { if (event->type == ESCKEY || event->type == RIGHTMOUSE) { - data->cancel = TRUE; - data->escapecancel = TRUE; - button_activate_state(C, but, BUTTON_STATE_EXIT); + if (event->val == KM_PRESS) { + data->cancel = TRUE; + data->escapecancel = TRUE; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } } else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { if (data->dragchange) @@ -3388,9 +3409,11 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut } else if (data->state == BUTTON_STATE_NUM_EDITING) { if (event->type == ESCKEY) { - data->cancel = true; - data->escapecancel = true; - button_activate_state(C, but, BUTTON_STATE_EXIT); + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } } else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { button_activate_state(C, but, BUTTON_STATE_EXIT); @@ -3406,6 +3429,102 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut return retval; } +static int ui_do_but_LISTBOX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +{ + uiList *ui_list = but->custom_data; + int *size = (int *)but->poin; + int mx, my, raw_dir_sign; + int retval = WM_UI_HANDLER_CONTINUE; + + mx = event->x; + my = event->y; + + /* We find the direction of the mouse since last time, before converting coordinates into block's space. + * We'll use it to avoid flickering in case some rows are higher than UI_UNIT_Y. + */ + raw_dir_sign = (data->draglasty - my < 0) ? -1 : 1; + data->draglasty = my; + + ui_window_to_block(data->region, block, &mx, &my); + + if (data->state == BUTTON_STATE_NUM_EDITING) { + if (event->type == ESCKEY) { + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + *size = (int)data->origvalue; + button_activate_state(C, but, BUTTON_STATE_EXIT); + ui_list->flag &= ~UILST_RESIZING; + ED_region_tag_redraw(data->region); + } + } + else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + button_activate_state(C, but, BUTTON_STATE_EXIT); + ui_list->flag &= ~UILST_RESIZING; + ED_region_tag_redraw(data->region); + } + else if (event->type == MOUSEMOVE) { + /* If we switched from dragged to auto size, suspend shrinking dragging and set dragstarty to a temp + * refpoint. + */ + if (data->draglastvalue > 0 && *size == 0) { + data->draglastvalue = *size; + data->dragstartx = data->dragstarty; /* draglasty already used... */ + data->dragstarty = my; + } + else { + int delta = data->dragstarty - my; + /* We only actually do something if the real mousemouve direction matches the "virtual" + * mousemove direction in current block's space. This avoids flickering when drag-resizing lists with + * items drawing higher that UI_UNIT_Y. + */ + if (delta * raw_dir_sign > 0) { + /* Number of rows to show/hide, UI_UNIT_Y should work nice in most cases. */ + delta = (int)floorf(((float)delta / (float)UI_UNIT_Y) + 0.5f); + + /* If we are not in autosize mode, default behavior... */ + if (*size > 0 && delta != 0) { + /* This prevents some instability in case some items draw more/less than UI_UNIT_Y height. */ + delta = (delta < -5) ? -5 : (delta > 5) ? 5 : delta; + /* We can't use ui_numedit_apply()... */ + /* list template will clamp, but we do not want to reach 0 aka autosize mode! */ + *size = max_ii(*size + delta, 1); + + /* Used to detect switch to/from autosize mode. */ + data->draglastvalue = *size; + + data->dragchange = true; + data->applied = data->applied_interactive = true; + + ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; + ED_region_tag_redraw(data->region); + } + /* If we are leaving autosize mode (growing dragging), restore to minimal size. */ + else if (delta > 0) { + /* We can't use ui_numedit_apply()... */ + *size = ui_list->dyn_data->visual_height_min; + + /* Restore real dragstarty value! */ + data->dragstarty = data->dragstartx; + + /* Used to detect switch to/from autosize mode. */ + data->draglastvalue = *size; + + data->dragchange = true; + data->applied = data->applied_interactive = true; + + ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; + ED_region_tag_redraw(data->region); + } + } + } + } + + retval = WM_UI_HANDLER_BREAK; + } + + return retval; +} static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { @@ -3466,31 +3585,6 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co return WM_UI_HANDLER_BREAK; } } - else if (but->type == COLOR) { - if (ELEM3(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) { - float *hsv = ui_block_hsv_get(but->block); - float col[3]; - - ui_get_but_vectorf(but, col); - rgb_to_hsv_compat_v(col, hsv); - - if (event->type == WHEELDOWNMOUSE) - hsv[2] = CLAMPIS(hsv[2] - 0.05f, 0.0f, 1.0f); - else if (event->type == WHEELUPMOUSE) - hsv[2] = CLAMPIS(hsv[2] + 0.05f, 0.0f, 1.0f); - else { - float fac = 0.005 * (event->y - event->prevy); - hsv[2] = CLAMPIS(hsv[2] + fac, 0.0f, 1.0f); - } - - hsv_to_rgb_v(hsv, data->vec); - ui_set_but_vectorf(but, data->vec); - - button_activate_state(C, but, BUTTON_STATE_EXIT); - ui_apply_button(C, but->block, but, data, true); - return WM_UI_HANDLER_BREAK; - } - } } else if (data->state == BUTTON_STATE_WAIT_DRAG) { @@ -3578,6 +3672,41 @@ static bool ui_numedit_but_NORMAL(uiBut *but, uiHandleButtonData *data, int mx, return changed; } +static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +{ + if (data->state == BUTTON_STATE_HIGHLIGHT) { + if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { + button_activate_state(C, but, BUTTON_STATE_MENU_OPEN); + return WM_UI_HANDLER_BREAK; + } + else if (ELEM3(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) { + float *hsv = ui_block_hsv_get(but->block); + float col[3]; + + ui_get_but_vectorf(but, col); + rgb_to_hsv_compat_v(col, hsv); + + if (event->type == WHEELDOWNMOUSE) + hsv[2] = CLAMPIS(hsv[2] - 0.05f, 0.0f, 1.0f); + else if (event->type == WHEELUPMOUSE) + hsv[2] = CLAMPIS(hsv[2] + 0.05f, 0.0f, 1.0f); + else { + float fac = 0.005 * (event->y - event->prevy); + hsv[2] = CLAMPIS(hsv[2] + fac, 0.0f, 1.0f); + } + + hsv_to_rgb_v(hsv, data->vec); + ui_set_but_vectorf(but, data->vec); + + button_activate_state(C, but, BUTTON_STATE_EXIT); + ui_apply_button(C, but->block, but, data, true); + return WM_UI_HANDLER_BREAK; + } + } + + return WM_UI_HANDLER_CONTINUE; +} + static int ui_do_but_NORMAL(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -3875,9 +4004,11 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu } else if (data->state == BUTTON_STATE_NUM_EDITING) { if (event->type == ESCKEY || event->type == RIGHTMOUSE) { - data->cancel = true; - data->escapecancel = true; - button_activate_state(C, but, BUTTON_STATE_EXIT); + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } } else if (event->type == MOUSEMOVE) { if (mx != data->draglastx || my != data->draglasty) { @@ -4086,9 +4217,11 @@ static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandle } else if (data->state == BUTTON_STATE_NUM_EDITING) { if (event->type == ESCKEY || event->type == RIGHTMOUSE) { - data->cancel = true; - data->escapecancel = true; - button_activate_state(C, but, BUTTON_STATE_EXIT); + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } } /* XXX hardcoded keymap check.... */ else if (event->type == WHEELDOWNMOUSE) { @@ -4531,9 +4664,11 @@ static int ui_do_but_HISTOGRAM(bContext *C, uiBlock *block, uiBut *but, uiHandle } else if (data->state == BUTTON_STATE_NUM_EDITING) { if (event->type == ESCKEY) { - data->cancel = true; - data->escapecancel = true; - button_activate_state(C, but, BUTTON_STATE_EXIT); + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } } else if (event->type == MOUSEMOVE) { if (mx != data->draglastx || my != data->draglasty) { @@ -4614,9 +4749,11 @@ static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleB } else if (data->state == BUTTON_STATE_NUM_EDITING) { if (event->type == ESCKEY) { - data->cancel = true; - data->escapecancel = true; - button_activate_state(C, but, BUTTON_STATE_EXIT); + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } } else if (event->type == MOUSEMOVE) { if (mx != data->draglastx || my != data->draglasty) { @@ -4681,9 +4818,11 @@ static int ui_do_but_VECTORSCOPE(bContext *C, uiBlock *block, uiBut *but, uiHand } else if (data->state == BUTTON_STATE_NUM_EDITING) { if (event->type == ESCKEY) { - data->cancel = true; - data->escapecancel = true; - button_activate_state(C, but, BUTTON_STATE_EXIT); + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } } else if (event->type == MOUSEMOVE) { if (mx != data->draglastx || my != data->draglasty) { @@ -4792,9 +4931,11 @@ static int ui_do_but_TRACKPREVIEW(bContext *C, uiBlock *block, uiBut *but, uiHan } else if (data->state == BUTTON_STATE_NUM_EDITING) { if (event->type == ESCKEY) { - data->cancel = true; - data->escapecancel = true; - button_activate_state(C, but, BUTTON_STATE_EXIT); + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } } else if (event->type == MOUSEMOVE) { if (mx != data->draglastx || my != data->draglasty) { @@ -4967,7 +5108,12 @@ static bool ui_but_menu(bContext *C, uiBut *but) uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); if (but->rnapoin.data && but->rnaprop) { - bool is_anim = RNA_property_animateable(&but->rnapoin, but->rnaprop); + PointerRNA *ptr = &but->rnapoin; + PropertyRNA *prop = but->rnaprop; + bool is_anim = RNA_property_animateable(ptr, prop); + bool is_editable = RNA_property_editable(ptr, prop); + /*bool is_idprop = RNA_property_is_idprop(prop);*/ /* XXX does not work as expected, not strictly needed */ + bool is_set = RNA_property_is_set(ptr, prop); /* second slower test, saved people finding keyframe items in menus when its not possible */ if (is_anim) @@ -5114,6 +5260,10 @@ static bool ui_but_menu(bContext *C, uiBut *but) uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Reset to Default Value"), ICON_NONE, "UI_OT_reset_default_button", "all", 1); } + if (is_editable /*&& is_idprop*/ && is_set) { + uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Unset"), + ICON_NONE, "UI_OT_unset_property_button"); + } uiItemO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Data Path"), ICON_NONE, "UI_OT_copy_data_path_button"); @@ -5161,13 +5311,12 @@ static bool ui_but_menu(bContext *C, uiBut *but) } /* Show header tools for header buttons. */ - if (CTX_wm_region(C)) { + { ARegion *ar = CTX_wm_region(C); - if (ar->regiontype == RGN_TYPE_HEADER) { - - uiItemMenuF(layout, IFACE_("Header"), ICON_NONE, ED_screens_header_tools_menu_create, NULL); - uiItemS(layout); - } + if (ar && (ar->regiontype == RGN_TYPE_HEADER)) { + uiItemMenuF(layout, IFACE_("Header"), ICON_NONE, ED_screens_header_tools_menu_create, NULL); + uiItemS(layout); + } } { /* Docs */ @@ -5256,6 +5405,28 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * else if (event->type == EVT_DROP) { ui_but_drop(C, event, but, data); } + /* handle eyedropper */ + else if ((event->type == EKEY) && (event->val == KM_PRESS)) { + if (event->alt || event->shift || event->ctrl || event->oskey) { + /* pass */ + } + else { + if (but->type == COLOR) { + WM_operator_name_call(C, "UI_OT_eyedropper_color", WM_OP_INVOKE_DEFAULT, NULL); + return WM_UI_HANDLER_BREAK; + } + else if (but->type == SEARCH_MENU_UNLINK) { + if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_POINTER) { + StructRNA *type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop); + const short idcode = RNA_type_to_ID_code(type); + if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) { + WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL); + return WM_UI_HANDLER_BREAK; + } + } + } + } + } /* handle keyframing */ else if ((event->type == IKEY) && !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey) && @@ -5273,7 +5444,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * ui_but_anim_insert_keyframe(C); } - ED_region_tag_redraw(CTX_wm_region(C)); + ED_region_tag_redraw(data->region); return WM_UI_HANDLER_BREAK; } @@ -5287,7 +5458,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * else ui_but_anim_add_driver(C); - ED_region_tag_redraw(CTX_wm_region(C)); + ED_region_tag_redraw(data->region); return WM_UI_HANDLER_BREAK; } @@ -5301,17 +5472,10 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * else ui_but_anim_add_keyingset(C); - ED_region_tag_redraw(CTX_wm_region(C)); + ED_region_tag_redraw(data->region); return WM_UI_HANDLER_BREAK; } - /* reset to default */ - /* XXX hardcoded keymap check.... */ - else if (event->type == BACKSPACEKEY && event->val == KM_PRESS) { - /* ctrl+backspace = reset active button; backspace = reset a whole array*/ - if (!(ELEM3(but->type, HSVCIRCLE, HSVCUBE, HISTOGRAM))) - ui_set_but_default(C, !event->ctrl); - } /* handle menu */ else if (event->type == RIGHTMOUSE && event->val == KM_PRESS) { /* RMB has two options now */ @@ -5367,8 +5531,10 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case NUMSLI: retval = ui_do_but_SLI(C, block, but, data, event); break; - case ROUNDBOX: case LISTBOX: + retval = ui_do_but_LISTBOX(C, block, but, data, event); + break; + case ROUNDBOX: case LABEL: case LISTLABEL: case ROW: @@ -5406,7 +5572,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * if (but->a1 == UI_GRAD_V_ALT) /* signal to prevent calling up color picker */ retval = ui_do_but_EXIT(C, but, data, event); else - retval = ui_do_but_BLOCK(C, but, data, event); + retval = ui_do_but_COLOR(C, but, data, event); break; case BUT_NORMAL: retval = ui_do_but_NORMAL(C, block, but, data, event); @@ -5436,7 +5602,22 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case BUT_EXTRA: break; } - + + + /* reset to default (generic function, only use if not handled by switch above) */ + /* XXX hardcoded keymap check.... */ + if (data->state == BUTTON_STATE_HIGHLIGHT) { + if ((retval == WM_UI_HANDLER_CONTINUE) && + (event->type == BACKSPACEKEY && event->val == KM_PRESS)) + { + /* ctrl+backspace = reset active button; backspace = reset a whole array*/ + ui_set_but_default(C, !event->ctrl); + ED_region_tag_redraw(data->region); + retval = WM_UI_HANDLER_BREAK; + } + } + + return retval; } @@ -5622,8 +5803,6 @@ static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y) uiBut *but; int mx, my; -// if (!win->active) -// return NULL; if (!ui_mouse_inside_region(ar, x, y)) return NULL; @@ -5768,7 +5947,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s WM_cursor_grab_disable(data->window, NULL); } #else - WM_cursor_grab_disable(data->window, ); + WM_cursor_grab_disable(data->window, NULL); #endif } } @@ -6423,90 +6602,166 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar) { - uiBut *but = ui_list_find_mouse_over(ar, event->x, event->y); + uiBut *but, *dragbut; + uiList *ui_list; + uiListDyn *dyn_data; int retval = WM_UI_HANDLER_CONTINUE; int type = event->type, val = event->val; + int mx, my; + bool is_over_dragbut = false; - if (but) { - uiList *ui_list = but->custom_data; + but = ui_list_find_mouse_over(ar, event->x, event->y); + if (!but) { + return retval; + } - if (ui_list) { - - /* convert pan to scrollwheel */ - if (type == MOUSEPAN) { - ui_pan_to_scroll(event, &type, &val); - - /* if type still is mousepan, we call it handled, since delta-y accumulate */ - /* also see wm_event_system.c do_wheel_ui hack */ - if (type == MOUSEPAN) - retval = WM_UI_HANDLER_BREAK; - } - - if (val == KM_PRESS) { - - if (ELEM(type, UPARROWKEY, DOWNARROWKEY) || - ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt))) - { - const int value_orig = RNA_property_int_get(&but->rnapoin, but->rnaprop); - int value, min, max; + ui_list = but->custom_data; + if (!ui_list || !ui_list->dyn_data) { + return retval; + } + dyn_data = ui_list->dyn_data; + + mx = event->x; + my = event->y; + ui_window_to_block(ar, but->block, &mx, &my); - /* activate up/down the list */ - value = value_orig; + /* Find our "dragging" button. */ + for (dragbut = but->block->buttons.first; dragbut; dragbut = dragbut->next) { + if (dragbut->poin == (void *)ui_list) { + break; + } + } + if (dragbut && dragbut == ui_but_find_mouse_over(ar, event->x, event->y)) { + is_over_dragbut = true; + } - if (ELEM(type, UPARROWKEY, WHEELUPMOUSE)) - value--; - else - value++; + if (is_over_dragbut && type == LEFTMOUSE && val == KM_PRESS) { + uiHandleButtonData *data; + int *size = (int *)but->poin; - CLAMP(value, 0, ui_list->list_last_len - 1); + ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE); + button_activate_state(C, but, BUTTON_STATE_INIT); - if (value < ui_list->list_scroll) - ui_list->list_scroll = value; - else if (value >= ui_list->list_scroll + ui_list->list_size) - ui_list->list_scroll = value - ui_list->list_size + 1; + data = but->active; + data->dragstarty = my; + + button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); + + /* Again, have to override values set by ui_numedit_begin, because our listbox button also has a rnapoin... */ + *size = data->origvalue = (double)dyn_data->visual_height; + ui_list->flag |= UILST_RESIZING; + + retval = WM_UI_HANDLER_BREAK; + } + else { + /* convert pan to scrollwheel */ + if (type == MOUSEPAN) { + ui_pan_to_scroll(event, &type, &val); + + /* if type still is mousepan, we call it handled, since delta-y accumulate */ + /* also see wm_event_system.c do_wheel_ui hack */ + if (type == MOUSEPAN) + retval = WM_UI_HANDLER_BREAK; + } - RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max); - value = CLAMPIS(value, min, max); + if (val == KM_PRESS) { + if (ELEM(type, UPARROWKEY, DOWNARROWKEY) || + ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt))) + { + const int value_orig = RNA_property_int_get(&but->rnapoin, but->rnaprop); + int value, min, max, inc; - if (value != value_orig) { - RNA_property_int_set(&but->rnapoin, but->rnaprop, value); - RNA_property_update(C, &but->rnapoin, but->rnaprop); + /* activate up/down the list */ + value = value_orig; + if ((ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) != 0) { + inc = ELEM(type, UPARROWKEY, WHEELUPMOUSE) ? 1 : -1; + } + else { + inc = ELEM(type, UPARROWKEY, WHEELUPMOUSE) ? -1 : 1; + } - ui_apply_undo(but); - ED_region_tag_redraw(ar); + if (dyn_data->items_filter_neworder || dyn_data->items_filter_flags) { + /* If we have a display order different from collection order, we have some work! */ + int *org_order = MEM_mallocN(dyn_data->items_shown * sizeof(int), AT); + int *new_order = dyn_data->items_filter_neworder; + int i, org_idx = -1, len = dyn_data->items_len; + int current_idx = -1; + int filter_exclude = ui_list->filter_flag & UILST_FLT_EXCLUDE; + + for (i = 0; i < len; i++) { + if (!dyn_data->items_filter_flags || + ((dyn_data->items_filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude)) + { + org_order[new_order ? new_order[++org_idx] : ++org_idx] = i; + if (i == value) { + current_idx = new_order ? new_order[org_idx] : org_idx; + } + } + else if (i == value && org_idx >= 0) { + current_idx = -(new_order ? new_order[org_idx] : org_idx) - 1; + } + } + /* Now, org_order maps displayed indices to real indices, + * and current_idx either contains the displayed index of active value (positive), + * or its more-nearest one (negated). + */ + if (current_idx < 0) { + current_idx = (current_idx * -1) + (inc < 0 ? inc : inc - 1); } + else { + current_idx += inc; + } + CLAMP(current_idx, 0, dyn_data->items_shown - 1); + value = org_order[current_idx]; + MEM_freeN(org_order); + } + else { + value += inc; + } - retval = WM_UI_HANDLER_BREAK; + CLAMP(value, 0, dyn_data->items_len - 1); + + RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max); + CLAMP(value, min, max); + + if (value != value_orig) { + RNA_property_int_set(&but->rnapoin, but->rnaprop, value); + RNA_property_update(C, &but->rnapoin, but->rnaprop); + + ui_apply_undo(but); + + ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; + ED_region_tag_redraw(ar); } - else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) { - /* silly replacement for proper grip */ - if (ui_list->list_grip_size == 0) - ui_list->list_grip_size = ui_list->list_size; + retval = WM_UI_HANDLER_BREAK; + } + else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) { + /* We now have proper grip, but keep this anyway! */ + if (ui_list->list_grip == 0) + ui_list->list_grip = dyn_data->visual_height; + /* list template will clamp */ + if (type == WHEELUPMOUSE) + ui_list->list_grip--; + else + ui_list->list_grip++; + + ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM; + ED_region_tag_redraw(ar); + retval = WM_UI_HANDLER_BREAK; + } + else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE)) { + if (dyn_data->height > dyn_data->visual_height) { + /* list template will clamp */ if (type == WHEELUPMOUSE) - ui_list->list_grip_size--; + ui_list->list_scroll--; else - ui_list->list_grip_size++; - - ui_list->list_grip_size = MAX2(ui_list->list_grip_size, 1); + ui_list->list_scroll++; ED_region_tag_redraw(ar); retval = WM_UI_HANDLER_BREAK; } - else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE)) { - if (ui_list->list_last_len > ui_list->list_size) { - /* list template will clamp */ - if (type == WHEELUPMOUSE) - ui_list->list_scroll--; - else - ui_list->list_scroll++; - - ED_region_tag_redraw(ar); - - retval = WM_UI_HANDLER_BREAK; - } - } } } } @@ -7511,6 +7766,8 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata) } else if (temp.cancel_func) temp.cancel_func(C, temp.popup_arg); + + WM_event_add_mousemove(C); } else { /* re-enable tooltips */ diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index d2a8c47b347..9cc16d82810 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -393,7 +393,7 @@ extern bool ui_set_but_string(struct bContext *C, uiBut *but, const char *str); extern bool ui_set_but_string_eval_num(struct bContext *C, uiBut *but, const char *str, double *value); extern int ui_get_but_string_max_length(uiBut *but); -extern void ui_set_but_default(struct bContext *C, short all); +extern void ui_set_but_default(struct bContext *C, const bool all); extern void ui_check_but(uiBut *but); extern bool ui_is_but_float(uiBut *but); @@ -538,7 +538,7 @@ extern void ui_draw_but(const struct bContext *C, ARegion *ar, struct uiStyle *s struct ThemeUI; void ui_widget_color_init(struct ThemeUI *tui); -void ui_draw_menu_item(struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state); +void ui_draw_menu_item(struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state, bool use_sep); void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state); extern const unsigned char checker_stipple_sml[32 * 32 / 8]; @@ -584,4 +584,8 @@ int ui_but_anim_expression_set(uiBut *but, const char *str); int ui_but_anim_expression_create(uiBut *but, const char *str); void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, float cfra); -#endif +/* interface_eyedropper.c */ +void UI_OT_eyedropper_color(struct wmOperatorType *ot); +void UI_OT_eyedropper_id(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 079ba97aa9d..424d2231a03 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -471,6 +471,8 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, in but->type = NUMSLI; if (toggle && but->type == OPTION) but->type = TOG; + if ((a == 0) && (subtype == PROP_AXISANGLE)) + uiButSetUnitType(but, PROP_UNIT_ROTATION); } if (boolarr) { @@ -568,7 +570,7 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *n PropertySubType subtype; int labelw; - sub = uiLayoutRow(layout, FALSE); + sub = uiLayoutRow(layout, layout->align); uiBlockSetCurLayout(block, sub); if (name[0]) { @@ -1465,6 +1467,7 @@ void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propna uiBlock *block; StructRNA *icontype; int w, h; + char namestr[UI_MAX_NAME_STR]; /* validate arguments */ prop = RNA_struct_find_property(ptr, propname); @@ -1507,6 +1510,8 @@ void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propna if (!name) name = RNA_property_ui_name(prop); + name = ui_item_name_add_colon(name, namestr); + /* create button */ block = uiLayoutGetBlock(layout); @@ -2429,6 +2434,15 @@ uiLayout *uiLayoutListBox(uiLayout *layout, uiList *ui_list, PointerRNA *ptr, Pr but->rnapoin = *actptr; but->rnaprop = actprop; + /* Resizing data. */ + /* Note: we can't use usual "num button" value handling, as it only tries rnapoin when it is non-NULL... :/ + * So just setting but->poin, not but->pointype. + */ + but->poin = (void *)&ui_list->list_grip; + but->hardmin = but->softmin = 0.0f; + but->hardmax = but->softmax = 1000.0f; /* Should be more than enough! */ + but->a1 = 0.0f; + /* only for the undo string */ if (but->flag & UI_BUT_UNDO) { but->tip = RNA_property_description(actprop); @@ -2678,8 +2692,9 @@ static void ui_item_align(uiLayout *litem, short nr) BLI_remlink(&litem->root->block->buttons, box->roundbox); BLI_addhead(&litem->root->block->buttons, box->roundbox); } - else + else if (((uiLayout *)item)->align) { ui_item_align((uiLayout *)item, nr); + } } } diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index cfe6e313c58..36e965e13d2 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -27,20 +27,14 @@ * \ingroup edinterface */ -#include <stdio.h> -#include <math.h> #include <string.h> #include "MEM_guardedalloc.h" -#include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_text_types.h" /* for UI_OT_reports_to_text */ #include "BLI_blenlib.h" -#include "BLI_math_color.h" -#include "BLI_math_vector.h" -#include "BLI_utildefines.h" #include "BLF_api.h" #include "BLF_translation.h" @@ -54,12 +48,8 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "BIF_gl.h" - #include "UI_interface.h" -#include "IMB_colormanagement.h" - #include "interface_intern.h" #include "WM_api.h" @@ -70,282 +60,6 @@ #include "BKE_main.h" #include "BLI_ghash.h" -#include "ED_image.h" /* for HDR color sampling */ -#include "ED_node.h" /* for HDR color sampling */ -#include "ED_clip.h" /* for HDR color sampling */ - -/* ********************************************************** */ - -typedef struct Eyedropper { - struct ColorManagedDisplay *display; - - PointerRNA ptr; - PropertyRNA *prop; - int index; - - int accum_start; /* has mouse been presed */ - float accum_col[3]; - int accum_tot; -} Eyedropper; - -static int eyedropper_init(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - Eyedropper *eye; - - op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper"); - - uiContextActiveProperty(C, &eye->ptr, &eye->prop, &eye->index); - - if ((eye->ptr.data == NULL) || - (eye->prop == NULL) || - (RNA_property_editable(&eye->ptr, eye->prop) == FALSE) || - (RNA_property_array_length(&eye->ptr, eye->prop) < 3) || - (RNA_property_type(eye->prop) != PROP_FLOAT)) - { - return FALSE; - } - - if (RNA_property_subtype(eye->prop) == PROP_COLOR) { - const char *display_device; - - display_device = scene->display_settings.display_device; - eye->display = IMB_colormanagement_display_get_named(display_device); - } - - return TRUE; -} - -static void eyedropper_exit(bContext *C, wmOperator *op) -{ - WM_cursor_restore(CTX_wm_window(C)); - - if (op->customdata) - MEM_freeN(op->customdata); - op->customdata = NULL; -} - -static int eyedropper_cancel(bContext *C, wmOperator *op) -{ - eyedropper_exit(C, op); - return OPERATOR_CANCELLED; -} - -/* *** eyedropper_color_ helper functions *** */ - -/** - * \brief get the color from the screen. - * - * Special check for image or nodes where we MAY have HDR pixels which don't display. - */ -static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int mx, int my, float r_col[3]) -{ - - /* we could use some clever */ - wmWindow *win = CTX_wm_window(C); - ScrArea *sa; - for (sa = win->screen->areabase.first; sa; sa = sa->next) { - if (BLI_rcti_isect_pt(&sa->totrct, mx, my)) { - if (sa->spacetype == SPACE_IMAGE) { - ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); - if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { - SpaceImage *sima = sa->spacedata.first; - int mval[2] = {mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - - if (ED_space_image_color_sample(sima, ar, mval, r_col)) { - return; - } - } - } - else if (sa->spacetype == SPACE_NODE) { - ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); - if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { - SpaceNode *snode = sa->spacedata.first; - int mval[2] = {mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - - if (ED_space_node_color_sample(snode, ar, mval, r_col)) { - return; - } - } - } - else if (sa->spacetype == SPACE_CLIP) { - ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); - if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { - SpaceClip *sc = sa->spacedata.first; - int mval[2] = {mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - - if (ED_space_clip_color_sample(sc, ar, mval, r_col)) { - return; - } - } - } - } - } - - /* fallback to simple opengl picker */ - glReadBuffer(GL_FRONT); - glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col); - glReadBuffer(GL_BACK); -} - -/* sets the sample color RGB, maintaining A */ -static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3]) -{ - float col_conv[4]; - - /* to maintain alpha */ - RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv); - - /* convert from display space to linear rgb space */ - if (eye->display) { - copy_v3_v3(col_conv, col); - IMB_colormanagement_display_to_scene_linear_v3(col_conv, eye->display); - } - else { - copy_v3_v3(col_conv, col); - } - - RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv); - - RNA_property_update(C, &eye->ptr, eye->prop); -} - -/* set sample from accumulated values */ -static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye) -{ - float col[3]; - mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot); - eyedropper_color_set(C, eye, col); -} - -/* single point sample & set */ -static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my) -{ - float col[3]; - eyedropper_color_sample_fl(C, eye, mx, my, col); - eyedropper_color_set(C, eye, col); -} - -static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my) -{ - float col[3]; - eyedropper_color_sample_fl(C, eye, mx, my, col); - /* delay linear conversion */ - add_v3_v3(eye->accum_col, col); - eye->accum_tot++; -} - -/* main modal status check */ -static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - Eyedropper *eye = (Eyedropper *)op->customdata; - - switch (event->type) { - case ESCKEY: - case RIGHTMOUSE: - return eyedropper_cancel(C, op); - case LEFTMOUSE: - if (event->val == KM_RELEASE) { - if (eye->accum_tot == 0) { - eyedropper_color_sample(C, eye, event->x, event->y); - } - else { - eyedropper_color_set_accum(C, eye); - } - eyedropper_exit(C, op); - return OPERATOR_FINISHED; - } - else if (event->val == KM_PRESS) { - /* enable accum and make first sample */ - eye->accum_start = TRUE; - eyedropper_color_sample_accum(C, eye, event->x, event->y); - } - break; - case MOUSEMOVE: - if (eye->accum_start) { - /* button is pressed so keep sampling */ - eyedropper_color_sample_accum(C, eye, event->x, event->y); - eyedropper_color_set_accum(C, eye); - } - break; - case SPACEKEY: - if (event->val == KM_RELEASE) { - eye->accum_tot = 0; - zero_v3(eye->accum_col); - eyedropper_color_sample_accum(C, eye, event->x, event->y); - eyedropper_color_set_accum(C, eye); - } - break; - } - - return OPERATOR_RUNNING_MODAL; -} - -/* Modal Operator init */ -static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - /* init */ - if (eyedropper_init(C, op)) { - WM_cursor_modal(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); - - /* add temp handler */ - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; - } - else { - eyedropper_exit(C, op); - return OPERATOR_CANCELLED; - } -} - -/* Repeat operator */ -static int eyedropper_exec(bContext *C, wmOperator *op) -{ - /* init */ - if (eyedropper_init(C, op)) { - - /* do something */ - - /* cleanup */ - eyedropper_exit(C, op); - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } -} - -static int eyedropper_poll(bContext *C) -{ - if (!CTX_wm_window(C)) return 0; - else return 1; -} - -static void UI_OT_eyedropper(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Eyedropper"; - ot->idname = "UI_OT_eyedropper"; - ot->description = "Sample a color from the Blender Window to store in a property"; - - /* api callbacks */ - ot->invoke = eyedropper_invoke; - ot->modal = eyedropper_modal; - ot->cancel = eyedropper_cancel; - ot->exec = eyedropper_exec; - ot->poll = eyedropper_poll; - - /* flags */ - ot->flag = OPTYPE_BLOCKING; - - /* properties */ -} - /* Reset Default Theme ------------------------ */ static int reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op)) @@ -434,6 +148,28 @@ static void UI_OT_copy_data_path_button(wmOperatorType *ot) /* Reset to Default Values Button Operator ------------------------ */ +static int operator_button_property_finish(bContext *C, PointerRNA *ptr, PropertyRNA *prop) +{ + ID *id = ptr->id.data; + + /* perform updates required for this property */ + RNA_property_update(C, ptr, prop); + + /* as if we pressed the button */ + uiContextActivePropertyHandle(C); + + /* Since we don't want to undo _all_ edits to settings, eg window + * edits on the screen or on operator settings. + * it might be better to move undo's inline - campbell */ + if (id && ID_CHECK_UNDO(id)) { + /* do nothing, go ahead with undo */ + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + static int reset_default_button_poll(bContext *C) { PointerRNA ptr; @@ -449,7 +185,6 @@ static int reset_default_button_exec(bContext *C, wmOperator *op) { PointerRNA ptr; PropertyRNA *prop; - int success = 0; int index, all = RNA_boolean_get(op->ptr, "all"); /* try to reset the nominated setting to its default value */ @@ -457,32 +192,11 @@ static int reset_default_button_exec(bContext *C, wmOperator *op) /* if there is a valid property that is editable... */ if (ptr.data && prop && RNA_property_editable(&ptr, prop)) { - if (RNA_property_reset(&ptr, prop, (all) ? -1 : index)) { - /* perform updates required for this property */ - RNA_property_update(C, &ptr, prop); - - /* as if we pressed the button */ - uiContextActivePropertyHandle(C); - - success = 1; - } + if (RNA_property_reset(&ptr, prop, (all) ? -1 : index)) + return operator_button_property_finish(C, &ptr, prop); } - /* Since we don't want to undo _all_ edits to settings, eg window - * edits on the screen or on operator settings. - * it might be better to move undo's inline - campbell */ - if (success) { - ID *id = ptr.id.data; - if (id && ID_CHECK_UNDO(id)) { - /* do nothing, go ahead with undo */ - } - else { - return OPERATOR_CANCELLED; - } - } - /* end hack */ - - return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; } static void UI_OT_reset_default_button(wmOperatorType *ot) @@ -503,6 +217,43 @@ static void UI_OT_reset_default_button(wmOperatorType *ot) RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array"); } +/* Unset Property Button Operator ------------------------ */ + +static int unset_property_button_exec(bContext *C, wmOperator *UNUSED(op)) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index; + + /* try to unset the nominated property */ + uiContextActiveProperty(C, &ptr, &prop, &index); + + /* if there is a valid property that is editable... */ + if (ptr.data && prop && RNA_property_editable(&ptr, prop) + /*&& RNA_property_is_idprop(prop)*/ && RNA_property_is_set(&ptr, prop)) + { + RNA_property_unset(&ptr, prop); + return operator_button_property_finish(C, &ptr, prop); + } + + return OPERATOR_CANCELLED; +} + +static void UI_OT_unset_property_button(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Unset property"; + ot->idname = "UI_OT_unset_property_button"; + ot->description = "Clear the property and use default or generated value in operators"; + + /* callbacks */ + ot->poll = ED_operator_regionactive; + ot->exec = unset_property_button_exec; + + /* flags */ + ot->flag = OPTYPE_UNDO; +} + /* Copy To Selected Operator ------------------------ */ static int copy_to_selected_list(bContext *C, PointerRNA *ptr, ListBase *lb, int *use_path) @@ -1077,10 +828,10 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot) void UI_buttons_operatortypes(void) { - WM_operatortype_append(UI_OT_eyedropper); WM_operatortype_append(UI_OT_reset_default_theme); WM_operatortype_append(UI_OT_copy_data_path_button); WM_operatortype_append(UI_OT_reset_default_button); + WM_operatortype_append(UI_OT_unset_property_button); WM_operatortype_append(UI_OT_copy_to_selected_button); WM_operatortype_append(UI_OT_reports_to_textblock); /* XXX: temp? */ @@ -1089,4 +840,8 @@ void UI_buttons_operatortypes(void) WM_operatortype_append(UI_OT_edittranslation_init); #endif WM_operatortype_append(UI_OT_reloadtranslation); + + /* external */ + WM_operatortype_append(UI_OT_eyedropper_color); + WM_operatortype_append(UI_OT_eyedropper_id); } diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 95f47be0b70..15fbd51c6fc 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -196,7 +196,7 @@ static MenuData *decompose_menu_string(const char *str) s++; } } - else if (c == '|' || c == '\n' || c == '\0') { + else if (c == UI_SEP_CHAR || c == '\n' || c == '\0') { if (nitem) { *s = '\0'; @@ -770,6 +770,7 @@ typedef struct uiSearchboxData { int active; /* index in items array */ bool noback; /* when menu opened with enough space for this */ bool preview; /* draw thumbnail previews, rather than list */ + bool use_sep; /* use the UI_SEP_CHAR char for splitting shortcuts (good for operators, bad for data) */ int prv_rows, prv_cols; } uiSearchboxData; @@ -928,7 +929,7 @@ bool ui_searchbox_apply(uiBut *but, ARegion *ar) if (data->active != -1) { const char *name = data->items.names[data->active]; - const char *name_sep = strchr(name, '|'); + const char *name_sep = data->use_sep ? strchr(name, UI_SEP_CHAR) : NULL; BLI_strncpy(but->editstr, name, name_sep ? (name_sep - name) : data->items.maxstrlen); @@ -1034,7 +1035,7 @@ void ui_searchbox_update(bContext *C, ARegion *ar, uiBut *but, const bool reset) for (a = 0; a < data->items.totitem; a++) { const char *name = data->items.names[a]; - const char *name_sep = strchr(name, '|'); + const char *name_sep = data->use_sep ? strchr(name, UI_SEP_CHAR) : NULL; if (STREQLEN(but->editstr, name, name_sep ? (name_sep - name) : data->items.maxstrlen)) { data->active = a; break; @@ -1087,10 +1088,14 @@ static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) ui_searchbox_butrect(&rect, data, a); /* widget itself */ - if (data->preview) - ui_draw_preview_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a == data->active) ? UI_ACTIVE : 0); - else - ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a == data->active) ? UI_ACTIVE : 0); + if (data->preview) { + ui_draw_preview_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], + (a == data->active) ? UI_ACTIVE : 0); + } + else { + ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], + (a == data->active) ? UI_ACTIVE : 0, data->use_sep); + } } /* indicate more */ @@ -1114,7 +1119,8 @@ static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) ui_searchbox_butrect(&rect, data, a); /* widget itself */ - ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a == data->active) ? UI_ACTIVE : 0); + ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], + (a == data->active) ? UI_ACTIVE : 0, data->use_sep); } /* indicate more */ @@ -1194,6 +1200,11 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but) data->prv_rows = but->a1; data->prv_cols = but->a2; } + + /* only show key shortcuts when needed (not rna buttons) [#36699] */ + if (but->rnaprop == NULL) { + data->use_sep = true; + } /* compute position */ if (but->block->flag & UI_BLOCK_SEARCH_MENU) { @@ -2174,7 +2185,7 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper yco = -3.0f * UI_UNIT_Y; if (show_picker) { - bt = uiDefIconButO(block, BUT, "UI_OT_eyedropper", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, butwidth + 10, yco, UI_UNIT_X, UI_UNIT_Y, NULL); + bt = uiDefIconButO(block, BUT, "UI_OT_eyedropper_color", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, butwidth + 10, yco, UI_UNIT_X, UI_UNIT_Y, NULL); uiButSetFunc(bt, close_popup_cb, bt, NULL); } @@ -2301,11 +2312,11 @@ static int ui_popup_string_hash(const char *str) { /* sometimes button contains hotkey, sometimes not, strip for proper compare */ int hash; - char *delimit = strchr(str, '|'); + char *delimit = strchr(str, UI_SEP_CHAR); - if (delimit) *delimit = 0; + if (delimit) *delimit = '\0'; hash = BLI_ghashutil_strhash(str); - if (delimit) *delimit = '|'; + if (delimit) *delimit = UI_SEP_CHAR; return hash; } @@ -2605,12 +2616,10 @@ static void confirm_cancel_operator(bContext *UNUSED(C), void *opv) WM_operator_free(opv); } -static void vconfirm_opname(bContext *C, const char *opname, const char *title, const char *itemfmt, va_list ap) -#ifdef __GNUC__ -__attribute__ ((format(printf, 4, 0))) -#endif -; -static void vconfirm_opname(bContext *C, const char *opname, const char *title, const char *itemfmt, va_list ap) +static void vconfirm_opname(bContext *C, const char *opname, const char *title, + const char *itemfmt, va_list ap) ATTR_PRINTF_FORMAT(4, 0); +static void vconfirm_opname(bContext *C, const char *opname, const char *title, + const char *itemfmt, va_list ap) { uiPopupBlockHandle *handle; char *s, buf[512]; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 61cc021800e..6b6b7114c84 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1,4 +1,5 @@ /* + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -43,6 +44,7 @@ #include "BLI_rect.h" #include "BLI_math.h" #include "BLI_listbase.h" +#include "BLI_fnmatch.h" #include "BLF_api.h" #include "BLF_translation.h" @@ -1017,6 +1019,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr) Scene *scene = CTX_data_scene(C); Object *ob; ModifierData *md, *vmd; + VirtualModifierData virtualModifierData; int i, lastCageIndex, cageIndex; /* verify we have valid data */ @@ -1039,7 +1042,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr) cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0); /* XXX virtual modifiers are not accesible for python */ - vmd = modifiers_getVirtualModifierList(ob); + vmd = modifiers_getVirtualModifierList(ob, &virtualModifierData); for (i = 0; vmd; i++, vmd = vmd->next) { if (md == vmd) @@ -1145,9 +1148,10 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) uiBlockSetEmboss(block, UI_EMBOSSN); uiItemR(row, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); uiBlockSetEmboss(block, UI_EMBOSS); - + /* name */ - uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco + 0.5f*UI_UNIT_X, yco, 5 * UI_UNIT_X, 0.9f*UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, ""); + uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, + xco + 0.5f * UI_UNIT_X, yco, 5 * UI_UNIT_X, 0.9f * UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, ""); if (con->flag & CONSTRAINT_DISABLE) uiLayoutSetRedAlert(row, TRUE); @@ -2468,7 +2472,7 @@ void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propnam static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout, struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon, struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname), - int UNUSED(index)) + int UNUSED(index), int UNUSED(flt_flag)) { char *namebuf; const char *name; @@ -2494,30 +2498,245 @@ static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UN } } +static void uilist_draw_filter_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout) +{ + PointerRNA listptr; + uiLayout *row, *subrow; + + RNA_pointer_create(NULL, &RNA_UIList, ui_list, &listptr); + + row = uiLayoutRow(layout, FALSE); + + subrow = uiLayoutRow(row, TRUE); + uiItemR(subrow, &listptr, "filter_name", 0, "", ICON_NONE); + uiItemR(subrow, &listptr, "use_filter_invert", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", + (ui_list->filter_flag & UILST_FLT_EXCLUDE) ? ICON_ZOOM_OUT : ICON_ZOOM_IN); + + subrow = uiLayoutRow(row, TRUE); + uiItemR(subrow, &listptr, "use_filter_sort_alpha", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + uiItemR(subrow, &listptr, "use_filter_sort_reverse", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", + (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) ? ICON_TRIA_UP : ICON_TRIA_DOWN); +} + +typedef struct { + char name[MAX_IDPROP_NAME]; + int org_idx; +} StringCmp; + +static int cmpstringp(const void *p1, const void *p2) +{ + /* Case-insensitive comparison. */ + return BLI_strcasecmp(((StringCmp *) p1)->name, ((StringCmp *) p2)->name); +} + +static void uilist_filter_items_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct PointerRNA *dataptr, + const char *propname) +{ + uiListDyn *dyn_data = ui_list->dyn_data; + PropertyRNA *prop = RNA_struct_find_property(dataptr, propname); + + const char *filter_raw = ui_list->filter_byname; + char *filter = (char *)filter_raw, filter_buff[32], *filter_dyn = NULL; + bool filter_exclude = (ui_list->filter_flag & UILST_FLT_EXCLUDE) != 0; + bool order_by_name = (ui_list->filter_sort_flag & UILST_FLT_SORT_ALPHA) != 0; + int len = RNA_property_collection_length(dataptr, prop); + + dyn_data->items_shown = dyn_data->items_len = len; + + if (len && (order_by_name || filter_raw[0])) { + StringCmp *names = NULL; + int order_idx = 0, i = 0; + + if (order_by_name) { + names = MEM_callocN(sizeof(StringCmp) * len, AT); + } + if (filter_raw[0]) { + size_t idx = 0, slen = strlen(filter_raw); + + dyn_data->items_filter_flags = MEM_callocN(sizeof(int) * len, AT); + dyn_data->items_shown = 0; + + /* Implicitly add heading/trailing wildcards if needed. */ + if (len + 3 <= 32) { + filter = filter_buff; + } + else { + filter = filter_dyn = MEM_mallocN((slen + 3) * sizeof(char), AT); + } + if (filter_raw[idx] != '*') { + filter[idx++] = '*'; + } + memcpy(filter + idx, filter_raw, slen); + idx += slen; + if (filter[idx - 1] != '*') { + filter[idx++] = '*'; + } + filter[idx] = '\0'; + } + + RNA_PROP_BEGIN (dataptr, itemptr, prop) + { + char *namebuf; + const char *name; + bool do_order = false; + + namebuf = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); + name = namebuf ? namebuf : ""; + + if (filter[0]) { + /* Case-insensitive! */ + if (fnmatch(filter, name, FNM_CASEFOLD) == 0) { + dyn_data->items_filter_flags[i] = UILST_FLT_ITEM; + if (!filter_exclude) { + dyn_data->items_shown++; + do_order = order_by_name; + } + //printf("%s: '%s' matches '%s'\n", __func__, name, filter); + } + else if (filter_exclude) { + dyn_data->items_shown++; + do_order = order_by_name; + } + } + else { + do_order = order_by_name; + } + + if (do_order) { + names[order_idx].org_idx = order_idx; + BLI_strncpy(names[order_idx++].name, name, MAX_IDPROP_NAME); + } + + /* free name */ + if (namebuf) { + MEM_freeN(namebuf); + } + i++; + } + RNA_PROP_END; + + if (order_by_name) { + int new_idx; + /* note: order_idx equals either to ui_list->items_len if no filtering done, + * or to ui_list->items_shown if filter is enabled, + * or to (ui_list->items_len - ui_list->items_shown) if filtered items are excluded. + * This way, we only sort items we actually intend to draw! + */ + qsort(names, order_idx, sizeof(StringCmp), cmpstringp); + + dyn_data->items_filter_neworder = MEM_mallocN(sizeof(int) * order_idx, AT); + for (new_idx = 0; new_idx < order_idx; new_idx++) { + dyn_data->items_filter_neworder[names[new_idx].org_idx] = new_idx; + } + } + + if (filter_dyn) { + MEM_freeN(filter_dyn); + } + if (names) { + MEM_freeN(names); + } + } +} + +typedef struct { + PointerRNA item; + int org_idx; + int flt_flag; +} _uilist_item; + +typedef struct { + int visual_items; /* Visual number of items (i.e. number of items we have room to display). */ + int start_idx; /* Index of first item to display. */ + int end_idx; /* Index of last item to display + 1. */ +} uiListLayoutdata; + +static void prepare_list(uiList *ui_list, int len, int activei, int rows, int maxrows, int columns, + uiListLayoutdata *layoutdata) +{ + uiListDyn *dyn_data = ui_list->dyn_data; + int activei_row, max_scroll; + + /* default rows */ + if (rows == 0) + rows = 5; + dyn_data->visual_height_min = rows; + if (maxrows == 0) + maxrows = 5; + if (columns == 0) + columns = 9; + + if (ui_list->list_grip >= rows) { + maxrows = rows = ui_list->list_grip; + } + else { + ui_list->list_grip = 0; /* Reset to auto-size mode. */ + /* Prevent auto-size mode to take effect while grab-resizing! */ + if (ui_list->flag & UILST_RESIZING) { + maxrows = rows; + } + } + + if (columns > 1) { + dyn_data->height = (int)ceil((double)len / (double)columns); + activei_row = (int)floor((double)activei / (double)columns); + } + else { + dyn_data->height = len; + activei_row = activei; + } + + /* Expand size if needed and possible. */ + if ((ui_list->list_grip == 0) && (rows != maxrows) && (dyn_data->height > rows)) { + rows = min_ii(dyn_data->height, maxrows); + } + + /* If list length changes or list is tagged to check this, and active is out of view, scroll to it .*/ + if (ui_list->list_last_len != len || ui_list->flag & UILST_SCROLL_TO_ACTIVE_ITEM) { + if (activei_row < ui_list->list_scroll) { + ui_list->list_scroll = activei_row; + } + else if (activei_row >= ui_list->list_scroll + rows) { + ui_list->list_scroll = activei_row - rows + 1; + } + ui_list->flag &= ~UILST_SCROLL_TO_ACTIVE_ITEM; + } + + max_scroll = max_ii(0, dyn_data->height - rows); + CLAMP(ui_list->list_scroll, 0, max_scroll); + ui_list->list_last_len = len; + dyn_data->visual_height = rows; + layoutdata->visual_items = rows * columns; + layoutdata->start_idx = ui_list->list_scroll * columns; + layoutdata->end_idx = min_ii(layoutdata->start_idx + rows * columns, len); +} + void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, - const char *active_propname, int rows, int maxrows, int layout_type) + const char *active_propname, int rows, int maxrows, int layout_type, int columns) { uiListType *ui_list_type; uiList *ui_list = NULL; + uiListDyn *dyn_data; ARegion *ar; uiListDrawItemFunc draw_item; + uiListDrawFilterFunc draw_filter; + uiListFilterItemsFunc filter_items; PropertyRNA *prop = NULL, *activeprop; PropertyType type, activetype; + _uilist_item *items_ptr = NULL; StructRNA *ptype; - uiLayout *box, *row, *col, *sub, *overlap; + uiLayout *glob = NULL, *box, *row, *col, *subrow, *sub, *overlap; uiBlock *block, *subblock; uiBut *but; + uiListLayoutdata layoutdata; char ui_list_id[UI_MAX_NAME_STR]; char numstr[32]; int rnaicon = ICON_NONE, icon = ICON_NONE; int i = 0, activei = 0; int len = 0; - int items; - int found; - int min, max; /* validate arguments */ /* Forbid default UI_UL_DEFAULT_CLASS_NAME list class without a custom list_id! */ @@ -2580,6 +2799,8 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co } draw_item = ui_list_type->draw_item ? ui_list_type->draw_item : uilist_draw_item_default; + draw_filter = ui_list_type->draw_filter ? ui_list_type->draw_filter : uilist_draw_filter_default; + filter_items = ui_list_type->filter_items ? ui_list_type->filter_items : uilist_filter_items_default; /* Find or add the uiList to the current Region. */ /* We tag the list id with the list type... */ @@ -2589,146 +2810,211 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co ui_list = BLI_findstring(&ar->ui_lists, ui_list_id, offsetof(uiList, list_id)); if (!ui_list) { - ui_list = MEM_callocN(sizeof(uiList), __func__); + ui_list = MEM_callocN(sizeof(uiList), AT); BLI_strncpy(ui_list->list_id, ui_list_id, sizeof(ui_list->list_id)); BLI_addtail(&ar->ui_lists, ui_list); } + if (!ui_list->dyn_data) { + ui_list->dyn_data = MEM_callocN(sizeof(uiListDyn), AT); + } + dyn_data = ui_list->dyn_data; + /* Because we can't actually pass type across save&load... */ ui_list->type = ui_list_type; ui_list->layout_type = layout_type; + /* Reset filtering data. */ + if (dyn_data->items_filter_flags) { + MEM_freeN(dyn_data->items_filter_flags); + dyn_data->items_filter_flags = NULL; + } + if (dyn_data->items_filter_neworder) { + MEM_freeN(dyn_data->items_filter_neworder); + dyn_data->items_filter_neworder = NULL; + } + dyn_data->items_len = dyn_data->items_shown = -1; + + /* Filter list items! (not for compact layout, though) */ + if (dataptr->data && prop) { + int filter_exclude = ui_list->filter_flag & UILST_FLT_EXCLUDE; + bool order_reverse = (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) != 0; + int items_shown, idx = 0; +#if 0 + int prev_ii = -1, prev_i; +#endif + + if (layout_type == UILST_LAYOUT_COMPACT) { + dyn_data->items_len = dyn_data->items_shown = RNA_property_collection_length(dataptr, prop); + } + else { + //printf("%s: filtering...\n", __func__); + filter_items(ui_list, C, dataptr, propname); + //printf("%s: filtering done.\n", __func__); + } + + items_shown = dyn_data->items_shown; + if (items_shown >= 0) { + items_ptr = MEM_mallocN(sizeof(_uilist_item) * items_shown, AT); + //printf("%s: items shown: %d.\n", __func__, items_shown); + RNA_PROP_BEGIN (dataptr, itemptr, prop) + { + if (!dyn_data->items_filter_flags || + ((dyn_data->items_filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude)) + { + int ii; + if (dyn_data->items_filter_neworder) { + ii = dyn_data->items_filter_neworder[idx++]; + ii = order_reverse ? items_shown - ii - 1 : ii; + } + else { + ii = order_reverse ? items_shown - ++idx : idx++; + } + //printf("%s: ii: %d\n", __func__, ii); + items_ptr[ii].item = itemptr; + items_ptr[ii].org_idx = i; + items_ptr[ii].flt_flag = dyn_data->items_filter_flags ? dyn_data->items_filter_flags[i] : 0; + + if (activei == i) { + activei = ii; + } +# if 0 /* For now, do not alter active element, even if it will be hidden... */ + else if (activei < i) { + /* We do not want an active but invisible item! + * Only exception is when all items are filtered out... + */ + if (prev_ii >= 0) { + activei = prev_ii; + RNA_property_int_set(active_dataptr, activeprop, prev_i); + } + else { + activei = ii; + RNA_property_int_set(active_dataptr, activeprop, i); + } + } + prev_i = i; + prev_ii = ii; +#endif + } + i++; + } + RNA_PROP_END; + } + if (dyn_data->items_shown >= 0) { + len = dyn_data->items_shown; + } + else { + len = dyn_data->items_len; + } + } + switch (layout_type) { case UILST_LAYOUT_DEFAULT: - /* default rows */ - if (rows == 0) - rows = 5; - if (maxrows == 0) - maxrows = 5; - if (ui_list->list_grip_size != 0) - rows = ui_list->list_grip_size; - /* layout */ box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop); - row = uiLayoutRow(box, FALSE); + glob = uiLayoutColumn(box, TRUE); + row = uiLayoutRow(glob, FALSE); col = uiLayoutColumn(row, TRUE); /* init numbers */ - RNA_property_int_range(active_dataptr, activeprop, &min, &max); - - if (prop) - len = RNA_property_collection_length(dataptr, prop); - items = CLAMPIS(len, rows, MAX2(rows, maxrows)); - - /* if list length changes and active is out of view, scroll to it */ - if ((ui_list->list_last_len != len) && - (activei < ui_list->list_scroll || activei >= ui_list->list_scroll + items)) - { - ui_list->list_scroll = activei; - } - - ui_list->list_scroll = min_ii(ui_list->list_scroll, len - items); - ui_list->list_scroll = max_ii(ui_list->list_scroll, 0); - ui_list->list_size = items; - ui_list->list_last_len = len; + prepare_list(ui_list, len, activei, rows, maxrows, 1, &layoutdata); if (dataptr->data && prop) { /* create list items */ - RNA_PROP_BEGIN (dataptr, itemptr, prop) - { - if (i >= ui_list->list_scroll && i < ui_list->list_scroll + items) { - subblock = uiLayoutGetBlock(col); - overlap = uiLayoutOverlap(col); + for (i = layoutdata.start_idx; i < layoutdata.end_idx; i++) { + PointerRNA *itemptr = &items_ptr[i].item; + int org_i = items_ptr[i].org_idx; + int flt_flag = items_ptr[i].flt_flag; + subblock = uiLayoutGetBlock(col); - uiBlockSetFlag(subblock, UI_BLOCK_LIST_ITEM); + overlap = uiLayoutOverlap(col); + + uiBlockSetFlag(subblock, UI_BLOCK_LIST_ITEM); - /* list item behind label & other buttons */ - sub = uiLayoutRow(overlap, FALSE); + /* list item behind label & other buttons */ + sub = uiLayoutRow(overlap, FALSE); - but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, - active_dataptr, activeprop, 0, 0, i, 0, 0, NULL); - uiButSetFlag(but, UI_BUT_NO_TOOLTIP); + but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, + active_dataptr, activeprop, 0, 0, org_i, 0, 0, NULL); + uiButSetFlag(but, UI_BUT_NO_TOOLTIP); - sub = uiLayoutRow(overlap, FALSE); + sub = uiLayoutRow(overlap, FALSE); - icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, false); - if (icon == ICON_DOT) - icon = ICON_NONE; - draw_item(ui_list, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i); + icon = UI_rnaptr_icon_get(C, itemptr, rnaicon, false); + if (icon == ICON_DOT) + icon = ICON_NONE; + draw_item(ui_list, C, sub, dataptr, itemptr, icon, active_dataptr, active_propname, + org_i, flt_flag); - /* If we are "drawing" active item, set all labels as active. */ - if (i == activei) { - ui_layout_list_set_labels_active(sub); - } - uiBlockClearFlag(subblock, UI_BLOCK_LIST_ITEM); + /* If we are "drawing" active item, set all labels as active. */ + if (i == activei) { + ui_layout_list_set_labels_active(sub); } - i++; + + uiBlockClearFlag(subblock, UI_BLOCK_LIST_ITEM); } - RNA_PROP_END; } /* add dummy buttons to fill space */ - while (i < ui_list->list_scroll + items) { - if (i >= ui_list->list_scroll) - uiItemL(col, "", ICON_NONE); - i++; + for (; i < layoutdata.start_idx + layoutdata.visual_items; i++) { + uiItemL(col, "", ICON_NONE); } /* add scrollbar */ - if (len > items) { + if (len > layoutdata.visual_items) { col = uiLayoutColumn(row, FALSE); - uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &ui_list->list_scroll, - 0, len - items, items, 0, ""); + uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height, + &ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height, + dyn_data->visual_height, 0, ""); } break; case UILST_LAYOUT_COMPACT: row = uiLayoutRow(layout, TRUE); - if (dataptr->data && prop) { - /* create list items */ - RNA_PROP_BEGIN (dataptr, itemptr, prop) - { - found = (activei == i); - - if (found) { - icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, false); - if (icon == ICON_DOT) - icon = ICON_NONE; - draw_item(ui_list, C, row, dataptr, &itemptr, icon, active_dataptr, active_propname, i); - } + if (dataptr->data && prop && dyn_data->items_shown > 0) { + PointerRNA *itemptr = &items_ptr[activei].item; + int org_i = items_ptr[activei].org_idx; - i++; - } - RNA_PROP_END; + icon = UI_rnaptr_icon_get(C, itemptr, rnaicon, false); + if (icon == ICON_DOT) + icon = ICON_NONE; + draw_item(ui_list, C, row, dataptr, itemptr, icon, active_dataptr, active_propname, org_i, 0); } - /* if list is empty, add in dummy button */ - if (i == 0) + else { uiItemL(row, "", ICON_NONE); + } /* next/prev button */ - BLI_snprintf(numstr, sizeof(numstr), "%d :", i); + BLI_snprintf(numstr, sizeof(numstr), "%d :", dyn_data->items_shown); but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, active_dataptr, activeprop, 0, 0, 0, 0, 0, ""); - if (i == 0) + if (dyn_data->items_shown == 0) uiButSetFlag(but, UI_BUT_DISABLED); break; case UILST_LAYOUT_GRID: box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop); - col = uiLayoutColumn(box, TRUE); - row = uiLayoutRow(col, FALSE); + glob = uiLayoutColumn(box, TRUE); + row = uiLayoutRow(glob, FALSE); + col = uiLayoutColumn(row, TRUE); + subrow = NULL; /* Quite gcc warning! */ + + prepare_list(ui_list, len, activei, rows, maxrows, columns, &layoutdata); if (dataptr->data && prop) { /* create list items */ - RNA_PROP_BEGIN (dataptr, itemptr, prop) - { + for (i = layoutdata.start_idx; i < layoutdata.end_idx; i++) { + PointerRNA *itemptr = &items_ptr[i].item; + int org_i = items_ptr[i].org_idx; + int flt_flag = items_ptr[i].flt_flag; + /* create button */ - if (!(i % 9)) - row = uiLayoutRow(col, FALSE); + if (!(i % columns)) + subrow = uiLayoutRow(col, FALSE); - subblock = uiLayoutGetBlock(row); - overlap = uiLayoutOverlap(row); + subblock = uiLayoutGetBlock(subrow); + overlap = uiLayoutOverlap(subrow); uiBlockSetFlag(subblock, UI_BLOCK_LIST_ITEM); @@ -2736,13 +3022,14 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co sub = uiLayoutRow(overlap, FALSE); but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, - active_dataptr, activeprop, 0, 0, i, 0, 0, NULL); + active_dataptr, activeprop, 0, 0, org_i, 0, 0, NULL); uiButSetFlag(but, UI_BUT_NO_TOOLTIP); sub = uiLayoutRow(overlap, FALSE); - icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, false); - draw_item(ui_list, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i); + icon = UI_rnaptr_icon_get(C, itemptr, rnaicon, false); + draw_item(ui_list, C, sub, dataptr, itemptr, icon, active_dataptr, active_propname, + org_i, flt_flag); /* If we are "drawing" active item, set all labels as active. */ if (i == activei) { @@ -2750,13 +3037,67 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co } uiBlockClearFlag(subblock, UI_BLOCK_LIST_ITEM); + } + } - i++; + /* add dummy buttons to fill space */ + for (; i < layoutdata.start_idx + layoutdata.visual_items; i++) { + if (!(i % columns)) { + subrow = uiLayoutRow(col, FALSE); } - RNA_PROP_END; + uiItemL(subrow, "", ICON_NONE); + } + + /* add scrollbar */ + if (len > layoutdata.visual_items) { + col = uiLayoutColumn(row, FALSE); + uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height, + &ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height, + dyn_data->visual_height, 0, ""); } break; } + + if (glob) { + row = uiLayoutRow(glob, TRUE); + subblock = uiLayoutGetBlock(row); + uiBlockSetEmboss(subblock, UI_EMBOSSN); + + if (ui_list->filter_flag & UILST_FLT_SHOW) { + but = uiDefIconButBitI(subblock, TOG, UILST_FLT_SHOW, 0, ICON_DISCLOSURE_TRI_DOWN, 0, 0, + UI_UNIT_X, UI_UNIT_Y * 0.6f, &(ui_list->filter_flag), 0, 0, 0, 0, + TIP_("Hide filtering options")); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ + + but = uiDefIconBut(subblock, BUT, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10.0f, UI_UNIT_Y * 0.6f, ui_list, + 0.0, 0.0, 0, -1, ""); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ + + uiBlockSetEmboss(subblock, UI_EMBOSS); + + col = uiLayoutColumn(glob, FALSE); + subblock = uiLayoutGetBlock(col); + uiDefBut(subblock, SEPR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y * 0.05f, NULL, 0.0, 0.0, 0, 0, ""); + + draw_filter(ui_list, C, col); + } + else { + but = uiDefIconButBitI(subblock, TOG, UILST_FLT_SHOW, 0, ICON_DISCLOSURE_TRI_RIGHT, 0, 0, + UI_UNIT_X, UI_UNIT_Y * 0.6f, &(ui_list->filter_flag), 0, 0, 0, 0, + TIP_("Show filtering options")); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ + + but = uiDefIconBut(subblock, BUT, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10.0f, UI_UNIT_Y * 0.6f, ui_list, + 0.0, 0.0, 0, -1, ""); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ + + uiBlockSetEmboss(subblock, UI_EMBOSS); + } + } + + if (items_ptr) { + MEM_freeN(items_ptr); + } } /************************* Operator Search Template **************************/ @@ -2792,7 +3133,7 @@ static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char if (WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, true, &name[len + 1], sizeof(name) - len - 1)) { - name[len] = '|'; + name[len] = UI_SEP_CHAR; } } @@ -3003,7 +3344,7 @@ static void keymap_item_modified(bContext *UNUSED(C), void *kmi_p, void *UNUSED( static void template_keymap_item_properties(uiLayout *layout, const char *title, PointerRNA *ptr) { - uiLayout *flow; + uiLayout *flow, *box, *row; uiItemS(layout); @@ -3015,6 +3356,8 @@ static void template_keymap_item_properties(uiLayout *layout, const char *title, RNA_STRUCT_BEGIN (ptr, prop) { int flag = RNA_property_flag(prop); + bool is_set = RNA_property_is_set(ptr, prop); + uiBut *but; if (flag & PROP_HIDDEN) continue; @@ -3030,8 +3373,22 @@ static void template_keymap_item_properties(uiLayout *layout, const char *title, } } - /* add property */ - uiItemFullR(flow, ptr, prop, -1, 0, 0, NULL, ICON_NONE); + box = uiLayoutBox(flow); + uiLayoutSetActive(box, is_set); + row = uiLayoutRow(box, false); + + /* property value */ + uiItemFullR(row, ptr, prop, -1, 0, 0, NULL, ICON_NONE); + + if (is_set) { + /* unset operator */ + uiBlock *block = uiLayoutGetBlock(row); + uiBlockSetEmboss(block, UI_EMBOSSN); + but = uiDefIconButO(block, BUT, "UI_OT_unset_property_button", WM_OP_EXEC_DEFAULT, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL); + but->rnapoin = *ptr; + but->rnaprop = prop; + uiBlockSetEmboss(block, UI_EMBOSS); + } } RNA_STRUCT_END; } @@ -3047,8 +3404,12 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr) /* attach callbacks to compensate for missing properties update, * we don't know which keymap (item) is being modified there */ - for (; but; but = but->next) - uiButSetFunc(but, keymap_item_modified, ptr->data, NULL); + for (; but; but = but->next) { + /* operator buttons may store props for use (file selector, [#36492]) */ + if (but->rnaprop) { + uiButSetFunc(but, keymap_item_modified, ptr->data, NULL); + } + } } } @@ -3100,6 +3461,8 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), P uiItemR(col, &view_transform_ptr, "exposure", 0, NULL, ICON_NONE); uiItemR(col, &view_transform_ptr, "gamma", 0, NULL, ICON_NONE); + uiItemR(col, &view_transform_ptr, "look", 0, IFACE_("Look"), ICON_NONE); + col = uiLayoutColumn(layout, FALSE); uiItemR(col, &view_transform_ptr, "use_curve_mapping", 0, NULL, ICON_NONE); if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 594d3e40dcd..4be8812d68c 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1215,7 +1215,7 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b /* cut string in 2 parts - only for menu entries */ if ((but->block->flag & UI_BLOCK_LOOP)) { if (ELEM3(but->type, NUM, TEX, NUMSLI) == 0) { - cpoin = strchr(but->drawstr, '|'); + cpoin = strchr(but->drawstr, UI_SEP_CHAR); if (cpoin) *cpoin = 0; } } @@ -1261,7 +1261,7 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b fstyle->align = UI_STYLE_TEXT_RIGHT; rect->xmax -= ui_but_draw_menu_icon(but) ? UI_DPI_ICON_SIZE : 0.25f * U.widget_unit; uiStyleFontDraw(fstyle, rect, cpoin + 1); - *cpoin = '|'; + *cpoin = UI_SEP_CHAR; } } @@ -2850,6 +2850,16 @@ static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int UN rect->xmin += BLI_rcti_size_y(rect) * 0.7 + delta; } +/* labels use Editor theme colors for text */ +static void widget_state_label(uiWidgetType *wt, int state) +{ + /* call this for option button */ + widget_state(wt, state); + if (state & UI_SELECT) + UI_GetThemeColor3ubv(TH_TEXT_HI, (unsigned char *)wt->wcol.text); + else + UI_GetThemeColor3ubv(TH_TEXT, (unsigned char *)wt->wcol.text); +} static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign) { @@ -2970,9 +2980,12 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) case UI_WTYPE_LISTLABEL: wt.wcol_theme = &btheme->tui.wcol_list_item; - /* fall-through */ /* we use usual label code too. */ + wt.draw = NULL; + /* Can't use usual label code. */ + break; case UI_WTYPE_LABEL: wt.draw = NULL; + wt.state = widget_state_label; break; case UI_WTYPE_TOGGLE: @@ -3482,7 +3495,7 @@ void ui_draw_search_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect) /* helper call to draw a menu item without button */ /* state: UI_ACTIVE or 0 */ -void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state) +void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state, bool use_sep) { uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM); rcti _rect = *rect; @@ -3499,21 +3512,25 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic if (iconid) rect->xmin += UI_DPI_ICON_SIZE; /* cut string in 2 parts? */ - cpoin = strchr(name, '|'); - if (cpoin) { - *cpoin = 0; - rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1) + 10; + if (use_sep) { + cpoin = strchr(name, UI_SEP_CHAR); + if (cpoin) { + *cpoin = 0; + rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1) + 10; + } } glColor4ubv((unsigned char *)wt->wcol.text); uiStyleFontDraw(fstyle, rect, name); /* part text right aligned */ - if (cpoin) { - fstyle->align = UI_STYLE_TEXT_RIGHT; - rect->xmax = _rect.xmax - 5; - uiStyleFontDraw(fstyle, rect, cpoin + 1); - *cpoin = '|'; + if (use_sep) { + if (cpoin) { + fstyle->align = UI_STYLE_TEXT_RIGHT; + rect->xmax = _rect.xmax - 5; + uiStyleFontDraw(fstyle, rect, cpoin + 1); + *cpoin = UI_SEP_CHAR; + } } /* restore rect, was messed with */ diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 1ef4d43c9f3..ace35f0276e 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -484,6 +484,14 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo case TH_STITCH_PREVIEW_ACTIVE: cp = ts->preview_stitch_active; break; + + case TH_UV_OTHERS: + cp = ts->uv_others; + break; + case TH_UV_SHADOW: + cp = ts->uv_shadow; + break; + case TH_MARKER_OUTLINE: cp = ts->marker_outline; break; case TH_MARKER: @@ -918,6 +926,9 @@ void ui_theme_init_default(void) rgba_char_args_set_fl(btheme->tima.preview_stitch_unstitchable, 1.0, 0.0, 0.0, 1.0); rgba_char_args_set_fl(btheme->tima.preview_stitch_active, 0.886, 0.824, 0.765, 0.140); + rgba_char_args_test_set(btheme->tima.uv_others, 96, 96, 96, 255); + rgba_char_args_test_set(btheme->tima.uv_shadow, 112, 112, 112, 255); + /* space text */ btheme->text = btheme->tv3d; rgba_char_args_set(btheme->text.back, 153, 153, 153, 255); @@ -2205,7 +2216,15 @@ void init_userdef_do_versions(void) } /* NOTE!! from now on use U.versionfile and U.subversionfile */ - + + if (U.versionfile < 269 || (U.versionfile == 268 && U.subversionfile < 3)) { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + rgba_char_args_test_set(btheme->tima.uv_others, 96, 96, 96, 255); + rgba_char_args_test_set(btheme->tima.uv_shadow, 112, 112, 112, 255); + } + } + if (U.pixelsize == 0.0f) U.pixelsize = 1.0f; diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index f656d22fc64..037fa7c6a94 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -2029,6 +2029,17 @@ void UI_view2d_to_region_no_clip(View2D *v2d, float x, float y, int *regionx, in } } +void UI_view2d_to_region_float(View2D *v2d, float x, float y, float *regionx, float *regiony) +{ + /* express given coordinates as proportional values */ + x = -v2d->cur.xmin / BLI_rctf_size_x(&v2d->cur); + y = -v2d->cur.ymin / BLI_rctf_size_y(&v2d->cur); + + /* convert proportional distances to screen coordinates */ + *regionx = v2d->mask.xmin + x * BLI_rcti_size_x(&v2d->mask); + *regiony = v2d->mask.ymin + y * BLI_rcti_size_y(&v2d->mask); +} + /* *********************************************************************** */ /* Utilities */ diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 929b7ae2a5d..00113666872 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -128,7 +128,7 @@ static int view_pan_init(bContext *C, wmOperator *op) } /* apply transform to view (i.e. adjust 'cur' rect) */ -static void view_pan_apply(wmOperator *op) +static void view_pan_apply(bContext *C, wmOperator *op) { v2dViewPanData *vpd = op->customdata; View2D *v2d = vpd->v2d; @@ -153,6 +153,7 @@ static void view_pan_apply(wmOperator *op) /* request updates to be done... */ ED_region_tag_redraw(vpd->ar); + WM_event_add_mousemove(C); UI_view2d_sync(vpd->sc, vpd->sa, v2d, V2D_LOCK_COPY); @@ -181,7 +182,7 @@ static int view_pan_exec(bContext *C, wmOperator *op) if (!view_pan_init(C, op)) return OPERATOR_CANCELLED; - view_pan_apply(op); + view_pan_apply(C, op); view_pan_exit(op); return OPERATOR_FINISHED; } @@ -209,7 +210,7 @@ static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event) RNA_int_set(op->ptr, "deltax", event->prevx - event->x); RNA_int_set(op->ptr, "deltay", event->prevy - event->y); - view_pan_apply(op); + view_pan_apply(C, op); view_pan_exit(op); return OPERATOR_FINISHED; } @@ -218,11 +219,11 @@ static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event) RNA_int_set(op->ptr, "deltay", 0); if (v2d->keepofs & V2D_LOCKOFS_X) - WM_cursor_modal(window, BC_NS_SCROLLCURSOR); + WM_cursor_modal_set(window, BC_NS_SCROLLCURSOR); else if (v2d->keepofs & V2D_LOCKOFS_Y) - WM_cursor_modal(window, BC_EW_SCROLLCURSOR); + WM_cursor_modal_set(window, BC_EW_SCROLLCURSOR); else - WM_cursor_modal(window, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(window, BC_NSEW_SCROLLCURSOR); /* add temp handler */ WM_event_add_modal_handler(C, op); @@ -246,7 +247,7 @@ static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event) vpd->lastx = event->x; vpd->lasty = event->y; - view_pan_apply(op); + view_pan_apply(C, op); break; } /* XXX - Mode switching isn't implemented. See comments in 36818. @@ -259,7 +260,7 @@ static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event) RNA_int_set(op->ptr, "deltay", (vpd->starty - vpd->lasty)); view_pan_exit(op); - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); WM_operator_name_call(C, "VIEW2D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL); return OPERATOR_FINISHED; } @@ -272,7 +273,7 @@ static int view_pan_modal(bContext *C, wmOperator *op, const wmEvent *event) RNA_int_set(op->ptr, "deltay", (vpd->starty - vpd->lasty)); view_pan_exit(op); - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); return OPERATOR_FINISHED; } @@ -333,7 +334,7 @@ static int view_scrollright_exec(bContext *C, wmOperator *op) RNA_int_set(op->ptr, "deltay", 0); /* apply movement, then we're done */ - view_pan_apply(op); + view_pan_apply(C, op); view_pan_exit(op); return OPERATOR_FINISHED; @@ -377,7 +378,7 @@ static int view_scrollleft_exec(bContext *C, wmOperator *op) RNA_int_set(op->ptr, "deltay", 0); /* apply movement, then we're done */ - view_pan_apply(op); + view_pan_apply(C, op); view_pan_exit(op); return OPERATOR_FINISHED; @@ -425,7 +426,7 @@ static int view_scrolldown_exec(bContext *C, wmOperator *op) } /* apply movement, then we're done */ - view_pan_apply(op); + view_pan_apply(C, op); view_pan_exit(op); return OPERATOR_FINISHED; @@ -475,7 +476,7 @@ static int view_scrollup_exec(bContext *C, wmOperator *op) } /* apply movement, then we're done */ - view_pan_apply(op); + view_pan_apply(C, op); view_pan_exit(op); return OPERATOR_FINISHED; @@ -986,11 +987,11 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *even } if (v2d->keepofs & V2D_LOCKOFS_X) - WM_cursor_modal(window, BC_NS_SCROLLCURSOR); + WM_cursor_modal_set(window, BC_NS_SCROLLCURSOR); else if (v2d->keepofs & V2D_LOCKOFS_Y) - WM_cursor_modal(window, BC_EW_SCROLLCURSOR); + WM_cursor_modal_set(window, BC_EW_SCROLLCURSOR); else - WM_cursor_modal(window, BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(window, BC_NSEW_SCROLLCURSOR); /* add temp handler */ WM_event_add_modal_handler(C, op); @@ -1092,7 +1093,7 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event /* free customdata */ view_zoomdrag_exit(C, op); - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); return OPERATOR_FINISHED; } @@ -1143,6 +1144,7 @@ static int view_borderzoom_exec(bContext *C, wmOperator *op) rctf rect; rctf cur_new = v2d->cur; int gesture_mode; + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); /* convert coordinates of rect to 'tot' rect coordinates */ UI_view2d_region_to_view(v2d, RNA_int_get(op->ptr, "xmin"), RNA_int_get(op->ptr, "ymin"), &rect.xmin, &rect.ymin); @@ -1194,7 +1196,7 @@ static int view_borderzoom_exec(bContext *C, wmOperator *op) } } - UI_view2d_smooth_view(C, ar, &cur_new); + UI_view2d_smooth_view(C, ar, &cur_new, smooth_viewtx); return OPERATOR_FINISHED; } @@ -1268,7 +1270,7 @@ static float smooth_view_rect_to_fac(const rctf *rect_a, const rctf *rect_b) /* will start timer if appropriate */ /* the arguments are the desired situation */ void UI_view2d_smooth_view(bContext *C, ARegion *ar, - const rctf *cur) + const rctf *cur, const int smooth_viewtx) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); @@ -1288,7 +1290,7 @@ void UI_view2d_smooth_view(bContext *C, ARegion *ar, fac = smooth_view_rect_to_fac(&v2d->cur, cur); } - if (U.smooth_viewtx && fac > FLT_EPSILON) { + if (smooth_viewtx && fac > FLT_EPSILON) { int changed = FALSE; if (BLI_rctf_compare(&sms.new_cur, &v2d->cur, FLT_EPSILON) == FALSE) @@ -1299,7 +1301,7 @@ void UI_view2d_smooth_view(bContext *C, ARegion *ar, if (changed) { sms.orig_cur = v2d->cur; - sms.time_allowed = (double)U.smooth_viewtx / 1000.0; + sms.time_allowed = (double)smooth_viewtx / 1000.0; /* scale the time allowed the change in view */ sms.time_allowed *= (double)fac; @@ -1372,14 +1374,16 @@ static void VIEW2D_OT_smoothview(wmOperatorType *ot) { /* identifiers */ ot->name = "Smooth View 2D"; - ot->description = "Zoom in the view to the nearest item contained in the border"; + ot->description = ""; ot->idname = "VIEW2D_OT_smoothview"; /* api callbacks */ ot->invoke = view2d_smoothview_invoke; - ot->poll = view2d_poll; + /* flags */ + ot->flag = OPTYPE_INTERNAL; + /* rna */ WM_operator_properties_gesture_border(ot, FALSE); } diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index a1bb7a8ae88..f50e4400b91 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -96,7 +96,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) int use_object_instantiation; int sort_by_name; int export_transformation_type; - int second_life; + int open_sim; if (!RNA_struct_property_is_set(op->ptr, "filepath")) { BKE_report(op->reports, RPT_ERROR, "No filename given"); @@ -106,6 +106,24 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", filepath); BLI_ensure_extension(filepath, sizeof(filepath), ".dae"); + + /* Avoid File write exceptions in Collada */ + if (!BLI_exists(filepath)) { + BLI_make_existing_file(filepath); + if (!BLI_file_touch(filepath)) { + BKE_report(op->reports, RPT_ERROR, "Can't create export file"); + fprintf(stdout, "Collada export: Can not create: %s\n", filepath); + return OPERATOR_CANCELLED; + } + } + else if (!BLI_file_is_writable(filepath)) { + BKE_report(op->reports, RPT_ERROR, "Can't overwrite export file"); + fprintf(stdout, "Collada export: Can not modify: %s\n", filepath); + return OPERATOR_CANCELLED; + } + + /* Now the exporter can create and write the export file */ + /* Options panel */ apply_modifiers = RNA_boolean_get(op->ptr, "apply_modifiers"); export_mesh_type = RNA_enum_get(op->ptr, "export_mesh_type_selection"); @@ -124,11 +142,13 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation"); sort_by_name = RNA_boolean_get(op->ptr, "sort_by_name"); export_transformation_type = RNA_enum_get(op->ptr, "export_transformation_type_selection"); - second_life = RNA_boolean_get(op->ptr, "second_life"); + open_sim = RNA_boolean_get(op->ptr, "open_sim"); /* get editmode results */ ED_object_editmode_load(CTX_data_edit_object(C)); + + if (collada_export(CTX_data_scene(C), filepath, apply_modifiers, @@ -148,7 +168,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) use_object_instantiation, sort_by_name, export_transformation_type, - second_life)) + open_sim)) { return OPERATOR_FINISHED; } @@ -216,7 +236,7 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr) row = uiLayoutRow(box, FALSE); uiItemR(row, imfptr, "deform_bones_only", 0, NULL, ICON_NONE); row = uiLayoutRow(box, FALSE); - uiItemR(row, imfptr, "second_life", 0, NULL, ICON_NONE); + uiItemR(row, imfptr, "open_sim", 0, NULL, ICON_NONE); /* Collada options: */ box = uiLayoutBox(layout); @@ -330,8 +350,8 @@ void WM_OT_collada_export(wmOperatorType *ot) RNA_def_enum(ot->srna, "export_transformation_type_selection", prop_bc_export_transformation_type, 0, "Transform", "Transformation type for translation, scale and rotation"); - RNA_def_boolean(ot->srna, "second_life", 0, "Export for Second Life", - "Compatibility mode for Second Life"); + RNA_def_boolean(ot->srna, "open_sim", 0, "Export for OpenSim", + "Compatibility mode for OpenSim and compatible online worlds"); } diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index 9c270144a0a..4cc9d3b59b1 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -737,3 +737,159 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot) RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", "Location of vertex in normalized space", -1.0f, 1.0f); } + +/******************** common primitive functions *********************/ + +static int create_primitive_from_points(bContext *C, wmOperator *op, const float (*points)[2], + int num_points, char handle_type) +{ + ScrArea *sa = CTX_wm_area(C); + Scene *scene = CTX_data_scene(C); + Mask *mask; + MaskLayer *mask_layer; + MaskSpline *new_spline; + float scale, location[2], frame_size[2]; + int i, width, height; + int size = RNA_float_get(op->ptr, "size"); + + ED_mask_get_size(sa, &width, &height); + scale = (float)size / max_ii(width, height); + + /* Get location in mask space. */ + frame_size[0] = width; + frame_size[1] = height; + RNA_float_get_array(op->ptr, "location", location); + location[0] /= width; + location[1] /= height; + BKE_mask_coord_from_frame(location, location, frame_size); + + /* Make it so new primitive is centered to mouse location. */ + location[0] -= 0.5f * scale; + location[1] -= 0.5f * scale; + + mask_layer = ED_mask_layer_ensure(C); + mask = CTX_data_edit_mask(C); + + ED_mask_select_toggle_all(mask, SEL_DESELECT); + + new_spline = BKE_mask_spline_add(mask_layer); + new_spline->flag = MASK_SPLINE_CYCLIC | SELECT; + new_spline->tot_point = num_points; + new_spline->points = MEM_recallocN(new_spline->points, + sizeof(MaskSplinePoint) * new_spline->tot_point); + + mask_layer->act_spline = new_spline; + mask_layer->act_point = NULL; + + for (i = 0; i < num_points; i++) { + MaskSplinePoint *new_point = &new_spline->points[i]; + + copy_v2_v2(new_point->bezt.vec[1], points[i]); + mul_v2_fl(new_point->bezt.vec[1], scale); + add_v2_v2(new_point->bezt.vec[1], location); + + new_point->bezt.h1 = handle_type; + new_point->bezt.h2 = handle_type; + BKE_mask_point_select_set(new_point, true); + } + + WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + + /* TODO: only update this spline */ + BKE_mask_update_display(mask, CFRA); + + return OPERATOR_FINISHED; +} + +static int primitive_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + ScrArea *sa = CTX_wm_area(C); + float cursor[2]; + int width, height; + + ED_mask_get_size(sa, &width, &height); + ED_mask_cursor_location_get(sa, cursor); + + cursor[0] *= width; + cursor[1] *= height; + + RNA_float_set_array(op->ptr, "location", cursor); + + return op->type->exec(C, op); +} + +static void define_prinitive_add_properties(wmOperatorType *ot) +{ + RNA_def_float(ot->srna, "size", 100, -FLT_MAX, FLT_MAX, + "Size", "Size of new circle", -FLT_MAX, FLT_MAX); + RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, + "Location", "Location of new circle", -FLT_MAX, FLT_MAX); +} + +/******************** primitive add circle *********************/ + +static int primitive_circle_add_exec(bContext *C, wmOperator *op) +{ + const float points[4][2] = {{0.0f, 0.5f}, + {0.5f, 1.0f}, + {1.0f, 0.5f}, + {0.5f, 0.0f}}; + int num_points = sizeof(points) / (2 * sizeof(float)); + + create_primitive_from_points(C, op, points, num_points, HD_AUTO); + + return OPERATOR_FINISHED; +} + +void MASK_OT_primitive_circle_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Circle"; + ot->description = "Add new circle-shaped spline"; + ot->idname = "MASK_OT_primitive_circle_add"; + + /* api callbacks */ + ot->exec = primitive_circle_add_exec; + ot->invoke = primitive_add_invoke; + ot->poll = ED_operator_mask; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + define_prinitive_add_properties(ot); +} + +/******************** primitive add suqare *********************/ + +static int primitive_square_add_exec(bContext *C, wmOperator *op) +{ + const float points[4][2] = {{0.0f, 0.0f}, + {0.0f, 1.0f}, + {1.0f, 1.0f}, + {1.0f, 0.0f}}; + int num_points = sizeof(points) / (2 * sizeof(float)); + + create_primitive_from_points(C, op, points, num_points, HD_VECT); + + return OPERATOR_FINISHED; +} + +void MASK_OT_primitive_square_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Square"; + ot->description = "Add new square-shaped spline"; + ot->idname = "MASK_OT_primitive_square_add"; + + /* api callbacks */ + ot->exec = primitive_square_add_exec; + ot->invoke = primitive_add_invoke; + ot->poll = ED_operator_mask; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + define_prinitive_add_properties(ot); +} diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c index 9ae5b436fb3..62eb9cc240a 100644 --- a/source/blender/editors/mask/mask_edit.c +++ b/source/blender/editors/mask/mask_edit.c @@ -363,6 +363,40 @@ void ED_mask_pixelspace_factor(ScrArea *sa, ARegion *ar, float *scalex, float *s } } +void ED_mask_cursor_location_get(ScrArea *sa, float cursor[2]) +{ + if (sa) { + switch (sa->spacetype) { + case SPACE_CLIP: + { + SpaceClip *space_clip = sa->spacedata.first; + copy_v2_v2(cursor, space_clip->cursor); + break; + } + case SPACE_SEQ: + { + zero_v2(cursor); + break; + } + case SPACE_IMAGE: + { + SpaceImage *space_image = sa->spacedata.first; + copy_v2_v2(cursor, space_image->cursor); + break; + } + default: + /* possible other spaces from which mask editing is available */ + BLI_assert(0); + zero_v2(cursor); + break; + } + } + else { + BLI_assert(0); + zero_v2(cursor); + } +} + /********************** registration *********************/ void ED_operatortypes_mask(void) @@ -376,6 +410,8 @@ void ED_operatortypes_mask(void) /* add */ WM_operatortype_append(MASK_OT_add_vertex); WM_operatortype_append(MASK_OT_add_feather_vertex); + WM_operatortype_append(MASK_OT_primitive_circle_add); + WM_operatortype_append(MASK_OT_primitive_square_add); /* geometry */ WM_operatortype_append(MASK_OT_switch_direction); @@ -417,6 +453,9 @@ void ED_operatortypes_mask(void) /* layers */ WM_operatortype_append(MASK_OT_layer_move); + + /* duplicate */ + WM_operatortype_append(MASK_OT_duplicate); } void ED_keymap_mask(wmKeyConfig *keyconf) @@ -429,6 +468,9 @@ void ED_keymap_mask(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MASK_OT_new", NKEY, KM_PRESS, KM_ALT, 0); + /* add menu */ + WM_keymap_add_menu(keymap, "MASK_MT_add", AKEY, KM_PRESS, KM_SHIFT, 0); + /* mask mode supports PET now */ ED_keymap_proportional_cycle(keyconf, keymap); ED_keymap_proportional_maskmode(keyconf, keymap); @@ -500,6 +542,9 @@ void ED_keymap_mask(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MASK_OT_shape_key_insert", IKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "MASK_OT_shape_key_clear", IKEY, KM_PRESS, KM_ALT, 0); + /* duplicate */ + WM_keymap_add_item(keymap, "MASK_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); + /* for image editor only */ WM_keymap_add_item(keymap, "UV_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0); @@ -514,7 +559,6 @@ void ED_keymap_mask(wmKeyConfig *keyconf) void ED_operatormacros_mask(void) { - /* XXX: just for sample */ wmOperatorType *ot; wmOperatorTypeMacro *otmacro; @@ -531,4 +575,11 @@ void ED_operatormacros_mask(void) WM_operatortype_macro_define(ot, "MASK_OT_add_feather_vertex"); otmacro = WM_operatortype_macro_define(ot, "MASK_OT_slide_point"); RNA_boolean_set(otmacro->ptr, "slide_feather", TRUE); + + ot = WM_operatortype_append_macro("MASK_OT_duplicate_move", "Add Duplicate", "Duplicate mask and move", + OPTYPE_UNDO | OPTYPE_REGISTER); + WM_operatortype_macro_define(ot, "MASK_OT_duplicate"); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_enum_set(otmacro->ptr, "proportional", 0); + RNA_boolean_set(otmacro->ptr, "mirror", FALSE); } diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h index bd148c48980..51705aa5837 100644 --- a/source/blender/editors/mask/mask_intern.h +++ b/source/blender/editors/mask/mask_intern.h @@ -42,9 +42,12 @@ struct wmOperatorType; /* mask_add.c */ void MASK_OT_add_vertex(struct wmOperatorType *ot); void MASK_OT_add_feather_vertex(struct wmOperatorType *ot); +void MASK_OT_primitive_circle_add(struct wmOperatorType *ot); +void MASK_OT_primitive_square_add(struct wmOperatorType *ot); /* mask_ops.c */ struct Mask *ED_mask_new(struct bContext *C, const char *name); +struct MaskLayer *ED_mask_layer_ensure(struct bContext *C); void MASK_OT_new(struct wmOperatorType *ot); void MASK_OT_layer_new(struct wmOperatorType *ot); @@ -75,6 +78,8 @@ struct MaskSplinePoint *ED_mask_point_find_nearest( void MASK_OT_layer_move(struct wmOperatorType *ot); +void MASK_OT_duplicate(struct wmOperatorType *ot); + /* mask_relationships.c */ void MASK_OT_parent_set(struct wmOperatorType *ot); void MASK_OT_parent_clear(struct wmOperatorType *ot); diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index c9d3bd19941..5ca0d133b0e 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -292,6 +292,26 @@ Mask *ED_mask_new(bContext *C, const char *name) return mask; } +/* Get ative layer. Will create mask/layer to be sure there's an active layer. */ +MaskLayer *ED_mask_layer_ensure(bContext *C) +{ + Mask *mask = CTX_data_edit_mask(C); + MaskLayer *mask_layer; + + if (mask == NULL) { + /* If there's no active mask, create one. */ + mask = ED_mask_new(C, NULL); + } + + mask_layer = BKE_mask_layer_active(mask); + if (mask_layer == NULL) { + /* If there's no active mask layer, create one. */ + mask_layer = BKE_mask_layer_new(mask, ""); + } + + return mask_layer; +} + static int mask_new_exec(bContext *C, wmOperator *op) { char name[MAX_ID_NAME - 2]; @@ -1467,3 +1487,110 @@ void MASK_OT_layer_move(wmOperatorType *ot) /* properties */ RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move the active layer"); } + +/******************** duplicate *********************/ + +static int mask_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + Mask *mask = CTX_data_edit_mask(C); + MaskLayer *mask_layer = BKE_mask_layer_active(mask); + MaskSpline *spline; + + if (mask_layer == NULL) { + return OPERATOR_CANCELLED; + } + + for (spline = mask_layer->splines.last; + spline; + spline = spline->prev) + { + MaskSplinePoint *point = spline->points; + int i = 0; + while (i < spline->tot_point) { + int start = i, end = -1; + /* Find next selected segment. */ + while (MASKPOINT_ISSEL_ANY(point)) { + BKE_mask_point_select_set(point, false); + end = i; + if (i >= spline->tot_point - 1) { + break; + } + i++; + point++; + } + if (end >= start) { + MaskSpline *new_spline = BKE_mask_spline_add(mask_layer); + MaskSplinePoint *new_point; + int b; + + /* BKE_mask_spline_add might allocate the points, need to free them in this case. */ + if (new_spline->points) { + MEM_freeN(new_spline->points); + } + + /* Copy options from old spline. */ + new_spline->flag = spline->flag; + new_spline->offset_mode = spline->offset_mode; + new_spline->weight_interp = spline->weight_interp; + new_spline->parent = spline->parent; + + /* Allocate new points and copy them from old spline. */ + new_spline->tot_point = end - start + 1; + new_spline->points = MEM_mallocN(sizeof(MaskSplinePoint) * new_spline->tot_point, + "duplicated mask points"); + + memcpy(new_spline->points, spline->points + start, + new_spline->tot_point * sizeof(MaskSplinePoint)); + + /* Select points and duplicate their UWs (if needed). */ + for (b = 0, new_point = new_spline->points; + b < new_spline->tot_point; + b++, new_point++) + { + if (new_point->uw) { + new_point->uw = MEM_dupallocN(new_point->uw); + } + BKE_mask_point_select_set(new_point, true); + } + + /* Clear cyclic flag if we didn't copy the whole spline. */ + if (new_spline->flag & MASK_SPLINE_CYCLIC) { + if (start != 0 || end != spline->tot_point - 1) { + new_spline->flag &= ~MASK_SPLINE_CYCLIC; + } + } + + /* Flush selection to splines. */ + new_spline->flag |= SELECT; + spline->flag &= ~SELECT; + + mask_layer->act_spline = new_spline; + } + i++; + point++; + } + } + + /* TODO: only update edited splines */ + BKE_mask_update_display(mask, CFRA); + + WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + + return OPERATOR_FINISHED; +} + +void MASK_OT_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate Mask"; + ot->description = "Duplicate selected control points and segments between them"; + ot->idname = "MASK_OT_duplicate"; + + /* api callbacks */ + ot->exec = mask_duplicate_exec; + ot->poll = ED_maskedit_mask_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c index 2a1bdee32f7..9cc1702addb 100644 --- a/source/blender/editors/mask/mask_relationships.c +++ b/source/blender/editors/mask/mask_relationships.c @@ -102,32 +102,54 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op)) MaskLayer *masklay; /* parent info */ - SpaceClip *sc; - MovieClip *clip; + SpaceClip *sc = CTX_wm_space_clip(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTracking *tracking; MovieTrackingTrack *track; - MovieTrackingMarker *marker; + MovieTrackingPlaneTrack *plane_track; MovieTrackingObject *tracking_object; /* done */ - int framenr; + int framenr, parent_type; + float parmask_pos[2], orig_corners[4][2]; + char *sub_parent_name; - float marker_pos_ofs[2]; - float parmask_pos[2]; - - if ((NULL == (sc = CTX_wm_space_clip(C))) || - (NULL == (clip = sc->clip)) || - (NULL == (track = clip->tracking.act_track)) || - (NULL == (tracking_object = BKE_tracking_object_get_active(&clip->tracking)))) - { + if (ELEM(NULL, sc, clip)) { return OPERATOR_CANCELLED; } framenr = ED_space_clip_get_clip_frame_number(sc); - marker = BKE_tracking_marker_get(track, framenr); - add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset); + tracking = &clip->tracking; + tracking_object = BKE_tracking_object_get_active(&clip->tracking); + + if (tracking_object == NULL) { + return OPERATOR_CANCELLED; + } + + if ((track = BKE_tracking_track_get_active(tracking)) != NULL) { + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); + float marker_pos_ofs[2]; + + add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset); - BKE_mask_coord_from_movieclip(clip, &sc->user, parmask_pos, marker_pos_ofs); + BKE_mask_coord_from_movieclip(clip, &sc->user, parmask_pos, marker_pos_ofs); + + sub_parent_name = track->name; + parent_type = MASK_PARENT_POINT_TRACK; + memset(orig_corners, 0, sizeof(orig_corners)); + } + else if ((plane_track = BKE_tracking_plane_track_get_active(tracking)) != NULL) { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); + + zero_v2(parmask_pos); + sub_parent_name = plane_track->name; + parent_type = MASK_PARENT_PLANE_TRACK; + memcpy(orig_corners, plane_marker->corners, sizeof(orig_corners)); + } + else { + return OPERATOR_CANCELLED; + } for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { MaskSpline *spline; @@ -144,10 +166,12 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op)) if (MASKPOINT_ISSEL_ANY(point)) { point->parent.id_type = ID_MC; point->parent.id = &clip->id; + point->parent.type = parent_type; BLI_strncpy(point->parent.parent, tracking_object->name, sizeof(point->parent.parent)); - BLI_strncpy(point->parent.sub_parent, track->name, sizeof(point->parent.sub_parent)); + BLI_strncpy(point->parent.sub_parent, sub_parent_name, sizeof(point->parent.sub_parent)); copy_v2_v2(point->parent.parent_orig, parmask_pos); + memcpy(point->parent.parent_corners_orig, orig_corners, sizeof(point->parent.parent_corners_orig)); } } } diff --git a/source/blender/editors/mask/mask_shapekey.c b/source/blender/editors/mask/mask_shapekey.c index 93bdca93096..d5fbdca5b0a 100644 --- a/source/blender/editors/mask/mask_shapekey.c +++ b/source/blender/editors/mask/mask_shapekey.c @@ -38,6 +38,7 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_mask.h" +#include "BKE_report.h" #include "DNA_object_types.h" #include "DNA_mask_types.h" diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index f6da2a82150..2992290e9b6 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -43,7 +43,7 @@ set(SRC editface.c editmesh_add.c editmesh_bevel.c - editmesh_deform_laplacian.c + editmesh_deform_laplacian.c editmesh_bisect.c editmesh_extrude.c editmesh_inset.c editmesh_knife.c diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 902906fcf8a..7944c2f0cca 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -691,6 +691,7 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to int a, last; int totvert, totedge; int tot_unique = -1, tot_unique_prev = -1; + int tot_unique_edges = 0, tot_unique_edges_prev; MirrTopoHash_t *topo_hash = NULL; MirrTopoHash_t *topo_hash_prev = NULL; @@ -720,36 +721,45 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to totedge = me->edit_btmesh->bm->totedge; BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - topo_hash[BM_elem_index_get(eed->v1)]++; - topo_hash[BM_elem_index_get(eed->v2)]++; + const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); + topo_hash[i1]++; + topo_hash[i2]++; } } else { totedge = me->totedge; for (a = 0, medge = me->medge; a < me->totedge; a++, medge++) { - topo_hash[medge->v1]++; - topo_hash[medge->v2]++; + const unsigned int i1 = medge->v1, i2 = medge->v2; + topo_hash[i1]++; + topo_hash[i2]++; } } topo_hash_prev = MEM_dupallocN(topo_hash); tot_unique_prev = -1; + tot_unique_edges_prev = -1; while (1) { /* use the number of edges per vert to give verts unique topology IDs */ + tot_unique_edges = 0; + + /* This can make really big numbers, wrapping around here is fine */ if (em) { BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - topo_hash[BM_elem_index_get(eed->v1)] += topo_hash_prev[BM_elem_index_get(eed->v2)] * topo_pass; - topo_hash[BM_elem_index_get(eed->v2)] += topo_hash_prev[BM_elem_index_get(eed->v1)] * topo_pass; + const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); + topo_hash[i1] += topo_hash_prev[i2] * topo_pass; + topo_hash[i2] += topo_hash_prev[i1] * topo_pass; + tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); } } else { for (a = 0, medge = me->medge; a < me->totedge; a++, medge++) { - /* This can make really big numbers, wrapping around here is fine */ - topo_hash[medge->v1] += topo_hash_prev[medge->v2] * topo_pass; - topo_hash[medge->v2] += topo_hash_prev[medge->v1] * topo_pass; + const unsigned int i1 = medge->v1, i2 = medge->v2; + topo_hash[i1] += topo_hash_prev[i2] * topo_pass; + topo_hash[i2] += topo_hash_prev[i1] * topo_pass; + tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); } } memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); @@ -764,13 +774,14 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to } } - if (tot_unique <= tot_unique_prev) { + if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) { /* Finish searching for unique values when 1 loop dosnt give a * higher number of unique values compared to the previous loop */ break; } else { tot_unique_prev = tot_unique; + tot_unique_edges_prev = tot_unique_edges; } /* Copy the hash calculated this iter, so we can use them next time */ memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index f372053db55..47b9d5e2a9e 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -96,15 +96,6 @@ static void make_prim_finish(bContext *C, Object *obedit, bool was_editmode, int WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); } -static void make_prim_radius_prop(wmOperatorType *ot) -{ - PropertyRNA *prop; - - prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00); - RNA_def_property_subtype(prop, PROP_DISTANCE); -} - - static int add_primitive_plane_exec(bContext *C, wmOperator *op) { Object *obedit; @@ -114,6 +105,7 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op) bool was_editmode; unsigned int layer; + WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Plane"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); @@ -139,14 +131,13 @@ void MESH_OT_primitive_plane_add(wmOperatorType *ot) ot->idname = "MESH_OT_primitive_plane_add"; /* api callbacks */ - ot->invoke = WM_operator_view3d_distance_invoke; ot->exec = add_primitive_plane_exec; ot->poll = ED_operator_scene_editable; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - make_prim_radius_prop(ot); + ED_object_add_unit_props(ot); ED_object_add_generic_props(ot, true); } @@ -159,6 +150,7 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op) bool was_editmode; unsigned int layer; + WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Cube"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); @@ -185,14 +177,13 @@ void MESH_OT_primitive_cube_add(wmOperatorType *ot) ot->idname = "MESH_OT_primitive_cube_add"; /* api callbacks */ - ot->invoke = WM_operator_view3d_distance_invoke; ot->exec = add_primitive_cube_exec; ot->poll = ED_operator_scene_editable; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - make_prim_radius_prop(ot); + ED_object_add_unit_props(ot); ED_object_add_generic_props(ot, true); } @@ -215,6 +206,7 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) cap_end = RNA_enum_get(op->ptr, "fill_type"); cap_tri = (cap_end == 2); + WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Circle"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); @@ -241,7 +233,6 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot) ot->idname = "MESH_OT_primitive_circle_add"; /* api callbacks */ - ot->invoke = WM_operator_view3d_distance_invoke; ot->exec = add_primitive_circle_exec; ot->poll = ED_operator_scene_editable; @@ -250,7 +241,7 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot) /* props */ RNA_def_int(ot->srna, "vertices", 32, 3, INT_MAX, "Vertices", "", 3, 500); - make_prim_radius_prop(ot); + ED_object_add_unit_props(ot); RNA_def_enum(ot->srna, "fill_type", fill_type_items, 0, "Fill Type", ""); ED_object_add_generic_props(ot, true); @@ -268,6 +259,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) const bool cap_end = (end_fill_type != 0); const bool cap_tri = (end_fill_type == 2); + WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Cylinder"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); @@ -299,7 +291,6 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot) ot->idname = "MESH_OT_primitive_cylinder_add"; /* api callbacks */ - ot->invoke = WM_operator_view3d_distance_invoke; ot->exec = add_primitive_cylinder_exec; ot->poll = ED_operator_scene_editable; @@ -308,7 +299,7 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot) /* props */ RNA_def_int(ot->srna, "vertices", 32, 3, INT_MAX, "Vertices", "", 3, 500); - make_prim_radius_prop(ot); + ED_object_add_unit_props(ot); prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00); RNA_def_property_subtype(prop, PROP_DISTANCE); RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Cap Fill Type", ""); @@ -328,6 +319,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) const bool cap_end = (end_fill_type != 0); const bool cap_tri = (end_fill_type == 2); + WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Cone"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); @@ -356,7 +348,6 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot) ot->idname = "MESH_OT_primitive_cone_add"; /* api callbacks */ - ot->invoke = WM_operator_view3d_distance_invoke; ot->exec = add_primitive_cone_exec; ot->poll = ED_operator_scene_editable; @@ -385,6 +376,7 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op) bool was_editmode; unsigned int layer; + WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Grid"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); @@ -412,7 +404,6 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot) ot->idname = "MESH_OT_primitive_grid_add"; /* api callbacks */ - ot->invoke = WM_operator_view3d_distance_invoke; ot->exec = add_primitive_grid_exec; ot->poll = ED_operator_scene_editable; @@ -422,7 +413,7 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot) /* props */ RNA_def_int(ot->srna, "x_subdivisions", 10, 3, INT_MAX, "X Subdivisions", "", 3, 1000); RNA_def_int(ot->srna, "y_subdivisions", 10, 3, INT_MAX, "Y Subdivisions", "", 3, 1000); - make_prim_radius_prop(ot); + ED_object_add_unit_props(ot); ED_object_add_generic_props(ot, true); } @@ -437,6 +428,7 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op) unsigned int layer; bool was_editmode; + WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, &is_view_aligned); if (!is_view_aligned) rot[0] += (float)M_PI / 2.0f; @@ -469,12 +461,11 @@ void MESH_OT_primitive_monkey_add(wmOperatorType *ot) ot->idname = "MESH_OT_primitive_monkey_add"; /* api callbacks */ - ot->invoke = WM_operator_view3d_distance_invoke; ot->exec = add_primitive_monkey_exec; ot->poll = ED_operator_scene_editable; /* flags */ - make_prim_radius_prop(ot); + ED_object_add_unit_props(ot); ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; ED_object_add_generic_props(ot, true); @@ -489,6 +480,7 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) bool was_editmode; unsigned int layer; + WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Sphere"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); @@ -517,7 +509,6 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot) ot->idname = "MESH_OT_primitive_uv_sphere_add"; /* api callbacks */ - ot->invoke = WM_operator_view3d_distance_invoke; ot->exec = add_primitive_uvsphere_exec; ot->poll = ED_operator_scene_editable; @@ -542,6 +533,7 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) bool was_editmode; unsigned int layer; + WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Icosphere"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); @@ -570,7 +562,6 @@ void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot) ot->idname = "MESH_OT_primitive_ico_sphere_add"; /* api callbacks */ - ot->invoke = WM_operator_view3d_distance_invoke; ot->exec = add_primitive_icosphere_exec; ot->poll = ED_operator_scene_editable; diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c new file mode 100644 index 00000000000..5431b1deb1c --- /dev/null +++ b/source/blender/editors/mesh/editmesh_bisect.c @@ -0,0 +1,331 @@ +/* + * ***** 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) 2013 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/editmesh_bisect.c + * \ingroup edmesh + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_object_types.h" + +#include "BLI_math.h" + +#include "BKE_global.h" +#include "BKE_context.h" +#include "BKE_editmesh.h" + +#include "RNA_define.h" +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_screen.h" +#include "ED_view3d.h" + + +#include "mesh_intern.h" /* own include */ + +static int mesh_bisect_exec(bContext *C, wmOperator *op); + +/* -------------------------------------------------------------------- */ +/* Model Helpers */ + +typedef struct { + /* modal only */ + BMBackup mesh_backup; + bool is_first; + short twtype; +} BisectData; + +static bool mesh_bisect_interactive_calc( + bContext *C, wmOperator *op, + BMEditMesh *em, + float plane_co[3], float plane_no[3]) +{ + wmGesture *gesture = op->customdata; + BisectData *opdata; + + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + int x_start = RNA_int_get(op->ptr, "xstart"); + int y_start = RNA_int_get(op->ptr, "ystart"); + int x_end = RNA_int_get(op->ptr, "xend"); + int y_end = RNA_int_get(op->ptr, "yend"); + + /* reference location (some point in front of the view) for finding a point on a plane */ + const float *co_ref = rv3d->ofs; + float co_a_ss[2] = {x_start, y_start}, co_b_ss[2] = {x_end, y_end}, co_delta_ss[2]; + float co_a[3], co_b[3]; + const float zfac = ED_view3d_calc_zfac(rv3d, co_ref, NULL); + + opdata = gesture->userdata; + + /* view vector */ + ED_view3d_win_to_vector(ar, co_a_ss, co_a); + + /* view delta */ + sub_v2_v2v2(co_delta_ss, co_a_ss, co_b_ss); + ED_view3d_win_to_delta(ar, co_delta_ss, co_b, zfac); + + /* cross both to get a normal */ + cross_v3_v3v3(plane_no, co_a, co_b); + normalize_v3(plane_no); /* not needed but nicer for user */ + + /* point on plane, can use either start or endpoint */ + ED_view3d_win_to_3d(ar, co_ref, co_a_ss, plane_co); + + if (opdata->is_first == false) + EDBM_redo_state_restore(opdata->mesh_backup, em, false); + + opdata->is_first = false; + + return true; +} + +static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int ret; + + /* if the properties are set or there is no rv3d, + * skip model and exec immediately */ + + if ((CTX_wm_region_view3d(C) == NULL) || + (RNA_struct_property_is_set(op->ptr, "plane_co") && + RNA_struct_property_is_set(op->ptr, "plane_no"))) + { + return mesh_bisect_exec(C, op); + } + + ret = WM_gesture_straightline_invoke(C, op, event); + if (ret & OPERATOR_RUNNING_MODAL) { + View3D *v3d = CTX_wm_view3d(C); + + wmGesture *gesture = op->customdata; + BisectData *opdata; + + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + opdata = MEM_mallocN(sizeof(BisectData), "inset_operator_data"); + opdata->mesh_backup = EDBM_redo_state_store(em); + opdata->is_first = true; + gesture->userdata = opdata; + + /* misc other vars */ + G.moving = G_TRANSFORM_EDIT; + opdata->twtype = v3d->twtype; + v3d->twtype = 0; + } + return ret; +} + +static void edbm_bisect_exit(bContext *C, BisectData *opdata) +{ + View3D *v3d = CTX_wm_view3d(C); + EDBM_redo_state_free(&opdata->mesh_backup, NULL, false); + v3d->twtype = opdata->twtype; + G.moving = 0; +} + +static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + wmGesture *gesture = op->customdata; + BisectData *opdata = gesture->userdata; + BisectData opdata_back = *opdata; /* annoyance, WM_gesture_straightline_modal, frees */ + int ret; + + ret = WM_gesture_straightline_modal(C, op, event); + + if (ret & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) { + edbm_bisect_exit(C, &opdata_back); + } + + return ret; +} + +/* End Model Helpers */ +/* -------------------------------------------------------------------- */ + + + +static int mesh_bisect_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + + /* both can be NULL, fallbacks values are used */ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = ED_view3d_context_rv3d(C); + + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm; + BMOperator bmop; + float plane_co[3]; + float plane_no[3]; + float imat[4][4]; + + const float thresh = RNA_float_get(op->ptr, "threshold"); + const bool use_fill = RNA_boolean_get(op->ptr, "use_fill"); + const bool clear_inner = RNA_boolean_get(op->ptr, "clear_inner"); + const bool clear_outer = RNA_boolean_get(op->ptr, "clear_outer"); + + PropertyRNA *prop_plane_co; + PropertyRNA *prop_plane_no; + + prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co"); + if (RNA_property_is_set(op->ptr, prop_plane_co)) { + RNA_property_float_get_array(op->ptr, prop_plane_co, plane_co); + } + else { + copy_v3_v3(plane_co, give_cursor(scene, v3d)); + RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co); + } + + prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no"); + if (RNA_property_is_set(op->ptr, prop_plane_no)) { + RNA_property_float_get_array(op->ptr, prop_plane_no, plane_no); + } + else { + if (rv3d) { + copy_v3_v3(plane_no, rv3d->viewinv[1]); + } + else { + /* fallback... */ + plane_no[0] = plane_no[1] = 0.0f; plane_no[2] = 1.0f; + } + RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no); + } + + + + /* -------------------------------------------------------------------- */ + /* Modal support */ + /* Note: keep this isolated, exec can work wihout this */ + if ((op->customdata != NULL) && + mesh_bisect_interactive_calc(C, op, em, plane_co, plane_no)) + { + /* write back to the props */ + RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no); + RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co); + } + /* End Modal */ + /* -------------------------------------------------------------------- */ + + + + bm = em->bm; + + invert_m4_m4(imat, obedit->obmat); + mul_m4_v3(imat, plane_co); + mul_mat3_m4_v3(imat, plane_no); + + EDBM_op_init(em, &bmop, op, + "bisect_plane geom=%hvef plane_co=%v plane_no=%v dist=%f clear_inner=%b clear_outer=%b", + BM_ELEM_SELECT, plane_co, plane_no, thresh, clear_inner, clear_outer); + BMO_op_exec(bm, &bmop); + + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + if (use_fill) { + float normal_fill[3]; + BMOperator bmop_fill; + BMOperator bmop_attr; + + normalize_v3_v3(normal_fill, plane_no); + if (clear_outer == true && clear_inner == false) { + negate_v3(normal_fill); + } + + /* Fill */ + BMO_op_initf( + bm, &bmop_fill, op->flag, + "triangle_fill edges=%S normal=%v use_dissolve=%b", + &bmop, "geom_cut.out", normal_fill, true); + BMO_op_exec(bm, &bmop_fill); + + /* Copy Attributes */ + BMO_op_initf(bm, &bmop_attr, op->flag, + "face_attribute_fill faces=%S use_normals=%b use_data=%b", + &bmop_fill, "geom.out", false, true); + BMO_op_exec(bm, &bmop_attr); + + BMO_slot_buffer_hflag_enable(bm, bmop_fill.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true); + + BMO_op_finish(bm, &bmop_attr); + BMO_op_finish(bm, &bmop_fill); + } + + BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom_cut.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true); + + if (!EDBM_op_finish(em, &bmop, op, true)) { + return OPERATOR_CANCELLED; + } + else { + EDBM_update_generic(em, true, true); + EDBM_selectmode_flush(em); + return OPERATOR_FINISHED; + } +} + + +void MESH_OT_bisect(struct wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Bisect"; + ot->description = "Cut geometry along a plane"; + ot->idname = "MESH_OT_bisect"; + + /* api callbacks */ + ot->exec = mesh_bisect_exec; + ot->invoke = mesh_bisect_invoke; + ot->modal = mesh_bisect_modal; + ot->cancel = WM_gesture_straightline_cancel; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + + prop = RNA_def_float_vector(ot->srna, "plane_co", 3, NULL, -FLT_MAX, FLT_MAX, + "Plane Point", "A point on the plane", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_float_vector(ot->srna, "plane_no", 3, NULL, -FLT_MAX, FLT_MAX, + "Plane Normal", "The direction the plane points", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill in the cut"); + RNA_def_boolean(ot->srna, "clear_inner", false, "Clear Inner", "Remove geometry behind the plane"); + RNA_def_boolean(ot->srna, "clear_outer", false, "Clear Outer", "Remove geometry in front of the plane"); + + RNA_def_float(ot->srna, "threshold", 0.0001, 0.0, 10.0, "Axis Threshold", "", 0.00001, 0.1); + + WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); +} diff --git a/source/blender/editors/mesh/editmesh_deform_laplacian.c b/source/blender/editors/mesh/editmesh_deform_laplacian.c index 2e83a550022..4c1cb547684 100644 --- a/source/blender/editors/mesh/editmesh_deform_laplacian.c +++ b/source/blender/editors/mesh/editmesh_deform_laplacian.c @@ -758,9 +758,9 @@ wmKeyMap * laplacian_deform_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, HKEY, KM_PRESS, 0, 0, LAP_MODAL_MARK_STATIC); WM_modalkeymap_add_item(keymap, PKEY, KM_PRESS, 0, 0, LAP_MODAL_PREVIEW); - WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, LAP_MODAL_TRANSFORM); - WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, LAP_MODAL_TRANSFORM); - WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, LAP_MODAL_TRANSFORM); + //WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, LAP_MODAL_TRANSFORM); + //WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, LAP_MODAL_TRANSFORM); + //WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, LAP_MODAL_TRANSFORM); WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, LAP_MODAL_NOTHING); WM_modalkeymap_add_item(keymap, TKEY, KM_PRESS, 0, 0, LAP_MODAL_NOTHING); diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index b38f09b1dec..300fb67ec80 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -836,6 +836,8 @@ static int edbm_screw_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + copy_v3_v3(nor, obedit->obmat[2]); + /* calculate dvec */ mul_v3_m4v3(v1_co_global, obedit->obmat, v1->co); mul_v3_m4v3(v2_co_global, obedit->obmat, v2->co); diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index dba19ee5da6..3966826a5b2 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -228,10 +228,8 @@ static bool edbm_inset_calc(wmOperator *op) BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); } else { - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE, BM_ELEM_SELECT, false); - BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, false); - /* re-select faces so the verts and edges get selected too */ - BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, BM_ELEM_SELECT); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_in, "faces", BM_FACE, BM_ELEM_SELECT, true); } if (!EDBM_op_finish(em, &bmop, op, true)) { diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index e1d0a412ce7..5e88ecabd35 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -308,7 +308,7 @@ static void knife_add_edge_faces_to_vert(KnifeTool_OpData *kcd, KnifeVert *kfv, BMIter bmiter; BMFace *f; - BM_ITER_ELEM(f, &bmiter, e, BM_FACES_OF_EDGE) { + BM_ITER_ELEM (f, &bmiter, e, BM_FACES_OF_EDGE) { knife_append_list(kcd, &kfv->faces, f); } } @@ -354,7 +354,7 @@ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v) kfv = new_knife_vert(kcd, v->co, kcd->cagecos[BM_elem_index_get(v)]); kfv->v = v; BLI_ghash_insert(kcd->origvertmap, v, kfv); - BM_ITER_ELEM(f, &bmiter, v, BM_FACES_OF_VERT) { + BM_ITER_ELEM (f, &bmiter, v, BM_FACES_OF_VERT) { knife_append_list(kcd, &kfv->faces, f); } } @@ -379,7 +379,7 @@ static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e) BLI_ghash_insert(kcd->origedgemap, e, kfe); - BM_ITER_ELEM(f, &bmiter, e, BM_FACES_OF_EDGE) { + BM_ITER_ELEM (f, &bmiter, e, BM_FACES_OF_EDGE) { knife_append_list(kcd, &kfe->faces, f); } } @@ -420,7 +420,7 @@ static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, BMFace *f) lst = knife_empty_list(kcd); - BM_ITER_ELEM(e, &bmiter, f, BM_EDGES_OF_FACE) { + BM_ITER_ELEM (e, &bmiter, f, BM_EDGES_OF_FACE) { knife_append_list(kcd, lst, get_bm_knife_edge(kcd, e)); } @@ -497,13 +497,16 @@ static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd, KnifeEdge *kfe, float * and move cur data to prev. */ static void knife_add_single_cut(KnifeTool_OpData *kcd) { - KnifeEdge *kfe = new_knife_edge(kcd), *kfe2 = NULL, *kfe3 = NULL; + KnifeEdge *kfe, *kfe2 = NULL, *kfe3 = NULL; - if (kcd->prev.vert && kcd->prev.vert == kcd->curr.vert) - return; - if (kcd->prev.edge && kcd->prev.edge == kcd->curr.edge) + if ((kcd->prev.vert && kcd->prev.vert == kcd->curr.vert) || + (kcd->prev.edge && kcd->prev.edge == kcd->curr.edge)) + { + kcd->prev = kcd->curr; return; + } + kfe = new_knife_edge(kcd); kfe->draw = true; if (kcd->prev.vert) { @@ -573,38 +576,107 @@ static int verge_linehit(const void *vlh1, const void *vlh2) if (lh1->l < lh2->l) return -1; else if (lh1->l > lh2->l) return 1; + else if (lh1->v && lh2->v) { + /* want like verts to sort together; just compare pointers */ + if (lh1->v < lh2->v) return -1; + else if (lh1->v > lh2->v) return 1; + else return 0; + } else return 0; } /* If there's a linehit connected (same face) as testi in range [firsti, lasti], return the first such, else -1. + * It also counts as connected if both linehits are snapped to the same vertex. * If testi is out of range, look for connection to f instead, if f is non-NULL */ static int find_connected_linehit(KnifeTool_OpData *kcd, int testi, BMFace *f, int firsti, int lasti) { int i; - - for (i = firsti; i <= lasti; i++) { - if (testi >= 0 && testi < kcd->totlinehit) { - if (knife_find_common_face(&kcd->linehits[testi].kfe->faces, - &kcd->linehits[i].kfe->faces)) - { - return i; - } - } - else if (f) { - if (find_ref(&kcd->linehits[i].kfe->faces, f)) - return i; + ListBase *testfaces, *ifaces; + BMFace *testface, *iface; + BMEdgeHit *lh; + bool shareface; + + if (testi >= 0 && testi < kcd->totlinehit) { + testface = NULL; + testfaces = NULL; + lh = &kcd->linehits[testi]; + if (lh->v) + testfaces = &lh->v->faces; + else if (lh->kfe) + testfaces = &lh->kfe->faces; + else if (lh->f) { + testfaces = NULL; + testface = lh->f; } } + else { + testface = f; + testfaces = NULL; + } + for (i = firsti; i <= lasti; i++) { + shareface = false; + lh = &kcd->linehits[i]; + iface = NULL; + ifaces = NULL; + if (lh->v) + ifaces = &lh->v->faces; + else if (lh->kfe) + ifaces = &lh->kfe->faces; + else if (lh->f) { + ifaces = NULL; + iface = lh->f; + } + if (testfaces) { + if (ifaces) + shareface = (knife_find_common_face(testfaces, ifaces) != NULL); + else if (iface) + shareface = (find_ref(testfaces, iface) != NULL); + } + else if (ifaces) { + if (testface) + shareface = (find_ref(ifaces, testface) != NULL); + } + else if (testface && iface) { + shareface = (testface == iface); + } + if (shareface) + return i; + } return -1; } -/* Sort in order of distance along cut line, but take care when distances are equal */ -static void knife_sort_linehits(KnifeTool_OpData *kcd) +/* Sort in order of distance along cut line. + * Remove any successive linehits that are snapped to the same vertex. + * If joinfaces, treat hits at same distance as follows: try to find + * ordering so that preceding and succeeding hits will share a face. + */ +static void knife_sort_linehits(KnifeTool_OpData *kcd, bool joinfaces) { int i, j, k, nexti, nsame; qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit); + /* Remove duplicated linehits snapped to same vertex */ + i = j = 0; /* loop copies from j to i */ + while (j < kcd->totlinehit) { + nsame = 0; + if (kcd->linehits[j].v) { + for (k = j + 1; k < kcd->totlinehit; k++) { + if (kcd->linehits[k].v != kcd->linehits[j].v) + break; + nsame++; + } + } + if (i != j) + kcd->linehits[i] = kcd->linehits[j]; + i++; + j += 1 + nsame; + } + kcd->totlinehit = i; + + if (!joinfaces) + return; + /* for ranges of equal "l", swap if neccesary to make predecessor and * successor faces connected to the linehits at either end of the range */ for (i = 0; i < kcd->totlinehit - 1; i = nexti) { @@ -653,6 +725,7 @@ static void knife_add_single_cut_through(KnifeTool_OpData *kcd, KnifeVert *v1, K knife_edge_append_face(kcd, kfenew, f); } +#if 0 static void knife_get_vert_faces(KnifeTool_OpData *kcd, KnifeVert *kfv, BMFace *facef, ListBase *lst) { BMIter bmiter; @@ -685,20 +758,33 @@ static void knife_get_edge_faces(KnifeTool_OpData *kcd, KnifeEdge *kfe, ListBase } } } +#endif + +static void copy_hit_from_posdata(BMEdgeHit *lh, KnifePosData *pos, float lambda) +{ + lh->kfe = pos->edge; + lh->v = pos->vert; + lh->f = pos->bmface; + copy_v3_v3(lh->hit, pos->co); + copy_v3_v3(lh->cagehit, pos->cage); + copy_v3_v3(lh->realhit, pos->co); + lh->l = lambda; + /* perc and schit not used by callers of this function */ +} /* BMESH_TODO: add more functionality to cut-through: * - cutting "in face" (e.g., holes) should cut in all faces, not just visible one * - perhaps improve O(n^2) algorithm used here */ static void knife_cut_through(KnifeTool_OpData *kcd) { - BMEdgeHit *lh, *lh2; + BMEdgeHit *lh, *lh2, *linehits; BMFace *f; - KnifeEdge *kfe, *kfe2, *kfe3; - KnifeVert *v1, *v2, *firstv = NULL, *lastv = NULL; - ListBase firstfaces = {NULL, NULL}, lastfaces = {NULL, NULL}; - Ref *r, *r2; + KnifeEdge *kfe, *kfe2; + KnifeVert *v1, *v2, *lastv; + ListBase *faces1, *faces2; KnifeEdge **splitkfe; - int i, j; + bool needprev, needcurr; + int i, j, n; if (!kcd->totlinehit) { /* if no linehits then no interesting back face stuff to do */ @@ -706,93 +792,68 @@ static void knife_cut_through(KnifeTool_OpData *kcd) return; } - /* TODO: probably don't need to sort at all */ - qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit); - splitkfe = MEM_callocN(kcd->totlinehit * sizeof(KnifeEdge *), "knife_cut_through"); + /* sort eliminates hits on same vertices */ + knife_sort_linehits(kcd, false); - if (kcd->prev.vert) { - if (kcd->prev.vert == kcd->curr.vert) - return; - firstv = kcd->prev.vert; - knife_get_vert_faces(kcd, firstv, kcd->prev.bmface, &firstfaces); - } - else if (kcd->prev.edge) { - if (kcd->prev.edge == kcd->curr.edge) - return; - firstv = knife_split_edge(kcd, kcd->prev.edge, kcd->prev.co, &kfe3); - knife_get_edge_faces(kcd, kcd->prev.edge, &firstfaces); + /* code is cleaner if make prev and curr into hits (if they are on edges or verts) */ + n = kcd->totlinehit; + needprev = ((kcd->prev.vert && kcd->prev.vert != kcd->linehits[0].v) || kcd->prev.edge); + needcurr = ((kcd->curr.vert && kcd->curr.vert != kcd->linehits[n - 1].v) || kcd->curr.edge); + n += needprev + needcurr; + linehits = MEM_callocN(n * sizeof(BMEdgeHit), "knife_cut_through"); + i = 0; + if (needprev) { + copy_hit_from_posdata(&linehits[0], &kcd->prev, 0.0f); + i++; } + memcpy(linehits + i, kcd->linehits, kcd->totlinehit * sizeof(BMEdgeHit)); + i += kcd->totlinehit; + if (needcurr) + copy_hit_from_posdata(&linehits[i], &kcd->curr, 1.0f); - if (kcd->curr.vert) { - lastv = kcd->curr.vert; - knife_get_vert_faces(kcd, lastv, kcd->curr.bmface, &lastfaces); - } - else if (kcd->curr.edge) { - lastv = knife_split_edge(kcd, kcd->curr.edge, kcd->curr.co, &kfe3); - knife_get_edge_faces(kcd, kcd->curr.edge, &lastfaces); - } - - if (firstv) { - /* For each face incident to firstv, - * find the first following linehit (if any) sharing that face and connect */ - for (r = firstfaces.first; r; r = r->next) { - bool found = false; - f = r->ref; - for (j = 0, lh2 = kcd->linehits; j < kcd->totlinehit && !found; j++, lh2++) { - kfe2 = lh2->kfe; - for (r2 = kfe2->faces.first; r2; r2 = r2->next) { - if (r2->ref == f) { - v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]); - knife_add_single_cut_through(kcd, firstv, v2, f); - found = true; - break; - } - } - } - if (!found && lastv) { - for (r2 = lastfaces.first; r2; r2 = r2->next) { - if (r2->ref == f) { - knife_add_single_cut_through(kcd, firstv, lastv, f); - break; - } - } - } - } - } - for (i = 0, lh = kcd->linehits; i < kcd->totlinehit; i++, lh++) { + splitkfe = MEM_callocN(n * sizeof(KnifeEdge *), "knife_cut_through"); + + lastv = NULL; + for (i = 0, lh = linehits; i < n; i++, lh++) { kfe = lh->kfe; + v1 = NULL; - /* For each face attached to edge for this linehit, - * find the first following linehit (if any) sharing that face and connect */ - for (r = kfe->faces.first; r; r = r->next) { - bool found = false; - f = r->ref; - for (j = i + 1, lh2 = lh + 1; j < kcd->totlinehit && !found; j++, lh2++) { - kfe2 = lh2->kfe; - for (r2 = kfe2->faces.first; r2; r2 = r2->next) { - if (r2->ref == f) { - v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]); - v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]); - knife_add_single_cut_through(kcd, v1, v2, f); - found = true; - break; - } - } + /* get faces incident on hit lh */ + if (lh->v) { + v1 = lh->v; + faces1 = &v1->faces; + } + else if (kfe) { + faces1 = &kfe->faces; + } + + /* For each following hit, connect if lh1 an lh2 share a face */ + for (j = i + 1, lh2 = lh + 1; j < n; j++, lh2++) { + kfe2 = lh2->kfe; + v2 = NULL; + if (lh2->v) { + v2 = lh2->v; + faces2 = &v2->faces; } - if (!found && lastv) { - for (r2 = lastfaces.first; r2; r2 = r2->next) { - if (r2->ref == f) { - v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]); - knife_add_single_cut_through(kcd, v1, lastv, f); - break; - } - } + else if (kfe2) { + faces2 = &kfe2->faces; + } + + f = knife_find_common_face(faces1, faces2); + if (f) { + if (!v1) + v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]); + if (!v2) + v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]); + knife_add_single_cut_through(kcd, v1, v2, f); + lastv = v2; } } } MEM_freeN(splitkfe); + MEM_freeN(linehits); MEM_freeN(kcd->linehits); kcd->linehits = NULL; kcd->totlinehit = 0; @@ -816,7 +877,7 @@ static void knife_add_cut(KnifeTool_OpData *kcd) BMEdgeHit *lh, *lastlh, *firstlh; int i; - knife_sort_linehits(kcd); + knife_sort_linehits(kcd, true); lh = kcd->linehits; lastlh = firstlh = NULL; @@ -848,14 +909,14 @@ static void knife_add_cut(KnifeTool_OpData *kcd) continue; /* first linehit may be down face parallel to view */ - if (!lastlh && fabsf(lh->l) < KNIFE_FLT_EPS) + if (!lastlh && !lh->v && fabsf(lh->l) < KNIFE_FLT_EPS) continue; if (kcd->prev.is_space) { kcd->prev.is_space = 0; copy_v3_v3(kcd->prev.co, lh->hit); copy_v3_v3(kcd->prev.cage, lh->cagehit); - kcd->prev.vert = NULL; + kcd->prev.vert = lh->v; kcd->prev.edge = lh->kfe; kcd->prev.bmface = lh->f; continue; @@ -1172,6 +1233,69 @@ static float len_v3_tri_side_max(const float v1[3], const float v2[3], const flo return sqrtf(max_fff(s1, s2, s3)); } +/** + * given a tri, return 3 planes aligned with the tri's normal. + * + * If the triangle were extruded along its normal, + * the planes calculated would be the 3 sides around the extrusion. + */ +static void plane_from_tri_clip3_v3( + float tri_plane_clip[3][4], + const float v0[3], const float v1[3], const float v2[3]) +{ + float tri_norm[3]; + float tvec[3], cross[3]; + + normal_tri_v3(tri_norm, v0, v1, v2); + + sub_v3_v3v3(tvec, v0, v1); + cross_v3_v3v3(cross, tvec, tri_norm); + plane_from_point_normal_v3(tri_plane_clip[0], v0, cross); + + sub_v3_v3v3(tvec, v1, v2); + cross_v3_v3v3(cross, tvec, tri_norm); + plane_from_point_normal_v3(tri_plane_clip[1], v1, cross); + + sub_v3_v3v3(tvec, v2, v0); + cross_v3_v3v3(cross, tvec, tri_norm); + plane_from_point_normal_v3(tri_plane_clip[2], v2, cross); +} + +/** + * Given a line that is planar with a tri, clip the segment by that tri. + * + * This is needed so we end up with both points in the triangle. + */ +static bool isect_line_tri_coplanar_v3( + const float p1[3], const float p2[3], + const float v0[3], const float v1[3], const float v2[3], + float r_isects[2][3], + + /* avoid re-calculating every time */ + float tri_plane[4], float tri_plane_clip[3][4]) +{ + float p1_tmp[3] = {UNPACK3(p1)}; + float p2_tmp[3] = {UNPACK3(p2)}; + + (void)v0, (void)v1, (void)v2; + + /* first check if the points are planar with the tri */ + if ((fabsf(dist_squared_to_plane_v3(p1, tri_plane)) < KNIFE_FLT_EPS_SQUARED) && + (fabsf(dist_squared_to_plane_v3(p2, tri_plane)) < KNIFE_FLT_EPS_SQUARED) && + /* clip the segment by planes around the triangle so we can be sure the points + * aren't outside the triangle */ + (clip_segment_v3_plane_n(p1_tmp, p2_tmp, tri_plane_clip, 3))) + { + copy_v3_v3(r_isects[0], p1_tmp); + copy_v3_v3(r_isects[1], p2_tmp); + + return true; + } + else { + return false; + } +} + static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, const float v1[3], const float v2[3], const float v3[3], SmallHash *ehash, bglMats *mats, int *count) @@ -1181,9 +1305,11 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, BLI_array_declare(edges); BVHTreeOverlap *results, *result; BMLoop **ls; - float cos[9], lambda; + float cos[9], tri_norm[3], tri_plane[4], isects[2][3], lambda; + float tri_plane_clip[3][4]; unsigned int tot = 0; - int i; + int i, j, n_isects; + /* for comparing distances, error of intersection depends on triangle scale. * need to scale down before squaring for accurate comparison */ @@ -1194,6 +1320,11 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, copy_v3_v3(cos + 3, v2); copy_v3_v3(cos + 6, v3); + /* avoid re-calculation in #isect_line_tri_coplanar_v3 */ + normal_tri_v3(tri_norm, v1, v2, v3); + plane_from_point_normal_v3(tri_plane, v1, tri_norm); + plane_from_tri_clip3_v3(tri_plane_clip, v1, v2, v3); + BLI_bvhtree_insert(tree2, 0, cos, 3); BLI_bvhtree_balance(tree2); @@ -1217,11 +1348,28 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, continue; /* We already found a hit on this knife edge */ } - if (isect_line_tri_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, &lambda, NULL)) { - float p[3], no[3], view[3], sp[2]; + n_isects = 0; - interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda); + if (isect_line_tri_coplanar_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, + isects, + /* cached values */ + tri_plane, tri_plane_clip)) + { + /* both kfe ends are in cutting triangle */ + n_isects = 2; + } + else if (isect_line_tri_epsilon_v3(kfe->v1->cageco, kfe->v2->cageco, v1, v2, v3, + &lambda, NULL, depsilon)) + { + /* kfe intersects cutting triangle lambda of the way along kfe */ + interp_v3_v3v3(isects[0], kfe->v1->cageco, kfe->v2->cageco, lambda); + n_isects = 1; + } + + for (j = 0; j < n_isects; j++) { + float p[3]; + copy_v3_v3(p, isects[j]); if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_sq) { continue; } @@ -1239,16 +1387,18 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, continue; } - knife_project_v2(kcd, p, sp); - ED_view3d_unproject(mats, view, sp[0], sp[1], 0.0f); - mul_m4_v3(kcd->ob->imat, view); - if (kcd->cut_through) { f_hit = NULL; } else { /* check if this point is visible in the viewport */ - float p1[3], lambda1; + float p1[3], no[3], view[3], sp[2]; + float lambda1; + + /* screen projection */ + knife_project_v2(kcd, p, sp); + ED_view3d_unproject(mats, view, sp[0], sp[1], 0.0f); + mul_m4_v3(kcd->ob->imat, view); /* if face isn't planer, p may be behind the current tesselated tri, * so move it onto that and then a little towards eye */ @@ -1268,7 +1418,7 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, add_v3_v3(p1, no); /* ray cast */ - f_hit = BKE_bmbvh_ray_cast(bmtree, p1, no, NULL, NULL, NULL); + f_hit = BKE_bmbvh_ray_cast(bmtree, p1, no, KNIFE_FLT_EPS, NULL, NULL, NULL); } /* ok, if visible add the new point */ @@ -1283,6 +1433,7 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, hit.kfe = kfe; hit.v = NULL; + hit.l = 0.0f; knife_find_basef(kfe); hit.f = kfe->basef; @@ -1292,7 +1443,6 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, interp_v3_v3v3(p, kfe->v1->co, kfe->v2->co, hit.perc); copy_v3_v3(hit.realhit, p); - /* BMESH_TODO: should also snap to vertices */ if (kcd->snap_midpoints) { float perc = hit.perc; @@ -1310,6 +1460,12 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, interp_v3_v3v3(hit.hit, kfe->v1->co, kfe->v2->co, perc); interp_v3_v3v3(hit.cagehit, kfe->v1->cageco, kfe->v2->cageco, perc); } + else if (hit.perc < KNIFE_FLT_EPS || hit.perc > 1.0f - KNIFE_FLT_EPS) { + /* snap to vert */ + hit.v = (hit.perc < KNIFE_FLT_EPS) ? kfe->v1 : kfe->v2; + copy_v3_v3(hit.hit, hit.v->co); + copy_v3_v3(hit.cagehit, hit.v->co); + } else { copy_v3_v3(hit.hit, p); } @@ -1347,7 +1503,7 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd) float max_xyz = 0.0f; int i; - BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { for (i = 0; i < 3; i++) max_xyz = max_ff(max_xyz, fabs(v->co[i])); } @@ -1390,8 +1546,16 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) knife_project_v2(kcd, v1, s1); knife_project_v2(kcd, v2, s2); - if (len_squared_v2v2(s1, s2) < 1) - return; + if (kcd->is_interactive) { + if (len_squared_v2v2(s1, s2) < 1.0f) { + return; + } + } + else { + if (len_squared_v2v2(s1, s2) < KNIFE_FLT_EPS_SQUARED) { + return; + } + } /* unproject screen line */ ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, s1, v1, v3, true); @@ -1502,7 +1666,7 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs); sub_v3_v3v3(ray, origin_ofs, origin); - f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray, NULL, co, cageco); + f = BKE_bmbvh_ray_cast(kcd->bmbvh, origin, ray, 0.0f, NULL, co, cageco); if (is_space) *is_space = !f; @@ -1652,7 +1816,7 @@ static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], flo if (fptr) *fptr = f; - if (cure && p) { + if (cure) { if (!kcd->ignore_edge_snapping || !(cure->e)) { KnifeVert *edgesnap = NULL; @@ -1745,7 +1909,7 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo if (fptr) *fptr = f; - if (curv && p) { + if (curv) { copy_v3_v3(p, curv->co); copy_v3_v3(cagep, curv->cageco); @@ -1993,7 +2157,7 @@ static void knifenet_fill_faces(KnifeTool_OpData *kcd) for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { if (!kfv->v) { /* shouldn't we be at least copying the normal? - if not some comment here should explain why - campbell */ - kfv->v = BM_vert_create(bm, kfv->co, NULL); + kfv->v = BM_vert_create(bm, kfv->co, NULL, BM_CREATE_NOP); kfv->flag = 1; BMO_elem_flag_enable(bm, kfv->v, DEL); } @@ -2656,7 +2820,7 @@ static void knife_make_chain_cut(KnifeTool_OpData *kcd, BMFace *f, ListBase *cha l_new = NULL; if (nco == 0) { /* Want to prevent creating two-sided polygons */ - if (BM_edge_exists(v1, v2)) { + if (v1 == v2 || BM_edge_exists(v1, v2)) { f_new = NULL; } else { @@ -2683,7 +2847,7 @@ static void knife_make_chain_cut(KnifeTool_OpData *kcd, BMFace *f, ListBase *cha BM_edge_select_set(bm, l_new->e, true); } } - else { + else if (f_new) { BM_elem_select_copy(bm, bm, f_new, f); } @@ -2918,7 +3082,7 @@ static void knifetool_exit_ex(bContext *C, KnifeTool_OpData *kcd) return; if (kcd->is_interactive) { - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); /* deactivate the extra drawing stuff in 3D-View */ ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle); @@ -3053,7 +3217,7 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event) knifetool_init(C, kcd, only_select, cut_through, true); /* add a modal handler for this operator - handles loop selection */ - WM_cursor_modal(CTX_wm_window(C), BC_KNIFECURSOR); + WM_cursor_modal_set(CTX_wm_window(C), BC_KNIFECURSOR); WM_event_add_modal_handler(C, op); knifetool_update_mval_i(kcd, event->mval); @@ -3073,7 +3237,8 @@ enum { KNF_MODEL_IGNORE_SNAP_OFF, KNF_MODAL_ADD_CUT, KNF_MODAL_ANGLE_SNAP_TOGGLE, - KNF_MODAL_CUT_THROUGH_TOGGLE + KNF_MODAL_CUT_THROUGH_TOGGLE, + KNF_MODAL_PANNING }; wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf) @@ -3089,6 +3254,7 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf) {KNF_MODAL_CUT_THROUGH_TOGGLE, "CUT_THROUGH_TOGGLE", 0, "Toggle Cut Through", ""}, {KNF_MODAL_NEW_CUT, "NEW_CUT", 0, "End Current Cut", ""}, {KNF_MODAL_ADD_CUT, "ADD_CUT", 0, "Add Cut", ""}, + {KNF_MODAL_PANNING, "PANNING", 0, "Panning", ""}, {0, NULL, 0, NULL, NULL} }; @@ -3102,6 +3268,7 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf) /* items for modal map */ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CANCEL); + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_ANY, KM_ANY, 0, KNF_MODAL_PANNING); WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, KNF_MODAL_ADD_CUT); WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, KNF_MODAL_CANCEL); WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM); @@ -3227,18 +3394,12 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event) ED_region_tag_redraw(kcd->ar); break; - } - } - else { /* non-modal-mapped events */ - switch (event->type) { - case WHEELUPMOUSE: - case WHEELDOWNMOUSE: - return OPERATOR_PASS_THROUGH; - case MIDDLEMOUSE: + case KNF_MODAL_PANNING: if (event->val != KM_RELEASE) { - if (kcd->mode != MODE_PANNING) + if (kcd->mode != MODE_PANNING) { kcd->prevmode = kcd->mode; - kcd->mode = MODE_PANNING; + kcd->mode = MODE_PANNING; + } } else { kcd->mode = kcd->prevmode; @@ -3246,7 +3407,17 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event) ED_region_tag_redraw(kcd->ar); return OPERATOR_PASS_THROUGH; - + break; + } + } + else { /* non-modal-mapped events */ + switch (event->type) { + case MOUSEPAN: + case MOUSEZOOM: + case MOUSEROTATE: + case WHEELUPMOUSE: + case WHEELDOWNMOUSE: + return OPERATOR_PASS_THROUGH; case MOUSEMOVE: /* mouse moved somewhere to select another loop */ if (kcd->mode != MODE_PANNING) { knifetool_update_mval_i(kcd, event->mval); @@ -3354,7 +3525,7 @@ static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f, 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); + isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1, false); p = p->next; } diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index e7eaa625843..18db21a8726 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -52,6 +52,9 @@ #include "WM_types.h" +#include "bmesh.h" +#include "bmesh_tools.h" + #include "mesh_intern.h" /* own include */ struct UserData { diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 1360a180b2d..84952297235 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -50,6 +50,9 @@ #include "ED_transform.h" #include "ED_view3d.h" +#include "bmesh.h" +#include "bmesh_tools.h" + #include "mesh_intern.h" /* own include */ /** @@ -60,23 +63,29 @@ * point and would result in the same distance. */ #define INSET_DEFAULT 0.00001f -static float edbm_rip_edgedist(ARegion *ar, float mat[4][4], - const float co1[3], const float co2[3], const float mvalf[2], - const float inset) +static float edbm_rip_edgedist_squared(ARegion *ar, float mat[4][4], + const float co1[3], const float co2[3], const float mvalf[2], + const float inset) { - float vec1[2], vec2[2]; + float vec1[2], vec2[2], dist_sq; ED_view3d_project_float_v2_m4(ar, co1, vec1, mat); ED_view3d_project_float_v2_m4(ar, co2, vec2, mat); if (inset != 0.0f) { - const float dist = inset / len_v2v2(vec1, vec2); - interp_v2_v2v2(vec1, vec1, vec2, dist); - interp_v2_v2v2(vec2, vec2, vec1, dist); + const float dist_2d = len_v2v2(vec1, vec2); + if (dist_2d > FLT_EPSILON) { + const float dist = inset / dist_2d; + BLI_assert(finite(dist)); + interp_v2_v2v2(vec1, vec1, vec2, dist); + interp_v2_v2v2(vec2, vec2, vec1, dist); + } } - /* TODO: use dist_squared_to_line_segment_v2() looks like we only ever use for comparison */ - return dist_to_line_segment_v2(mvalf, vec1, vec2); + dist_sq = dist_squared_to_line_segment_v2(mvalf, vec1, vec2); + BLI_assert(finite(dist_sq)); + + return dist_sq; } #if 0 @@ -488,7 +497,7 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u /* face should never exist */ BLI_assert(BM_face_exists(f_verts, f_verts[3] ? 4 : 3, &f) == false); - f = BM_face_create_quad_tri_v(bm, f_verts, f_verts[3] ? 4 : 3, f_example, false); + f = BM_face_create_verts(bm, f_verts, f_verts[3] ? 4 : 3, f_example, BM_CREATE_NOP, true); l_iter = BM_FACE_FIRST_LOOP(f); @@ -525,11 +534,11 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve BMIter iter, liter; BMLoop *l; BMEdge *e, *e2; - BMVert *v, *ripvert = NULL; + BMVert *v; const int totvert_orig = bm->totvert; int i; float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]}; - float dist = FLT_MAX; + float dist_sq = FLT_MAX; float d; bool is_wire; @@ -562,15 +571,15 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve if (v->e) { /* find closest edge to mouse cursor */ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - int is_boundary = BM_edge_is_boundary(e); + const bool is_boundary = BM_edge_is_boundary(e); /* consider wire as boundary for this purpose, * otherwise we can't a face away from a wire edge */ totboundary_edge += (is_boundary != 0 || BM_edge_is_wire(e)); if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { if (is_boundary == false && BM_edge_is_manifold(e)) { - d = edbm_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT); - if (d < dist) { - dist = d; + d = edbm_rip_edgedist_squared(ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT); + if ((e2 == NULL) || (d < dist_sq)) { + dist_sq = d; e2 = e; } } @@ -596,10 +605,9 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve float l_mid_co[3]; l = l_all[i1]; edbm_calc_loop_co(l, l_mid_co); - d = edbm_rip_edgedist(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT); - - if (d < dist) { - dist = d; + d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT); + if ((e2 == NULL) || (d < dist_sq)) { + dist_sq = d; /* find the edge that is not in this loop */ e2 = NULL; @@ -647,7 +655,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve BM_select_history_remove(bm, ese.ele); } - dist = FLT_MAX; + dist_sq = FLT_MAX; /* in the loop below we find the best vertex to drag based on its connected geometry, * either by its face corner, or connected edge (when no faces are attached) */ @@ -658,12 +666,12 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve BM_ITER_ELEM (l, &iter, vout[i], BM_LOOPS_OF_VERT) { if (!BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) { float l_mid_co[3]; - edbm_calc_loop_co(l, l_mid_co); - d = edbm_rip_edgedist(ar, projectMat, v->co, l_mid_co, fmval, INSET_DEFAULT); + edbm_calc_loop_co(l, l_mid_co); + d = edbm_rip_edgedist_squared(ar, projectMat, v->co, l_mid_co, fmval, INSET_DEFAULT); - if (d < dist) { - dist = d; + if (d < dist_sq) { + dist_sq = d; vi_best = i; } } @@ -674,12 +682,12 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve BM_ITER_ELEM (e, &iter, vout[i], BM_EDGES_OF_VERT) { if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { float e_mid_co[3]; - mid_v3_v3v3(e_mid_co, e->v1->co, e->v2->co); - d = edbm_rip_edgedist(ar, projectMat, v->co, e_mid_co, fmval, INSET_DEFAULT); + mid_v3_v3v3(e_mid_co, e->v1->co, e->v2->co); + d = edbm_rip_edgedist_squared(ar, projectMat, v->co, e_mid_co, fmval, INSET_DEFAULT); - if (d < dist) { - dist = d; + if (d < dist_sq) { + dist_sq = d; vi_best = i; } } @@ -730,19 +738,36 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve /* rip two adjacent edges */ if (BM_edge_is_boundary(e2) || BM_vert_face_count(v) == 2) { /* Don't run the edge split operator in this case */ + BMVert *v_rip; - BM_elem_flag_enable(e2, BM_ELEM_TAG); /* only for face-fill (we don't call the operator) */ + l = BM_edge_vert_share_loop(e2->l, v); + + /* only tag for face-fill (we don't call the operator) */ + if (BM_edge_is_boundary(e2)) { + BM_elem_flag_enable(e2, BM_ELEM_TAG); + } + else { + BM_elem_flag_enable(l->e, BM_ELEM_TAG); + BM_elem_flag_enable(l->prev->e, BM_ELEM_TAG); + } /* keep directly before edgesplit */ if (do_fill) { fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm); } - l = e2->l; - ripvert = BM_face_vert_separate(bm, l->f, v); +#if 0 + v_rip = BM_face_vert_separate(bm, l->f, v); +#else + v_rip = BM_face_loop_separate(bm, l); +#endif + + BLI_assert(v_rip); - BLI_assert(ripvert); - if (!ripvert) { + if (v_rip) { + BM_vert_select_set(bm, v_rip, true); + } + else { if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs); return OPERATOR_CANCELLED; } @@ -769,37 +794,28 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve BM_mesh_edgesplit(em->bm, true, true, true); } - dist = FLT_MAX; + dist_sq = FLT_MAX; { /* --- select which vert --- */ BMVert *v_best = NULL; - float l_prev_co[3], l_next_co[3], l_corner_co[3]; - float scale; + float l_corner_co[3]; - dist = FLT_MAX; + dist_sq = FLT_MAX; BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { /* disable by default, re-enable winner at end */ BM_vert_select_set(bm, v, false); + BM_select_history_remove(bm, v); BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { - /* calculate a point in the face, rather then calculate the middle, - * make a vector pointing between the 2 edges attached to this loop */ - sub_v3_v3v3(l_prev_co, l->prev->v->co, l->v->co); - sub_v3_v3v3(l_next_co, l->next->v->co, l->v->co); - - scale = normalize_v3(l_prev_co) + normalize_v3(l_next_co); - mul_v3_fl(l_prev_co, scale); - mul_v3_fl(l_next_co, scale); - - add_v3_v3v3(l_corner_co, l_prev_co, l_next_co); - add_v3_v3(l_corner_co, l->v->co); - d = edbm_rip_edgedist(ar, projectMat, l->v->co, l_corner_co, fmval, INSET_DEFAULT); - if (d < dist) { + /* check if v_best is null in the _rare_ case there are numeric issues */ + edbm_calc_loop_co(l, l_corner_co); + d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_corner_co, fmval, INSET_DEFAULT); + if ((v_best == NULL) || (d < dist_sq)) { v_best = v; - dist = d; + dist_sq = d; } } } @@ -965,7 +981,7 @@ static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event) BMesh *bm = em->bm; BMIter iter; BMEdge *e; - int singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0); + const bool singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0); int ret; /* running in face mode hardly makes sense, so convert to region loop and rip */ diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index a1f1f6bd83f..4d512fab1c0 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -33,6 +33,7 @@ #include "BLI_listbase.h" #include "BLI_linklist.h" +#include "BLI_linklist_stack.h" #include "BLI_math.h" #include "BLI_rand.h" #include "BLI_array.h" @@ -185,53 +186,6 @@ unsigned int bm_solidoffs = 0, bm_wireoffs = 0, bm_vertoffs = 0; /* set in dr /* facilities for border select and circle select */ static char *selbuf = NULL; -/* opengl doesn't support concave... */ -static void draw_triangulated(const int mcords[][2], const short tot) -{ - ListBase lb = {NULL, NULL}; - DispList *dl; - float *fp; - int a; - const float z_up[3] = {0.0f, 0.0f, 1.0f}; - - /* make displist */ - dl = MEM_callocN(sizeof(DispList), "poly disp"); - dl->type = DL_POLY; - dl->parts = 1; - dl->nr = tot; - dl->verts = fp = MEM_callocN(tot * 3 * sizeof(float), "poly verts"); - BLI_addtail(&lb, dl); - - for (a = 0; a < tot; a++, fp += 3) { - fp[0] = (float)mcords[a][0]; - fp[1] = (float)mcords[a][1]; - } - - /* do the fill */ - BKE_displist_fill(&lb, &lb, z_up, false); - - /* do the draw */ - dl = lb.first; /* filldisplist adds in head of list */ - if (dl->type == DL_INDEX3) { - int *index; - - a = dl->parts; - fp = dl->verts; - index = dl->index; - glBegin(GL_TRIANGLES); - while (a--) { - glVertex3fv(fp + 3 * index[0]); - glVertex3fv(fp + 3 * index[1]); - glVertex3fv(fp + 3 * index[2]); - index += 3; - } - glEnd(); - } - - BKE_displist_free(&lb); -} - - /* reads rect, and builds selection array for quick lookup */ /* returns if all is OK */ bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xmax, short ymax) @@ -265,7 +219,11 @@ bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xma int EDBM_backbuf_check(unsigned int index) { + /* odd logic, if selbuf is NULL we assume no zbuf-selection is enabled + * and just ignore the depth buffer, this is error prone since its possible + * code doesn't set the depth buffer by accident, but leave for now. - Campbell */ if (selbuf == NULL) return 1; + if (index > 0 && index <= bm_vertoffs) return selbuf[index]; return 0; @@ -277,6 +235,18 @@ void EDBM_backbuf_free(void) selbuf = NULL; } +struct LassoMaskData { + unsigned int *px; + int width; +}; + +static void edbm_mask_lasso_px_cb(int x, int y, void *user_data) +{ + struct LassoMaskData *data = user_data; + data->px[(y * data->width) + x] = true; +} + + /* mcords is a polygon mask * - grab backbuffer, * - draw with black in backbuffer, @@ -285,9 +255,10 @@ void EDBM_backbuf_free(void) */ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax) { - unsigned int *dr, *drm; - struct ImBuf *buf, *bufmask; + unsigned int *dr, *dr_mask, *dr_mask_arr; + struct ImBuf *buf; int a; + struct LassoMaskData lasso_mask_data; /* method in use for face selecting too */ if (vc->obedit == NULL) { @@ -305,49 +276,25 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short dr = buf->rect; - if (vc->rv3d->gpuoffscreen) - GPU_offscreen_bind(vc->rv3d->gpuoffscreen); - - /* draw the mask */ - glDisable(GL_DEPTH_TEST); - - glColor3ub(0, 0, 0); - - /* yah, opengl doesn't do concave... tsk! */ - ED_region_pixelspace(vc->ar); - draw_triangulated(mcords, tot); - - glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */ - for (a = 0; a < tot; a++) { - glVertex2iv(mcords[a]); - } - glEnd(); - - glFinish(); /* to be sure readpixels sees mask */ - - if (vc->rv3d->gpuoffscreen) - GPU_offscreen_unbind(vc->rv3d->gpuoffscreen); - - /* grab mask */ - bufmask = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); + dr_mask = dr_mask_arr = MEM_callocN(sizeof(*dr_mask) * buf->x * buf->y, __func__); + lasso_mask_data.px = dr_mask; + lasso_mask_data.width = (xmax - xmin) + 1; - if (bufmask == NULL) { - return false; /* only when mem alloc fails, go crash somewhere else! */ - } - else { - drm = bufmask->rect; - } + fill_poly_v2i_n( + xmin, ymin, xmax + 1, ymax + 1, + mcords, tot, + edbm_mask_lasso_px_cb, &lasso_mask_data); /* build selection lookup */ selbuf = MEM_callocN(bm_vertoffs + 1, "selbuf"); a = (xmax - xmin + 1) * (ymax - ymin + 1); while (a--) { - if (*dr > 0 && *dr <= bm_vertoffs && *drm == 0) selbuf[*dr] = 1; - dr++; drm++; + if (*dr > 0 && *dr <= bm_vertoffs && *dr_mask == true) selbuf[*dr] = 1; + dr++; dr_mask++; } IMB_freeImBuf(buf); - IMB_freeImBuf(bufmask); + MEM_freeN(dr_mask_arr); return true; } @@ -1233,7 +1180,7 @@ static void mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de /* We can't be sure this has already been set... */ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); - BM_ITER_ELEM(f, &iterf, eed, BM_FACES_OF_EDGE) { + BM_ITER_ELEM (f, &iterf, eed, BM_FACES_OF_EDGE) { if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { float cent[3]; float co[2], tdist; @@ -2509,7 +2456,7 @@ static int edbm_select_nth_exec(bContext *C, wmOperator *op) int offset = RNA_int_get(op->ptr, "offset"); /* so input of offset zero ends up being (nth - 1) */ - offset = (offset + (nth - 1)) % nth; + offset = mod_i(offset, nth); if (edbm_deselect_nth(em, nth, offset) == false) { BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face"); @@ -2537,7 +2484,7 @@ void MESH_OT_select_nth(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100); - RNA_def_int(ot->srna, "offset", 0, 0, INT_MAX, "Offset", "", 0, 100); + RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100); } void em_setup_viewcontext(bContext *C, ViewContext *vc) @@ -2609,8 +2556,7 @@ static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; - BMFace **stack = MEM_mallocN(sizeof(BMFace *) * bm->totface, __func__); - STACK_DECLARE(stack); + BLI_LINKSTACK_DECLARE(stack, BMFace *); BMIter iter, liter, liter2; BMFace *f; @@ -2619,6 +2565,7 @@ static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); + BLI_LINKSTACK_INIT(stack); BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) || @@ -2628,7 +2575,7 @@ static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) continue; } - STACK_INIT(stack); + BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0); do { BM_face_select_set(bm, f, true); @@ -2648,16 +2595,14 @@ static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) angle = angle_normalized_v3v3(f->no, l2->f->no); if (angle < angle_limit) { - STACK_PUSH(stack, l2->f); + BLI_LINKSTACK_PUSH(stack, l2->f); } } } - } while ((f = STACK_POP(stack))); + } while ((f = BLI_LINKSTACK_POP(stack))); } - STACK_FREE(stack); - - MEM_freeN(stack); + BLI_LINKSTACK_FREE(stack); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 4610bb89ae4..9e5782c12f2 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -29,6 +29,8 @@ * \ingroup edmesh */ +#include <stddef.h> + #include "MEM_guardedalloc.h" #include "DNA_key_types.h" @@ -43,6 +45,7 @@ #include "BLI_noise.h" #include "BLI_math.h" #include "BLI_rand.h" +#include "BLI_sort_utils.h" #include "BKE_material.h" #include "BKE_context.h" @@ -892,14 +895,30 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em->bm; BMOperator bmop; + ListBase bm_selected_store = {NULL, NULL}; + + /* de-select all would clear otherwise */ + SWAP(ListBase, bm->selected, bm_selected_store); EDBM_op_init(em, &bmop, op, "duplicate geom=%hvef", BM_ELEM_SELECT); - BMO_op_exec(em->bm, &bmop); + BMO_op_exec(bm, &bmop); EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + + /* rebuild editselection */ + bm->selected = bm_selected_store; + + if (bm->selected.first) { + BMOpSlot *slot_vert_map_out = BMO_slot_get(bmop.slots_out, "vert_map.out"); + BMOpSlot *slot_edge_map_out = BMO_slot_get(bmop.slots_out, "edge_map.out"); + BMOpSlot *slot_face_map_out = BMO_slot_get(bmop.slots_out, "face_map.out"); + + BMO_mesh_selected_remap(bm, slot_vert_map_out, slot_edge_map_out, slot_face_map_out); + } if (!EDBM_op_finish(em, &bmop, op, true)) { return OPERATOR_CANCELLED; @@ -964,12 +983,6 @@ void MESH_OT_flip_normals(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static const EnumPropertyItem direction_items[] = { - {false, "CW", 0, "Clockwise", ""}, - {true, "CCW", 0, "Counter Clockwise", ""}, - {0, NULL, 0, NULL, NULL} -}; - /* only accepts 1 selected edge, or 2 selected faces */ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op) { @@ -2292,7 +2305,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) mouse_path = MEM_mallocN(len * sizeof(*mouse_path), __func__); /* get the cut curve */ - RNA_BEGIN(op->ptr, itemptr, "path") + RNA_BEGIN (op->ptr, itemptr, "path") { RNA_float_get_array(&itemptr, "loc", (float *)&mouse_path[len]); } @@ -2399,7 +2412,7 @@ void MESH_OT_knife_cut(wmOperatorType *ot) RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX); } -static int mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) +static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) { Base *base_new; Object *obedit = base_old->object; @@ -2441,7 +2454,7 @@ static int mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh BM_mesh_free(bm_new); ((Mesh *)base_new->object->data)->edit_btmesh = NULL; - return true; + return base_new; } static bool mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) @@ -2452,7 +2465,7 @@ static bool mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BM /* sel -> tag */ BM_mesh_elem_hflag_enable_test(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, true, BM_ELEM_SELECT); - return mesh_separate_tagged(bmain, scene, base_old, bm_old); + return (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL); } /* flush a hflag to from verts to edges/faces */ @@ -2492,6 +2505,63 @@ static void bm_mesh_hflag_flush_vert(BMesh *bm, const char hflag) } } +/** + * Sets an object to a single material. from one of its slots. + * + * \note This could be used for split-by-material for non mesh types. + * \note This could take material data from another object or args. + */ +static void mesh_separate_material_assign_mat_nr(Object *ob, const short mat_nr) +{ + ID *obdata = ob->data; + + Material ***matarar; + short *totcolp; + + totcolp = give_totcolp_id(obdata); + matarar = give_matarar_id(obdata); + + if ((totcolp && matarar) == 0) { + BLI_assert(0); + return; + } + + if (*totcolp) { + Material *ma_ob; + Material *ma_obdata; + char matbit; + + if (mat_nr < ob->totcol) { + ma_ob = ob->mat[mat_nr]; + matbit = ob->matbits[mat_nr]; + } + else { + ma_ob = NULL; + matbit = 0; + } + + if (mat_nr < *totcolp) { + ma_obdata = (*matarar)[mat_nr]; + } + else { + ma_obdata = NULL; + } + + BKE_material_clear_id(obdata, true); + BKE_material_resize_object(ob, 1, true); + BKE_material_resize_id(obdata, 1, true); + + ob->mat[0] = ma_ob; + ob->matbits[0] = matbit; + (*matarar)[0] = ma_obdata; + } + else { + BKE_material_clear_id(obdata, true); + BKE_material_resize_object(ob, 0, true); + BKE_material_resize_id(obdata, 0, true); + } +} + static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old) { BMFace *f_cmp, *f; @@ -2499,6 +2569,7 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM bool result = false; while ((f_cmp = BM_iter_at_index(bm_old, BM_FACES_OF_MESH, NULL, 0))) { + Base *base_new; const short mat_nr = f_cmp->mat_nr; int tot = 0; @@ -2522,11 +2593,22 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM /* leave the current object with some materials */ if (tot == bm_old->totface) { + mesh_separate_material_assign_mat_nr(base_old->object, mat_nr); + + /* since we're in editmode, must set faces here */ + BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) { + f->mat_nr = 0; + } break; } /* Move selection into a separate object */ - result |= mesh_separate_tagged(bmain, scene, base_old, bm_old); + base_new = mesh_separate_tagged(bmain, scene, base_old, bm_old); + if (base_new) { + mesh_separate_material_assign_mat_nr(base_new->object, mat_nr); + } + + result |= (base_new != NULL); } return result; @@ -2585,7 +2667,7 @@ static bool mesh_separate_loose(Main *bmain, Scene *scene, Base *base_old, BMesh bm_mesh_hflag_flush_vert(bm_old, BM_ELEM_TAG); /* Move selection into a separate object */ - result |= mesh_separate_tagged(bmain, scene, base_old, bm_old); + result |= (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL); } return result; @@ -2747,6 +2829,146 @@ void MESH_OT_fill(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_beauty", true, "Beauty", "Use best triangulation division"); } + +/* -------------------------------------------------------------------- */ +/* Grid Fill (and helper functions) */ + +static bool bm_edge_test_fill_grid_cb(BMEdge *e, void *UNUSED(bm_v)) +{ + return BM_elem_flag_test_bool(e, BM_ELEM_TAG); +} + +static float edbm_fill_grid_vert_tag_angle(BMVert *v) +{ + BMIter iter; + BMEdge *e_iter; + BMVert *v_pair[2]; + int i = 0; + BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e_iter, BM_ELEM_TAG)) { + v_pair[i++] = BM_edge_other_vert(e_iter, v); + } + } + BLI_assert(i == 2); + + return fabsf((float)M_PI - angle_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co)); +} + +/** + * non-essential utility function to select 2 open edge loops from a closed loop. + */ +static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span_calc) +{ + BMEdge *e; + BMIter iter; + int count; + int span = *r_span; + + ListBase eloops = {NULL}; + struct BMEdgeLoopStore *el_store; + // LinkData *el_store; + + /* select -> tag */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); + } + + count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_fill_grid_cb, bm); + el_store = eloops.first; + + if (count == 1 && BM_edgeloop_is_closed(el_store) && (BM_edgeloop_length_get(el_store) & 1) == 0) { + /* be clever! detect 2 edge loops from one closed edge loop */ + const int verts_len = BM_edgeloop_length_get(el_store); + ListBase *verts = BM_edgeloop_verts_get(el_store); + BMVert *v_act = BM_mesh_active_vert_get(bm); + LinkData *v_act_link; + BMEdge **edges = MEM_mallocN(sizeof(*edges) * verts_len, __func__); + int i; + + if (v_act && (v_act_link = BLI_findptr(verts, v_act, offsetof(LinkData, data)))) { + /* pass */ + } + else { + /* find the vertex with the best angle (a corner vertex) */ + LinkData *v_link, *v_link_best = NULL; + float angle_best = -1.0f; + for (v_link = verts->first; v_link; v_link = v_link->next) { + const float angle = edbm_fill_grid_vert_tag_angle(v_link->data); + if ((angle > angle_best) || (v_link_best == NULL)) { + angle_best = angle; + v_link_best = v_link; + } + } + + v_act_link = v_link_best; + v_act = v_act_link->data; + } + + if (offset != 0) { + v_act_link = BLI_findlink(verts, offset); + v_act = v_act_link->data; + } + + /* set this vertex first */ + BLI_rotatelist_first(verts, v_act_link); + BM_edgeloop_edges_get(el_store, edges); + + + if (span_calc) { + /* calculate the span by finding the next corner in 'verts' + * we dont know what defines a corner exactly so find the 4 verts + * in the loop with the greatest angle. + * Tag them and use the first tagged vertex to calculate the span. + * + * note: we may have already checked 'edbm_fill_grid_vert_tag_angle()' on each + * vert, but advantage of de-duplicating is minimal. */ + struct SortPointerByFloat *ele_sort = MEM_mallocN(sizeof(*ele_sort) * verts_len, __func__); + LinkData *v_link; + for (v_link = verts->first, i = 0; v_link; v_link = v_link->next, i++) { + BMVert *v = v_link->data; + const float angle = edbm_fill_grid_vert_tag_angle(v); + ele_sort[i].sort_value = angle; + ele_sort[i].data = v; + + BM_elem_flag_disable(v, BM_ELEM_TAG); + } + + qsort(ele_sort, verts_len, sizeof(*ele_sort), BLI_sortutil_cmp_float_reverse); + + for (i = 0; i < 4; i++) { + BMVert *v = ele_sort[i].data; + BM_elem_flag_enable(v, BM_ELEM_TAG); + } + + /* now find the first... */ + for (v_link = verts->first, i = 0; i < verts_len / 2; v_link = v_link->next, i++) { + BMVert *v = v_link->data; + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + if (v != v_act) { + span = i; + break; + } + } + } + MEM_freeN(ele_sort); + } + /* end span calc */ + + + /* un-flag 'rails' */ + for (i = 0; i < span; i++) { + BM_elem_flag_disable(edges[i], BM_ELEM_TAG); + BM_elem_flag_disable(edges[(verts_len / 2) + i], BM_ELEM_TAG); + } + MEM_freeN(edges); + } + /* else let the bmesh-operator handle it */ + + BM_mesh_edgeloops_free(&eloops); + + *r_span = span; +} + static int edbm_fill_grid_exec(bContext *C, wmOperator *op) { BMOperator bmop; @@ -2755,10 +2977,45 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op) const short use_smooth = edbm_add_edge_face__smooth_get(em->bm); const int totedge_orig = em->bm->totedge; const int totface_orig = em->bm->totface; + const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple"); + const bool use_prepare = true; + + + if (use_prepare) { + /* use when we have a single loop selected */ + PropertyRNA *prop_span = RNA_struct_find_property(op->ptr, "span"); + PropertyRNA *prop_offset = RNA_struct_find_property(op->ptr, "offset"); + bool calc_span; + + const int clamp = em->bm->totvertsel; + int span; + int offset; + + if (RNA_property_is_set(op->ptr, prop_span)) { + span = RNA_property_int_get(op->ptr, prop_span); + span = min_ii(span, (clamp / 2) - 1); + calc_span = false; + } + else { + span = clamp / 4; + calc_span = true; + } + + offset = RNA_property_int_get(op->ptr, prop_offset); + offset = clamp ? mod_i(offset, clamp) : 0; + + /* in simple cases, move selection for tags, but also support more advanced cases */ + edbm_fill_grid_prepare(em->bm, offset, &span, calc_span); + + RNA_property_int_set(op->ptr, prop_span, span); + } + /* end tricky prepare code */ + if (!EDBM_op_init(em, &bmop, op, - "grid_fill edges=%he mat_nr=%i use_smooth=%b", - BM_ELEM_SELECT, em->mat_nr, use_smooth)) + "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b", + use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT, + em->mat_nr, use_smooth, use_interp_simple)) { return OPERATOR_CANCELLED; } @@ -2786,6 +3043,8 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op) void MESH_OT_fill_grid(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Grid Fill"; ot->description = "Fill grid from two loops"; @@ -2797,6 +3056,13 @@ void MESH_OT_fill_grid(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_int(ot->srna, "span", 1, 1, INT_MAX, "Span", "Number of sides (zero disables)", 1, 100); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "Number of sides (zero disables)", -100, 100); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + RNA_def_boolean(ot->srna, "use_interp_simple", 0, "Simple Blending", ""); } static int edbm_fill_holes_exec(bContext *C, wmOperator *op) @@ -3070,7 +3336,7 @@ void MESH_OT_dissolve_verts(wmOperatorType *ot) { /* identifiers */ ot->name = "Dissolve Vertices"; - ot->description = "Dissolve geometry"; + ot->description = "Dissolve verts, merge edges and faces"; ot->idname = "MESH_OT_dissolve_verts"; /* api callbacks */ @@ -3107,7 +3373,7 @@ void MESH_OT_dissolve_edges(wmOperatorType *ot) { /* identifiers */ ot->name = "Dissolve Edges"; - ot->description = "Dissolve geometry"; + ot->description = "Dissolve edges, merging faces"; ot->idname = "MESH_OT_dissolve_edges"; /* api callbacks */ @@ -3146,7 +3412,7 @@ void MESH_OT_dissolve_faces(wmOperatorType *ot) { /* identifiers */ ot->name = "Dissolve Faces"; - ot->description = "Dissolve geometry"; + ot->description = "Dissolve faces"; ot->idname = "MESH_OT_dissolve_faces"; /* api callbacks */ @@ -4247,7 +4513,7 @@ void MESH_OT_wireframe(wmOperatorType *ot) /* identifiers */ ot->name = "Wire Frame"; ot->idname = "MESH_OT_wireframe"; - ot->description = "Inset new faces into selected faces"; + ot->description = "Create a solid wire-frame from faces"; /* api callbacks */ ot->exec = edbm_wireframe_exec; @@ -4289,7 +4555,8 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true); + /* Delete unused vertices, edges, and faces */ if (RNA_boolean_get(op->ptr, "delete_unused")) { if (!EDBM_op_callf(em, op, "delete geom=%S context=%i", @@ -4312,9 +4579,11 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op) /* Merge adjacent triangles */ if (RNA_boolean_get(op->ptr, "join_triangles")) { - if (!EDBM_op_callf(em, op, "join_triangles faces=%S limit=%f", - &bmop, "geom.out", - RNA_float_get(op->ptr, "limit"))) + if (!EDBM_op_call_and_selectf(em, op, + "faces.out", true, + "join_triangles faces=%S limit=%f", + &bmop, "geom.out", + RNA_float_get(op->ptr, "limit"))) { EDBM_op_finish(em, &bmop, op, true); return OPERATOR_CANCELLED; @@ -4372,10 +4641,17 @@ static int mesh_symmetrize_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); BMOperator bmop; - EDBM_op_init(em, &bmop, op, "symmetrize input=%hvef direction=%i", - BM_ELEM_SELECT, RNA_enum_get(op->ptr, "direction")); + const float thresh = RNA_float_get(op->ptr, "threshold"); + + EDBM_op_init(em, &bmop, op, + "symmetrize input=%hvef direction=%i dist=%f", + BM_ELEM_SELECT, RNA_enum_get(op->ptr, "direction"), thresh); BMO_op_exec(em->bm, &bmop); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + if (!EDBM_op_finish(em, &bmop, op, true)) { return OPERATOR_CANCELLED; } @@ -4403,6 +4679,7 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items, BMO_SYMMETRIZE_NEGATIVE_X, "Direction", "Which sides to copy from and to"); + RNA_def_float(ot->srna, "threshold", 0.0001, 0.0, 10.0, "Threshold", "", 0.00001, 0.1); } static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 46cab3b4416..e457f7c45af 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -662,10 +662,7 @@ static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *UNUSED(obdata)) UndoMesh *um = umv; BMesh *bm; - const BMAllocTemplate allocsize = {um->me.totvert, - um->me.totedge, - um->me.totloop, - um->me.totpoly}; + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me); ob->shapenr = em->bm->shapenr = um->shapenr; @@ -1481,7 +1478,7 @@ int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d) static BMFace *edge_ray_cast(struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e) { - BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, NULL, r_hitout, NULL); + BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, NULL, r_hitout, NULL); if (f && BM_edge_in_face(e, f)) return NULL; diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 9dcb38b9f87..287938c4002 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -95,6 +95,8 @@ void MESH_OT_primitive_ico_sphere_add(struct wmOperatorType *ot); /* *** editmesh_bevel.c *** */ void MESH_OT_bevel(struct wmOperatorType *ot); +/* *** editmesh_bisect.c *** */ +void MESH_OT_bisect(struct wmOperatorType *ot); /* *** editmesh_extrude.c *** */ void MESH_OT_extrude_repeat(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index 66e577975b6..83feed6756f 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -26,6 +26,10 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/editors/mesh/mesh_navmesh.c + * \ingroup edmesh + */ + #include "MEM_guardedalloc.h" #include "DNA_scene_types.h" @@ -350,7 +354,7 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, co[1] = bmin[1] + v[1] * ch; co[2] = bmin[2] + v[2] * cs; SWAP(float, co[1], co[2]); - BM_vert_create(em->bm, co, NULL, 0); + BM_vert_create(em->bm, co, NULL, BM_CREATE_NOP); } /* create custom data layer to save polygon idx */ @@ -381,7 +385,7 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, for (j = nv; j < ndv; j++) { copy_v3_v3(co, &dverts[3 * (vbase + j)]); SWAP(float, co[1], co[2]); - BM_vert_create(em->bm, co, NULL, 0); + BM_vert_create(em->bm, co, NULL, BM_CREATE_NOP); } /* need to rebuild entirely because array size changes */ diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index fb0ec4e5768..64ce040c729 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -176,6 +176,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_convex_hull); #endif + WM_operatortype_append(MESH_OT_bisect); WM_operatortype_append(MESH_OT_symmetrize); WM_operatortype_append(MESH_OT_symmetry_snap); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index d012a8ac656..5ee980ef5cb 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -178,7 +178,6 @@ int join_mesh_exec(bContext *C, wmOperator *op) if (kb->data) MEM_freeN(kb->data); kb->data = MEM_callocN(sizeof(float) * 3 * totvert, "join_shapekey"); kb->totelem = totvert; - kb->weights = NULL; } } else if (haskey) { @@ -315,7 +314,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) /* standard data */ CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert); - CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert); + CustomData_copy_data_named(&me->vdata, &vdata, 0, vertofs, me->totvert); /* vertex groups */ dvert = CustomData_get(&vdata, vertofs, CD_MDEFORMVERT); @@ -416,7 +415,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) if (me->totedge) { CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge); - CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge); + CustomData_copy_data_named(&me->edata, &edata, 0, edgeofs, me->totedge); for (a = 0; a < me->totedge; a++, medge++) { medge->v1 += vertofs; @@ -438,7 +437,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) } CustomData_merge(&me->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloop); - CustomData_copy_data(&me->ldata, &ldata, 0, loopofs, me->totloop); + CustomData_copy_data_named(&me->ldata, &ldata, 0, loopofs, me->totloop); for (a = 0; a < me->totloop; a++, mloop++) { mloop->v += vertofs; @@ -462,7 +461,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) } CustomData_merge(&me->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpoly); - CustomData_copy_data(&me->pdata, &pdata, 0, polyofs, me->totpoly); + CustomData_copy_data_named(&me->pdata, &pdata, 0, polyofs, me->totpoly); for (a = 0; a < me->totpoly; a++, mpoly++) { mpoly->loopstart += loopofs; @@ -1012,6 +1011,31 @@ BMVert *editbmesh_get_x_mirror_vert(Object *ob, struct BMEditMesh *em, BMVert *e } } +/** + * Wrapper for objectmode/editmode. + * + * call #EDBM_index_arrays_ensure first for editmesh. + */ +int ED_mesh_mirror_get_vert(Object *ob, int index) +{ + Mesh *me = ob->data; + BMEditMesh *em = me->edit_btmesh; + bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; + int index_mirr; + + if (em) { + BMVert *eve, *eve_mirr; + eve = EDBM_vert_at_index(em, index); + eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, index, use_topology); + index_mirr = eve_mirr ? BM_elem_index_get(eve_mirr) : -1; + } + else { + index_mirr = mesh_get_x_mirror_vert(ob, index, use_topology); + } + + return index_mirr; +} + #if 0 static float *editmesh_get_mirror_uv(BMEditMesh *em, int axis, float *uv, float *mirrCent, float *face_cent) @@ -1136,7 +1160,7 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em) mesh_octree_table(ob, em, NULL, 'e'); - fhash = BLI_ghash_new(mirror_facehash, mirror_facecmp, "mirror_facehash gh"); + fhash = BLI_ghash_new_ex(mirror_facehash, mirror_facecmp, "mirror_facehash gh", me->totface); for (a = 0, mf = mface; a < me->totface; a++, mf++) BLI_ghash_insert(fhash, mf, mf); diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index de0af1d1bb8..68ca55651a8 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -98,7 +98,7 @@ void load_editMball(Object *UNUSED(obedit)) } /* Add metaelem primitive to metaball object (which is in edit mode) */ -MetaElem *add_metaball_primitive(bContext *UNUSED(C), Object *obedit, float mat[4][4], float dia, int type, int UNUSED(newname)) +MetaElem *add_metaball_primitive(bContext *UNUSED(C), Object *obedit, float mat[4][4], float dia, int type) { MetaBall *mball = (MetaBall *)obedit->data; MetaElem *ml; @@ -112,6 +112,8 @@ MetaElem *add_metaball_primitive(bContext *UNUSED(C), Object *obedit, float mat[ ml = BKE_mball_element_add(mball, type); ml->rad *= dia; + mball->wiresize *= dia; + mball->rendersize *= dia; copy_v3_v3(&ml->x, mat[3]); ml->flag |= SELECT; @@ -499,19 +501,13 @@ bool mouse_mball(bContext *C, const int mval[2], bool extend, bool deselect, boo /* free all MetaElems from ListBase */ static void freeMetaElemlist(ListBase *lb) { - MetaElem *ml, *next; + MetaElem *ml; if (lb == NULL) return; - ml = lb->first; - while (ml) { - next = ml->next; - BLI_remlink(lb, ml); + while ((ml = BLI_pophead(lb))) { MEM_freeN(ml); - ml = next; } - - lb->first = lb->last = NULL; } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index ce61b4fce50..db68a0eca4d 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -191,7 +191,7 @@ void ED_object_base_init_transform(bContext *C, Base *base, const float loc[3], * Returns standard diameter. */ float ED_object_new_primitive_matrix(bContext *C, Object *obedit, const float loc[3], const float rot[3], float primmat[4][4], - int apply_diameter) + bool apply_diameter) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -236,7 +236,15 @@ static void view_align_update(struct Main *UNUSED(main), struct Scene *UNUSED(sc RNA_struct_idprops_unset(ptr, "rotation"); } -void ED_object_add_generic_props(wmOperatorType *ot, int do_editmode) +void ED_object_add_unit_props(wmOperatorType *ot) +{ + PropertyRNA *prop; + + prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00); + RNA_def_property_subtype(prop, PROP_DISTANCE); +} + +void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode) { PropertyRNA *prop; @@ -261,8 +269,8 @@ void ED_object_add_generic_props(wmOperatorType *ot, int do_editmode) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } -int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float loc[3], float rot[3], - bool *enter_editmode, unsigned int *layer, bool *is_view_aligned) +bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float loc[3], float rot[3], + bool *enter_editmode, unsigned int *layer, bool *is_view_aligned) { View3D *v3d = CTX_wm_view3d(C); unsigned int _layer; @@ -356,16 +364,16 @@ int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float loc[3], fl if (layer && *layer == 0) { BKE_report(op->reports, RPT_ERROR, "Property 'layer' has no values set"); - return 0; + return false; } - return 1; + return true; } /* For object add primitive operators. * Do not call undo push in this function (users of this function have to). */ Object *ED_object_add_type(bContext *C, int type, const float loc[3], const float rot[3], - int enter_editmode, unsigned int layer) + bool enter_editmode, unsigned int layer) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -570,6 +578,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op) float mat[4][4]; float dia; + WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; @@ -577,12 +586,14 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op) obedit = ED_object_add_type(C, OB_MBALL, loc, rot, TRUE, layer); newob = true; } - else + else { DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + } - dia = ED_object_new_primitive_matrix(C, obedit, loc, rot, mat, FALSE); + ED_object_new_primitive_matrix(C, obedit, loc, rot, mat, false); + dia = RNA_float_get(op->ptr, "radius"); - add_metaball_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type"), newob); + add_metaball_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type")); /* userdef */ if (newob && !enter_editmode) { @@ -602,7 +613,7 @@ void OBJECT_OT_metaball_add(wmOperatorType *ot) ot->idname = "OBJECT_OT_metaball_add"; /* api callbacks */ - ot->invoke = WM_menu_invoke;/* object_metaball_add_invoke; */ + ot->invoke = WM_menu_invoke; ot->exec = object_metaball_add_exec; ot->poll = ED_operator_scene_editable; @@ -611,6 +622,7 @@ void OBJECT_OT_metaball_add(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", metaelem_type_items, 0, "Primitive", ""); + ED_object_add_unit_props(ot); ED_object_add_generic_props(ot, TRUE); } @@ -1243,7 +1255,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, ob->parent = NULL; ob->constraints.first = ob->constraints.last = NULL; - ob->disp.first = ob->disp.last = NULL; + ob->curve_cache = NULL; ob->transflag &= ~OB_DUPLI; ob->lay = base->lay; @@ -1385,7 +1397,7 @@ static EnumPropertyItem convert_target_items[] = { static void curvetomesh(Scene *scene, Object *ob) { - if (ob->disp.first == NULL) + if (ELEM(NULL, ob->curve_cache, ob->curve_cache->disp.first)) BKE_displist_make_curveTypes(scene, ob, 0); /* force creation */ BKE_mesh_from_nurbs(ob); /* also does users */ @@ -1553,7 +1565,7 @@ static int convert_exec(bContext *C, wmOperator *op) cu = newob->data; - if (!newob->disp.first) + if ( !newob->curve_cache || !newob->curve_cache->disp.first) BKE_displist_make_curveTypes(scene, newob, 0); newob->type = OB_CURVE; @@ -1595,7 +1607,7 @@ static int convert_exec(bContext *C, wmOperator *op) curvetomesh(scene, newob); /* meshes doesn't use displist */ - BKE_displist_free(&newob->disp); + BKE_object_free_curve_cache(newob); } } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { @@ -1616,7 +1628,7 @@ static int convert_exec(bContext *C, wmOperator *op) newob = ob; /* meshes doesn't use displist */ - BKE_displist_free(&newob->disp); + BKE_object_free_curve_cache(newob); } curvetomesh(scene, newob); @@ -1635,7 +1647,7 @@ static int convert_exec(bContext *C, wmOperator *op) ob->flag |= OB_DONE; } - if (!baseob->disp.first) { + if (!baseob->curve_cache || !baseob->curve_cache->disp.first) { BKE_displist_make_mball(scene, baseob); } @@ -1658,7 +1670,7 @@ static int convert_exec(bContext *C, wmOperator *op) for (a = 0; a < newob->totcol; a++) id_us_plus((ID *)me->mat[a]); } - BKE_mesh_from_metaball(&baseob->disp, newob->data); + BKE_mesh_from_metaball(&baseob->curve_cache->disp, newob->data); if (obact->type == OB_MBALL) { basact = basen; diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 8b674cf1e50..376f2ed294b 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -264,40 +264,68 @@ static DerivedMesh *multiresbake_create_hiresdm(Scene *scene, Object *ob, int *l } typedef enum ClearFlag { - CLEAR_NORMAL = 1 + CLEAR_TANGENT_NORMAL = 1, + CLEAR_DISPLACEMENT = 2 } ClearFlag; -static void clear_images(MTFace *mtface, int totface, ClearFlag flag) +static void clear_single_image(Image *image, ClearFlag flag) { - int a; const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f}; const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f}; const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f}; const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f}; + const float disp_alpha[4] = {0.5f, 0.5f, 0.5f, 0.0f}; + const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + + if ((image->id.flag & LIB_DOIT) == 0) { + ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); + + if (flag == CLEAR_TANGENT_NORMAL) + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid); + else if (flag == CLEAR_DISPLACEMENT) + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid); + else + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid); + + image->id.flag |= LIB_DOIT; - for (a = 0; a < totface; a++) + BKE_image_release_ibuf(image, ibuf, NULL); + } +} + +static void clear_images(MTFace *mtface, int totface, ClearFlag flag) +{ + int a; + + for (a = 0; a < totface; a++) { mtface[a].tpage->id.flag &= ~LIB_DOIT; + } for (a = 0; a < totface; a++) { - Image *ima = mtface[a].tpage; + clear_single_image(mtface[a].tpage, flag); + } - if ((ima->id.flag & LIB_DOIT) == 0) { - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + for (a = 0; a < totface; a++) { + mtface[a].tpage->id.flag &= ~LIB_DOIT; + } +} - if (flag == CLEAR_NORMAL) - IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid); - else - IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid); +static void clear_images_poly(MTexPoly *mtpoly, int totpoly, ClearFlag flag) +{ + int a; - ima->id.flag |= LIB_DOIT; + for (a = 0; a < totpoly; a++) { + mtpoly[a].tpage->id.flag &= ~LIB_DOIT; + } - BKE_image_release_ibuf(ima, ibuf, NULL); - } + for (a = 0; a < totpoly; a++) { + clear_single_image(mtpoly[a].tpage, flag); } - for (a = 0; a < totface; a++) - mtface[a].tpage->id.flag &= ~LIB_DOIT; + for (a = 0; a < totpoly; a++) { + mtpoly[a].tpage->id.flag &= ~LIB_DOIT; + } } static int multiresbake_image_exec_locked(bContext *C, wmOperator *op) @@ -313,14 +341,20 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { Mesh *me; + ClearFlag clear_flag = 0; ob = base->object; me = (Mesh *)ob->data; - if (scene->r.bake_mode == RE_BAKE_NORMALS && scene->r.bake_normal_space == R_BAKE_SPACE_TANGENT) - clear_images(me->mtface, me->totface, CLEAR_NORMAL); - else - clear_images(me->mtface, me->totface, 0); + if (scene->r.bake_mode == RE_BAKE_NORMALS) { + clear_flag = CLEAR_TANGENT_NORMAL; + } + else if (scene->r.bake_mode == RE_BAKE_DISPLACEMENT) { + clear_flag = CLEAR_DISPLACEMENT; + } + + clear_images(me->mtface, me->totface, clear_flag); + clear_images_poly(me->mtpoly, me->totpoly, clear_flag); } CTX_DATA_END; } @@ -414,11 +448,16 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa for (data = bkj->data.first; data; data = data->next) { DerivedMesh *dm = data->lores_dm; MTFace *mtface = CustomData_get_layer(&dm->faceData, CD_MTFACE); + ClearFlag clear_flag = 0; + + if (bkj->mode == RE_BAKE_NORMALS) { + clear_flag = CLEAR_TANGENT_NORMAL; + } + else if (bkj->mode == RE_BAKE_DISPLACEMENT) { + clear_flag = CLEAR_DISPLACEMENT; + } - if (bkj->mode == RE_BAKE_NORMALS) - clear_images(mtface, dm->getNumTessFaces(dm), CLEAR_NORMAL); - else - clear_images(mtface, dm->getNumTessFaces(dm), 0); + clear_images(mtface, dm->getNumTessFaces(dm), clear_flag); } } diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 7f7a0777bbf..bd4c2e997fe 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -79,6 +79,7 @@ #include "BKE_softbody.h" #include "BKE_modifier.h" #include "BKE_editmesh.h" +#include "BKE_report.h" #include "ED_armature.h" #include "ED_curve.h" @@ -556,11 +557,20 @@ void ED_object_editmode_enter(bContext *C, int flag) if (flag & EM_WAITCURSOR) waitcursor(0); } -static int editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) +static int editmode_toggle_exec(bContext *C, wmOperator *op) { + const int mode_flag = OB_MODE_EDIT; + const bool is_mode_set = (CTX_data_edit_object(C) != NULL); ToolSettings *toolsettings = CTX_data_tool_settings(C); - if (!CTX_data_edit_object(C)) + if (!is_mode_set) { + Scene *scene = CTX_data_scene(C); + if (!ED_object_mode_compat_set(C, scene->basact->object, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } + } + + if (!is_mode_set) ED_object_editmode_enter(C, EM_WAITCURSOR); else ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */ @@ -582,10 +592,7 @@ static int editmode_toggle_poll(bContext *C) if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)) return 0; - return (ob->type == OB_MESH || ob->type == OB_ARMATURE || - ob->type == OB_FONT || ob->type == OB_MBALL || - ob->type == OB_LATTICE || ob->type == OB_SURF || - ob->type == OB_CURVE); + return (ELEM7(ob->type, OB_MESH, OB_ARMATURE, OB_FONT, OB_MBALL, OB_LATTICE, OB_SURF, OB_CURVE)); } void OBJECT_OT_editmode_toggle(wmOperatorType *ot) @@ -598,7 +605,6 @@ void OBJECT_OT_editmode_toggle(wmOperatorType *ot) /* api callbacks */ ot->exec = editmode_toggle_exec; - ot->poll = editmode_toggle_poll; /* flags */ @@ -607,16 +613,25 @@ void OBJECT_OT_editmode_toggle(wmOperatorType *ot) /* *************************** */ -static int posemode_exec(bContext *C, wmOperator *UNUSED(op)) +static int posemode_exec(bContext *C, wmOperator *op) { Base *base = CTX_data_active_base(C); + Object *ob = base->object; + const int mode_flag = OB_MODE_POSE; + const bool is_mode_set = (ob->mode & mode_flag) != 0; - if (base->object->type == OB_ARMATURE) { - if (base->object == CTX_data_edit_object(C)) { + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } + } + + if (ob->type == OB_ARMATURE) { + if (ob == CTX_data_edit_object(C)) { ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO); ED_armature_enter_posemode(C, base); } - else if (base->object->mode & OB_MODE_POSE) + else if (is_mode_set) ED_armature_exit_posemode(C, base); else ED_armature_enter_posemode(C, base); @@ -1417,8 +1432,9 @@ static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d) space = size[0] / size[1]; } else if (ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { - Curve *cu = ob->data; - space = cu->size[0] / cu->size[1]; + float size[3]; + BKE_curve_texspace_get(ob->data, NULL, NULL, size); + space = size[0] / size[1]; } x = ibuf->x / space; @@ -1455,12 +1471,14 @@ static EnumPropertyItem *object_mode_set_itemsf(bContext *C, PointerRNA *UNUSED( ob = CTX_data_active_object(C); if (ob) { + const bool use_mode_particle_edit = (ob->particlesystem.first != NULL) || (ob->soft != NULL) || + (modifiers_findByType(ob, eModifierType_Cloth) != NULL); while (input->identifier) { if ((input->value == OB_MODE_EDIT && OB_TYPE_SUPPORT_EDITMODE(ob->type)) || (input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) || - (input->value == OB_MODE_PARTICLE_EDIT && ob->particlesystem.first) || - ((input->value == OB_MODE_SCULPT || input->value == OB_MODE_VERTEX_PAINT || - input->value == OB_MODE_WEIGHT_PAINT || input->value == OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) || + (input->value == OB_MODE_PARTICLE_EDIT && use_mode_particle_edit) || + (ELEM4(input->value, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, + OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) || (input->value == OB_MODE_OBJECT)) { RNA_enum_item_add(&item, &totitem, input); @@ -1500,19 +1518,21 @@ static const char *object_mode_op_string(int mode) } /* checks the mode to be set is compatible with the object - * should be made into a generic function */ -static bool object_mode_set_compat(bContext *UNUSED(C), wmOperator *op, Object *ob) + * should be made into a generic function + */ +static bool object_mode_compat_test(Object *ob, ObjectMode mode) { - ObjectMode mode = RNA_enum_get(op->ptr, "mode"); - if (ob) { if (mode == OB_MODE_OBJECT) return true; switch (ob->type) { case OB_MESH: - if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT | OB_MODE_PARTICLE_EDIT)) + if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | + OB_MODE_TEXTURE_PAINT | OB_MODE_PARTICLE_EDIT)) + { return true; + } break; case OB_CURVE: case OB_SURF: @@ -1535,6 +1555,30 @@ static bool object_mode_set_compat(bContext *UNUSED(C), wmOperator *op, Object * return false; } +/** + * Sets the mode to a compatible state (use before entering the mode). + * + * This is so each mode's exec function can call + */ +bool ED_object_mode_compat_set(bContext *C, Object *ob, int mode, ReportList *reports) +{ + bool ok; + if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) { + const char *opstring = object_mode_op_string(ob->mode); + WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); + ok = ELEM(ob->mode, mode, OB_MODE_OBJECT); + if (!ok) { + wmOperatorType *ot = WM_operatortype_find(opstring, false); + BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name); + } + } + else { + ok = true; + } + + return ok; +} + static int object_mode_set_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); @@ -1542,25 +1586,31 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) ObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT; int toggle = RNA_boolean_get(op->ptr, "toggle"); - if (!ob || !object_mode_set_compat(C, op, ob)) + if (!ob || !object_mode_compat_test(ob, mode)) return OPERATOR_PASS_THROUGH; - /* Exit current mode if it's not the mode we're setting */ - if (ob->mode != OB_MODE_OBJECT && ob->mode != mode) - WM_operator_name_call(C, object_mode_op_string(ob->mode), WM_OP_EXEC_REGION_WIN, NULL); + if (ob->mode != mode) { + /* we should be able to remove this call, each operator calls */ + ED_object_mode_compat_set(C, ob, mode, op->reports); + } - if (mode != OB_MODE_OBJECT) { + /* Exit current mode if it's not the mode we're setting */ + if (mode != OB_MODE_OBJECT && (ob->mode != mode || toggle)) { /* Enter new mode */ - if (ob->mode != mode || toggle) - WM_operator_name_call(C, object_mode_op_string(mode), WM_OP_EXEC_REGION_WIN, NULL); - - if (toggle) { - if (ob->mode == mode) - /* For toggling, store old mode so we know what to go back to */ - ob->restore_mode = restore_mode; - else if (ob->restore_mode != OB_MODE_OBJECT && ob->restore_mode != mode) { - WM_operator_name_call(C, object_mode_op_string(ob->restore_mode), WM_OP_EXEC_REGION_WIN, NULL); - } + WM_operator_name_call(C, object_mode_op_string(mode), WM_OP_EXEC_REGION_WIN, NULL); + } + + if (toggle) { + /* Special case for Object mode! */ + if (mode == OB_MODE_OBJECT && restore_mode == OB_MODE_OBJECT && ob->restore_mode != OB_MODE_OBJECT) { + WM_operator_name_call(C, object_mode_op_string(ob->restore_mode), WM_OP_EXEC_REGION_WIN, NULL); + } + else if (ob->mode == mode) { + /* For toggling, store old mode so we know what to go back to */ + ob->restore_mode = restore_mode; + } + else if (ob->restore_mode != OB_MODE_OBJECT && ob->restore_mode != mode) { + WM_operator_name_call(C, object_mode_op_string(ob->restore_mode), WM_OP_EXEC_REGION_WIN, NULL); } } @@ -1569,6 +1619,8 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) void OBJECT_OT_mode_set(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Set Object Mode"; ot->description = "Sets the object interaction mode"; @@ -1584,14 +1636,20 @@ void OBJECT_OT_mode_set(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "mode", object_mode_items, OB_MODE_OBJECT, "Mode", ""); RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf); + RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); - RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); + prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } void ED_object_toggle_modes(bContext *C, int mode) { + /* Couldn't we use object_mode_op_string() here? + * Also, if several bits are set in mode, several toggle ops will be called, is this expected? + * If so, would be nice to explain why. ;) --mont29 + */ if (mode & OB_MODE_SCULPT) WM_operator_name_call(C, "SCULPT_OT_sculptmode_toggle", WM_OP_EXEC_REGION_WIN, NULL); if (mode & OB_MODE_VERTEX_PAINT) diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index 1f52346222c..a9fd3ce1288 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -289,7 +289,7 @@ void GROUP_OT_objects_remove_all(wmOperatorType *ot) { /* identifiers */ ot->name = "Remove From All Groups"; - ot->description = "Remove selected objects from all groups or a selected group"; + ot->description = "Remove selected objects from all groups"; ot->idname = "GROUP_OT_objects_remove_all"; /* api callbacks */ @@ -335,7 +335,7 @@ void GROUP_OT_objects_remove(wmOperatorType *ot) /* identifiers */ ot->name = "Remove From Group"; - ot->description = "Remove selected objects from all groups or a selected group"; + ot->description = "Remove selected objects from a group"; ot->idname = "GROUP_OT_objects_remove"; /* api callbacks */ diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 5b20489c9cb..37656f82b25 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -569,7 +569,7 @@ void OBJECT_OT_hook_add_selob(wmOperatorType *ot) { /* identifiers */ ot->name = "Hook to Selected Object"; - ot->description = "Hook selected vertices to the first selected Object"; + ot->description = "Hook selected vertices to the first selected object"; ot->idname = "OBJECT_OT_hook_add_selob"; /* api callbacks */ @@ -603,7 +603,7 @@ void OBJECT_OT_hook_add_newob(wmOperatorType *ot) { /* identifiers */ ot->name = "Hook to New Object"; - ot->description = "Hook selected vertices to the first selected Object"; + ot->description = "Hook selected vertices to a newly created object"; ot->idname = "OBJECT_OT_hook_add_newob"; /* api callbacks */ diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 03d51fcbe82..0ba84e27420 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -637,9 +637,9 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, cu = ob->data; BKE_report(reports, RPT_INFO, "Applied modifier only changed CV points, not tessellated/bevel vertices"); - vertexCos = BKE_curve_vertexCos_get(cu, &cu->nurb, &numVerts); + vertexCos = BKE_curve_nurbs_vertexCos_get(&cu->nurb, &numVerts); mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0); - BK_curve_vertexCos_apply(cu, &cu->nurb, vertexCos); + BK_curve_nurbs_vertexCos_apply(&cu->nurb, vertexCos); MEM_freeN(vertexCos); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 52f51cfcf48..be4948d8a80 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -55,6 +55,7 @@ #include "BLI_listbase.h" #include "BLI_linklist.h" #include "BLI_string.h" +#include "BLI_kdtree.h" #include "BLI_utildefines.h" #include "BLF_translation.h" @@ -584,12 +585,12 @@ EnumPropertyItem prop_make_parent_types[] = { {PAR_PATH_CONST, "PATH_CONST", 0, "Path Constraint", ""}, {PAR_LATTICE, "LATTICE", 0, "Lattice Deform", ""}, {PAR_VERTEX, "VERTEX", 0, "Vertex", ""}, - {PAR_TRIA, "TRIA", 0, "Triangle", ""}, + {PAR_VERTEX_TRI, "VERTEX_TRI", 0, "Vertex (Triangle)", ""}, {0, NULL, 0, NULL, NULL} }; int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object *ob, Object *par, - int partype, int xmirror, int keep_transform) + int partype, bool xmirror, bool keep_transform, const int vert_par[3]) { bPoseChannel *pchan = NULL; int pararm = ELEM4(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO); @@ -718,8 +719,17 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object if (pchan->bone) pchan->bone->flag |= BONE_RELATIVE_PARENTING; } - else + else if (partype == PAR_VERTEX) { + ob->partype = PARVERT1; + ob->par1 = vert_par[0]; + } + else if (partype == PAR_VERTEX_TRI) { + ob->partype = PARVERT3; + copy_v3_v3_int(&ob->par1, vert_par); + } + else { ob->partype = PAROBJECT; /* note, dna define, not operator property */ + } /* constraint */ if (partype == PAR_PATH_CONST) { @@ -766,25 +776,83 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object return 1; } + + +static void parent_set_vert_find(KDTree *tree, Object *child, int vert_par[3], bool is_tri) +{ + const float *co_find = child->obmat[3]; + if (is_tri) { + KDTreeNearest nearest[3]; + int tot; + + tot = BLI_kdtree_find_nearest_n(tree, co_find, NULL, nearest, 3); + BLI_assert(tot == 3); + + vert_par[0] = nearest[0].index; + vert_par[1] = nearest[1].index; + vert_par[2] = nearest[2].index; + + BLI_assert(min_iii(UNPACK3(vert_par)) >= 0); + } + else { + vert_par[0] = BLI_kdtree_find_nearest(tree, co_find, NULL, NULL); + BLI_assert(vert_par[0] >= 0); + vert_par[1] = 0; + vert_par[2] = 0; + } +} + static int parent_set_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *par = ED_object_active_context(C); int partype = RNA_enum_get(op->ptr, "type"); - int xmirror = RNA_boolean_get(op->ptr, "xmirror"); - int keep_transform = RNA_boolean_get(op->ptr, "keep_transform"); - int ok = 1; + bool xmirror = RNA_boolean_get(op->ptr, "xmirror"); + bool keep_transform = RNA_boolean_get(op->ptr, "keep_transform"); + bool ok = true; + + /* vertex parent (kdtree) */ + const bool is_vert_par = ELEM(partype, PAR_VERTEX, PAR_VERTEX_TRI); + const bool is_tri = partype == PAR_VERTEX_TRI; + int tree_tot; + struct KDTree *tree = NULL; + int vert_par[3] = {0, 0, 0}; + int *vert_par_p = is_vert_par ? vert_par : NULL; + + + if (is_vert_par) { + tree = BKE_object_as_kdtree(par, &tree_tot); + BLI_assert(tree != NULL); + + if (tree_tot < (is_tri ? 3 : 1)) { + BKE_report(op->reports, RPT_ERROR, "Not enough vertices for vertex-parent"); + ok = false; + goto cleanup; + } + } + + /* Non vertex-parent */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - if (!ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, xmirror, keep_transform)) { - ok = 0; + if (is_vert_par) { + parent_set_vert_find(tree, ob, vert_par, is_tri); + } + + if (!ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) { + ok = false; break; } } CTX_DATA_END; + +cleanup: + if (is_vert_par) { + BLI_kdtree_free(tree); + } + if (!ok) return OPERATOR_CANCELLED; @@ -835,6 +903,12 @@ static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_LATTICE); } + /* vertex parenting */ + if (OB_TYPE_SUPPORT_PARVERT(ob->type)) { + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_VERTEX); + uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_VERTEX_TRI); + } + uiPupMenuEnd(C, pup); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 366aa72f2b8..4d7abbe7c39 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -50,6 +50,7 @@ #include "BKE_curve.h" #include "BKE_depsgraph.h" #include "BKE_main.h" +#include "BKE_idcode.h" #include "BKE_mball.h" #include "BKE_mesh.h" #include "BKE_object.h" @@ -379,54 +380,45 @@ static int apply_objects_internal(bContext *C, ReportList *reports, int apply_lo Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale; - int change = 1; + bool change = true; /* first check if we can execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - - if (ob->type == OB_MESH) { - if (ID_REAL_USERS(ob->data) > 1) { - BKE_report(reports, RPT_ERROR, "Cannot apply to a multi user mesh, doing nothing"); - change = 0; - } - } - else if (ob->type == OB_ARMATURE) { - if (ID_REAL_USERS(ob->data) > 1) { - BKE_report(reports, RPT_ERROR, "Cannot apply to a multi user armature, doing nothing"); - change = 0; + if (ELEM6(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) { + ID *obdata = ob->data; + if (ID_REAL_USERS(obdata) > 1) { + BKE_reportf(reports, RPT_ERROR, + "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting", + ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); + change = false; } - } - else if (ob->type == OB_LATTICE) { - if (ID_REAL_USERS(ob->data) > 1) { - BKE_report(reports, RPT_ERROR, "Cannot apply to a multi user lattice, doing nothing"); - change = 0; - } - } - else if (ob->type == OB_MBALL) { - if (ID_REAL_USERS(ob->data) > 1) { - BKE_report(reports, RPT_ERROR, "Cannot apply to a multi user metaball, doing nothing"); - change = 0; + + if (obdata->lib) { + BKE_reportf(reports, RPT_ERROR, + "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting", + ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); + change = false; } } - else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { - Curve *cu; - if (ID_REAL_USERS(ob->data) > 1) { - BKE_report(reports, RPT_ERROR, "Cannot apply to a multi user curve, doing nothing"); - change = 0; - } + if (ELEM(ob->type, OB_CURVE, OB_SURF)) { + ID *obdata = ob->data; + Curve *cu; cu = ob->data; if (((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) { - BKE_report(reports, RPT_ERROR, - "Neither rotation nor location could be applied to a 2D curve, doing nothing"); - change = 0; + BKE_reportf(reports, RPT_ERROR, + "Rotation/Location can't apply to a 2D curve: Object \"%s\", %s \"%s\", aborting", + ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); + change = false; } if (cu->key) { - BKE_report(reports, RPT_ERROR, "Cannot apply to a curve with vertex keys, doing nothing"); - change = 0; + BKE_reportf(reports, RPT_ERROR, + "Can't apply to a curve with shape-keys: Object \"%s\", %s \"%s\", aborting", + ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); + change = false; } } } @@ -435,7 +427,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, int apply_lo if (!change) return OPERATOR_CANCELLED; - change = 0; + change = false; /* now execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) @@ -551,7 +543,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, int apply_lo } } else if (ob->type == OB_CAMERA) { - MovieClip *clip = BKE_object_movieclip_get(scene, ob, FALSE); + MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); /* applying scale on camera actually scales clip's reconstruction. * of there's clip assigned to camera nothing to do actually. @@ -562,6 +554,21 @@ static int apply_objects_internal(bContext *C, ReportList *reports, int apply_lo if (apply_scale) BKE_tracking_reconstruction_scale(&clip->tracking, ob->size); } + else if (ob->type == OB_EMPTY) { + /* It's possible for empties too, even though they don't + * really have obdata, since we can simply apply the maximum + * scaling to the empty's drawsize. + * + * Core Assumptions: + * 1) Most scaled empties have uniform scaling + * (i.e. for visibility reasons), AND/OR + * 2) Preserving non-uniform scaling is not that important, + * and is something that many users would be willing to + * sacrifice for having an easy way to do this. + */ + float max_scale = MAX3(ob->size[0], ob->size[1], ob->size[2]); + ob->empty_drawsize *= max_scale; + } else { continue; } @@ -585,12 +592,14 @@ static int apply_objects_internal(bContext *C, ReportList *reports, int apply_lo DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); - change = 1; + change = true; } CTX_DATA_END; - if (!change) + if (!change) { + BKE_report(reports, RPT_WARNING, "Objects have no data to transform"); return OPERATOR_CANCELLED; + } WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; @@ -768,7 +777,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) } if (ctx_ob_act) { - BLI_rotatelist(&ctx_data_list, (LinkData *)ctx_ob_act); + BLI_rotatelist_first(&ctx_data_list, (LinkData *)ctx_ob_act); } for (tob = bmain->object.first; tob; tob = tob->id.next) { diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 294b0632015..82454baae78 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -51,6 +51,7 @@ #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_linklist_stack.h" #include "BLF_translation.h" @@ -87,7 +88,6 @@ 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 ED_vgroup_give_parray(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, const bool use_vert_sel); static bool vertex_group_use_vert_sel(Object *ob) { @@ -208,7 +208,7 @@ void ED_vgroup_data_clamp_range(ID *id, const int total) MDeformVert **dvert_arr; int dvert_tot; - if (ED_vgroup_give_parray(id, &dvert_arr, &dvert_tot, false)) { + if (ED_vgroup_parray_alloc(id, &dvert_arr, &dvert_tot, false)) { int i; for (i = 0; i < dvert_tot; i++) { MDeformVert *dv = dvert_arr[i]; @@ -223,7 +223,7 @@ void ED_vgroup_data_clamp_range(ID *id, const int total) } } -static bool ED_vgroup_give_parray(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, const bool use_vert_sel) +bool ED_vgroup_parray_alloc(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, const bool use_vert_sel) { *dvert_tot = 0; *dvert_arr = NULL; @@ -326,8 +326,121 @@ static bool ED_vgroup_give_parray(ID *id, MDeformVert ***dvert_arr, int *dvert_t 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. + * + * \note \a dvert_array has mirrored weights filled in, incase cleanup operations are needed on both. + */ +void ED_vgroup_parray_mirror_sync(Object *ob, + MDeformVert **dvert_array, const int dvert_tot, + const bool *vgroup_validmap, const int vgroup_tot) +{ + BMEditMesh *em = BKE_editmesh_from_object(ob); + MDeformVert **dvert_array_all = NULL; + int dvert_tot_all; + int i; + + /* get an array of all verts, not only selected */ + if (ED_vgroup_parray_alloc(ob->data, &dvert_array_all, &dvert_tot_all, false) == false) { + BLI_assert(0); + return; + } + if (em) { + EDBM_index_arrays_ensure(em, BM_VERT); + } + + for (i = 0; i < dvert_tot; i++) { + if (dvert_array[i] == NULL) { + /* its unselected, check if its mirror is */ + int i_sel = ED_mesh_mirror_get_vert(ob, i); + if ((i_sel != -1) && (i_sel != i) && (dvert_array[i_sel])) { + /* we found a match! */ + MDeformVert *dv_src = dvert_array[i_sel]; + MDeformVert *dv_dst = dvert_array_all[i]; + + defvert_copy_subset(dv_dst, dv_src, vgroup_validmap, vgroup_tot); + + dvert_array[i] = dvert_array_all[i]; + } + } + } + + MEM_freeN(dvert_array_all); +} + +/** + * Fill in the pointers for mirror verts (as if all mirror verts were selected too). + * + * similar to #ED_vgroup_parray_mirror_sync but only fill in mirror points. + */ +void ED_vgroup_parray_mirror_assign(Object *ob, + MDeformVert **dvert_array, const int dvert_tot) +{ + BMEditMesh *em = BKE_editmesh_from_object(ob); + MDeformVert **dvert_array_all = NULL; + int dvert_tot_all; + int i; + + /* get an array of all verts, not only selected */ + if (ED_vgroup_parray_alloc(ob->data, &dvert_array_all, &dvert_tot_all, false) == false) { + BLI_assert(0); + return; + } + BLI_assert(dvert_tot == dvert_tot_all); + if (em) { + EDBM_index_arrays_ensure(em, BM_VERT); + } + + for (i = 0; i < dvert_tot; i++) { + if (dvert_array[i] == NULL) { + /* its unselected, check if its mirror is */ + int i_sel = ED_mesh_mirror_get_vert(ob, i); + if ((i_sel != -1) && (i_sel != i) && (dvert_array[i_sel])) { + /* we found a match! */ + dvert_array[i] = dvert_array_all[i]; + } + } + } + + MEM_freeN(dvert_array_all); +} + +void ED_vgroup_parray_remove_zero(MDeformVert **dvert_array, const int dvert_tot, + const bool *vgroup_validmap, const int vgroup_tot, + const float epsilon, const bool keep_single) +{ + MDeformVert *dv; + int i; + + for (i = 0; i < dvert_tot; i++) { + int j; + + /* in case its not selected */ + if (!(dv = dvert_array[i])) { + continue; + } + + j = dv->totweight; + + while (j--) { + MDeformWeight *dw; + + if (keep_single && dv->totweight == 1) + break; + + dw = dv->dw + j; + if ((dw->def_nr < vgroup_tot) && vgroup_validmap[dw->def_nr]) { + if (dw->weight <= epsilon) { + defvert_remove_group(dv, dw); + } + } + } + } +} + /* returns true if the id type supports weights */ -bool ED_vgroup_give_array(ID *id, MDeformVert **dvert_arr, int *dvert_tot) +bool ED_vgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_tot) { if (id) { switch (GS(id->name)) { @@ -355,7 +468,7 @@ bool ED_vgroup_give_array(ID *id, MDeformVert **dvert_arr, int *dvert_tot) } /* matching index only */ -bool ED_vgroup_copy_array(Object *ob, Object *ob_from) +bool ED_vgroup_array_copy(Object *ob, Object *ob_from) { MDeformVert **dvert_array_from, **dvf; MDeformVert **dvert_array, **dv; @@ -366,11 +479,11 @@ bool ED_vgroup_copy_array(Object *ob, Object *ob_from) int defbase_tot = BLI_countlist(&ob->defbase); bool new_vgroup = false; - ED_vgroup_give_parray(ob_from->data, &dvert_array_from, &dvert_tot_from, false); - ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, false); + 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)) { - ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, false); + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); new_vgroup = true; } @@ -783,8 +896,8 @@ static bool ed_vgroup_transfer_weight(Object *ob_dst, Object *ob_src, bDeformGro if (!me_dst->dvert) ED_vgroup_data_create(ob_dst->data); /* Get vertex group arrays.*/ - ED_vgroup_give_parray(ob_src->data, &dv_array_src, &dv_tot_src, false); - ED_vgroup_give_parray(ob_dst->data, &dv_array_dst, &dv_tot_dst, use_vert_sel); + ED_vgroup_parray_alloc(ob_src->data, &dv_array_src, &dv_tot_src, false); + ED_vgroup_parray_alloc(ob_dst->data, &dv_array_dst, &dv_tot_dst, use_vert_sel); /* Get indexes of vertex groups.*/ index_src = BLI_findindex(&ob_src->defbase, dg_src); @@ -1031,7 +1144,7 @@ static void ED_vgroup_nr_vert_add(Object *ob, int tot; /* get the vert */ - ED_vgroup_give_array(ob->data, &dvert, &tot); + ED_vgroup_array_get(ob->data, &dvert, &tot); if (dvert == NULL) return; @@ -1117,7 +1230,7 @@ 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_give_array(ob->data, &dv, &tot) && dv == NULL) + if (ED_vgroup_array_get(ob->data, &dv, &tot) && dv == NULL) ED_vgroup_data_create(ob->data); /* call another function to do the work @@ -1142,7 +1255,7 @@ void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum) /* get the deform vertices corresponding to the * vertnum */ - ED_vgroup_give_array(ob->data, &dvert, &tot); + ED_vgroup_array_get(ob->data, &dvert, &tot); if (dvert) { MDeformVert *dv = &dvert[vertnum]; @@ -1335,7 +1448,7 @@ static void vgroup_duplicate(Object *ob) icdg = (ob->actdef - 1); /* TODO, we might want to allow only copy selected verts here? - campbell */ - ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, false); + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, false); if (dvert_array) { for (i = 0; i < dvert_tot; i++) { @@ -1367,7 +1480,7 @@ bool *ED_vgroup_subset_from_select_type(Object *ob, eVGroupSelect subset_type, i 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 < *r_vgroup_tot) { + if ((def_nr_active >= 0) && (def_nr_active < *r_vgroup_tot)) { *r_subset_count = 1; vgroup_validmap[def_nr_active] = true; } @@ -1419,6 +1532,20 @@ bool *ED_vgroup_subset_from_select_type(Object *ob, eVGroupSelect subset_type, i 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; @@ -1432,7 +1559,7 @@ static void vgroup_normalize(Object *ob) return; } - ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { float weight_max = 0.0f; @@ -1561,9 +1688,12 @@ static void getVerticalAndHorizontalChange(const float norm[3], float d, const f /* A = Q - ((Q - P).N)N * D = (a * x0 + b * y0 +c * z0 + d) */ float projA[3], projB[3]; + float plane[4]; + + plane_from_point_normal_v3(plane, coord, norm); - closest_to_plane_v3(projA, coord, norm, start); - closest_to_plane_v3(projB, coord, norm, end); + closest_to_plane_v3(projA, plane, start); + closest_to_plane_v3(projB, plane, end); /* (vertical and horizontal refer to the plane's y and xz respectively) * vertical distance */ dists[index] = dot_v3v3(norm, end) + d; @@ -1833,9 +1963,10 @@ static void vgroup_levels_subset(Object *ob, const bool *vgroup_validmap, const MDeformVert *dv, **dvert_array = NULL; int i, dvert_tot = 0; - const int use_vert_sel = vertex_group_use_vert_sel(ob); + const bool use_vert_sel = vertex_group_use_vert_sel(ob); + const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false; - ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { @@ -1860,6 +1991,11 @@ static void vgroup_levels_subset(Object *ob, const bool *vgroup_validmap, const } } + if (use_mirror && use_vert_sel) { + ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, + vgroup_validmap, vgroup_tot); + } + MEM_freeN(dvert_array); } } @@ -1876,7 +2012,7 @@ static void vgroup_normalize_all(Object *ob, const bool lock_active) return; } - ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { const int defbase_tot = BLI_countlist(&ob->defbase); @@ -1963,9 +2099,10 @@ static void vgroup_invert_subset(Object *ob, MDeformWeight *dw; MDeformVert *dv, **dvert_array = NULL; int i, dvert_tot = 0; - const int use_vert_sel = vertex_group_use_vert_sel(ob); + const bool use_vert_sel = vertex_group_use_vert_sel(ob); + const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false; - ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { for (i = 0; i < dvert_tot; i++) { @@ -1989,149 +2126,153 @@ static void vgroup_invert_subset(Object *ob, if (dw) { dw->weight = 1.0f - dw->weight; - if (auto_remove && dw->weight <= 0.0f) { - defvert_remove_group(dv, dw); - } + CLAMP(dw->weight, 0.0f, 1.0f); } } } } + if (use_mirror && use_vert_sel) { + ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, + vgroup_validmap, vgroup_tot); + + if (auto_remove) { + ED_vgroup_parray_remove_zero(dvert_array, dvert_tot, + vgroup_validmap, vgroup_tot, + 0.0f, false); + } + } + MEM_freeN(dvert_array); } } -static void vgroup_blend(Object *ob, const float fac) +static void vgroup_blend_subset(Object *ob, const bool *vgroup_validmap, const int vgroup_tot, + const int subset_count, + const float fac) { - MDeformVert *dv; - MDeformWeight *dw; + const float ifac = 1.0f - fac; + MDeformVert **dvert_array = NULL; int i, dvert_tot = 0; - const int def_nr = ob->actdef - 1; - - BLI_assert(fac >= 0.0f && fac <= 1.0f); + int *vgroup_subset_map = BLI_array_alloca(vgroup_subset_map, subset_count); + float *vgroup_subset_weights = BLI_array_alloca(vgroup_subset_weights, subset_count); + const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false; - if (ob->type != OB_MESH) { - return; - } + BMEditMesh *em = BKE_editmesh_from_object(ob); + BMesh *bm = em ? em->bm : NULL; + Mesh *me = em ? NULL : ob->data; - if (BLI_findlink(&ob->defbase, def_nr)) { - const float ifac = 1.0f - fac; + MeshElemMap *emap ; + int *emap_mem; - BMEditMesh *em = BKE_editmesh_from_object(ob); - BMesh *bm = em ? em->bm : NULL; - Mesh *me = em ? NULL : ob->data; + BLI_SMALLSTACK_DECLARE(dv_stack, MDeformVert *); - /* bmesh only*/ - BMEdge *eed; - BMVert *eve; - BMIter iter; + ED_vgroup_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); - /* mesh only */ - MDeformVert *dvert_array = NULL; + if (bm) { + EDBM_index_arrays_ensure(em, BM_VERT); + emap = NULL; + emap_mem = NULL; + } + else { + BKE_mesh_vert_edge_map_create(&emap, &emap_mem, + me->medge, me->totvert, me->totedge); + } - float *vg_weights; - float *vg_users; - int sel1, sel2; - if (bm) { - BM_mesh_elem_index_ensure(bm, BM_VERT); - dvert_tot = bm->totvert; - } - else { - dvert_tot = me->totvert; - dvert_array = me->dvert; - } - - vg_weights = MEM_callocN(sizeof(float) * dvert_tot, "vgroup_blend_f"); - vg_users = MEM_callocN(sizeof(int) * dvert_tot, "vgroup_blend_i"); + for (i = 0; i < dvert_tot; i++) { + MDeformVert *dv; + int dv_stack_tot = 0; + int j; + /* in case its not selected */ if (bm) { - const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); - - BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { - sel1 = BM_elem_flag_test(eed->v1, BM_ELEM_SELECT); - sel2 = BM_elem_flag_test(eed->v2, BM_ELEM_SELECT); - - if (sel1 != sel2) { - int i1 /* , i2 */; - /* i1 is always the selected one */ - if (sel1) { - i1 = BM_elem_index_get(eed->v1); - /* i2 = BM_elem_index_get(eed->v2); */ /* UNUSED */ - eve = eed->v2; - } - else { - /* i2 = BM_elem_index_get(eed->v1); */ /* UNUSED */ - i1 = BM_elem_index_get(eed->v2); - eve = eed->v1; + BMVert *v = EDBM_vert_at_index(em, i); + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + BMIter eiter; + BMEdge *e; + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + BMVert *v_other = BM_edge_other_vert(e, v); + const int i_other = BM_elem_index_get(v_other); + + if (BM_elem_flag_test(v_other, BM_ELEM_SELECT) == 0) { + dv = dvert_array[i_other]; + BLI_SMALLSTACK_PUSH(dv_stack, dv); + dv_stack_tot++; } - - dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - dw = defvert_find_index(dv, def_nr); - if (dw) { - vg_weights[i1] += dw->weight; - } - vg_users[i1]++; } } - - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && vg_users[i] > 0) { - dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - - dw = defvert_verify_index(dv, def_nr); - dw->weight = (fac * (vg_weights[i] / (float)vg_users[i])) + (ifac * dw->weight); - /* in case of division errors */ - CLAMP(dw->weight, 0.0f, 1.0f); + } + else { + MVert *v = &me->mvert[i]; + if (v->flag & SELECT) { + for (j = 0; j < emap[i].count; j++) { + MEdge *e = &me->medge[emap[i].indices[j]]; + const int i_other = (e->v1 == i ? e->v2 : e->v1); + MVert *v_other = &me->mvert[i_other]; + + if ((v_other->flag & SELECT) == 0) { + dv = dvert_array[i_other]; + BLI_SMALLSTACK_PUSH(dv_stack, dv); + dv_stack_tot++; + } } } } - else { - MEdge *ed = me->medge; - MVert *mv; - for (i = 0; i < me->totedge; i++, ed++) { - sel1 = me->mvert[ed->v1].flag & SELECT; - sel2 = me->mvert[ed->v2].flag & SELECT; + if (dv_stack_tot) { + const float dv_mul = 1.0f / (float)dv_stack_tot; - if (sel1 != sel2) { - int i1, i2; - /* i1 is always the selected one */ - if (sel1) { - i1 = ed->v1; - i2 = ed->v2; - } - else { - i2 = ed->v1; - i1 = ed->v2; - } - - dv = &dvert_array[i2]; - dw = defvert_find_index(dv, def_nr); - if (dw) { - vg_weights[i1] += dw->weight; - } - vg_users[i1]++; + /* vgroup_subset_weights is zero'd at this point */ + while ((dv = BLI_SMALLSTACK_POP(dv_stack))) { + for (j = 0; j < subset_count; j++) { + vgroup_subset_weights[j] += dv_mul * defvert_find_weight(dv, vgroup_subset_map[j]); } } - mv = me->mvert; - dv = dvert_array; - - for (i = 0; i < dvert_tot; i++, mv++, dv++) { - if ((mv->flag & SELECT) && (vg_users[i] > 0)) { - dw = defvert_verify_index(dv, def_nr); - dw->weight = (fac * (vg_weights[i] / (float)vg_users[i])) + (ifac * dw->weight); + dv = dvert_array[i]; + for (j = 0; j < subset_count; j++) { + MDeformWeight *dw; + if (vgroup_subset_weights[j] > 0.0f) { + dw = defvert_verify_index(dv, vgroup_subset_map[j]); + } + else { + dw = defvert_find_index(dv, vgroup_subset_map[j]); + } - /* in case of division errors */ + if (dw) { + dw->weight = (fac * vgroup_subset_weights[j]) + (ifac * dw->weight); CLAMP(dw->weight, 0.0f, 1.0f); } + + /* zero for next iteration */ + vgroup_subset_weights[j] = 0.0f; } } + } - MEM_freeN(vg_weights); - MEM_freeN(vg_users); + if (bm) { + /* pass */ + } + else { + MEM_freeN(emap); + MEM_freeN(emap_mem); + } + + if (dvert_array) + MEM_freeN(dvert_array); + BLI_SMALLSTACK_FREE(dv_stack); + + /* not so efficient to get 'dvert_array' again just so unselected verts are NULL'd */ + if (use_mirror) { + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, true); + ED_vgroup_parray_mirror_sync(ob, dvert_array, dvert_tot, + vgroup_validmap, vgroup_tot); + if (dvert_array) + MEM_freeN(dvert_array); } } @@ -2164,7 +2305,7 @@ static int vgroup_limit_total_subset(Object *ob, const int use_vert_sel = vertex_group_use_vert_sel(ob); int remove_tot = 0; - ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { int num_to_drop = 0; @@ -2228,39 +2369,24 @@ static void vgroup_clean_subset(Object *ob, const bool *vgroup_validmap, const i const float epsilon, const bool keep_single) { MDeformVert **dvert_array = NULL; - int i, dvert_tot = 0; - const int use_vert_sel = vertex_group_use_vert_sel(ob); + int dvert_tot = 0; + const bool use_vert_sel = vertex_group_use_vert_sel(ob); + const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false; - ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel); + ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel); if (dvert_array) { - MDeformVert *dv; - MDeformWeight *dw; - - for (i = 0; i < dvert_tot; i++) { - int j; - - /* in case its not selected */ - if (!(dv = dvert_array[i])) { - continue; - } - - j = dv->totweight; - - while (j--) { - - if (keep_single && dv->totweight == 1) - break; - - dw = dv->dw + j; - if ((dw->def_nr < vgroup_tot) && vgroup_validmap[dw->def_nr]) { - if (dw->weight <= epsilon) { - defvert_remove_group(dv, dw); - } - } - } + if (use_mirror && use_vert_sel) { + /* correct behavior in this case isn't well defined + * for now assume both sides are mirrored correctly, + * so cleaning one side also cleans the other */ + ED_vgroup_parray_mirror_assign(ob, dvert_array, dvert_tot); } + ED_vgroup_parray_remove_zero(dvert_array, dvert_tot, + vgroup_validmap, vgroup_tot, + epsilon, keep_single); + MEM_freeN(dvert_array); } } @@ -2585,7 +2711,7 @@ static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg) assert(def_nr > -1); - ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot); + ED_vgroup_array_get(ob->data, &dvert_array, &dvert_tot); if (dvert_array) { int i, j; @@ -3504,8 +3630,13 @@ static int vertex_group_blend_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); float fac = RNA_float_get(op->ptr, "factor"); + eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode"); + + int subset_count, vgroup_tot; - vgroup_blend(ob, fac); + const bool *vgroup_validmap = ED_vgroup_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); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); @@ -3523,10 +3654,14 @@ static int vertex_group_blend_poll(bContext *C) if (!(ob && !ob->id.lib && data && !data->lib)) return false; + if (ob->type != OB_MESH) { + return false; + } + if (BKE_object_is_in_editmode_vgroup(ob)) { return true; } - else if ((ob->type == OB_MESH) && (ob->mode & OB_MODE_WEIGHT_PAINT)) { + else if (ob->mode & OB_MODE_WEIGHT_PAINT) { if (ME_EDIT_PAINT_SEL_MODE(((Mesh *)data)) == SCE_SELECT_VERTEX) { return true; } @@ -3557,6 +3692,7 @@ void OBJECT_OT_vertex_group_blend(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + vgroup_operator_subset_select_props(ot, true); prop = RNA_def_property(ot->srna, "factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text(prop, "Factor", ""); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -3746,7 +3882,7 @@ static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (obact != ob) { - if (ED_vgroup_copy_array(ob, obact)) change++; + if (ED_vgroup_array_copy(ob, obact)) change++; else fail++; } } @@ -4040,7 +4176,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) else { int dvert_tot = 0; - ED_vgroup_give_array(ob->data, &dvert, &dvert_tot); + ED_vgroup_array_get(ob->data, &dvert, &dvert_tot); /*create as necessary*/ if (dvert) { diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c index 5cb74e1ca09..568802dd7a0 100644 --- a/source/blender/editors/physics/dynamicpaint_ops.c +++ b/source/blender/editors/physics/dynamicpaint_ops.c @@ -18,6 +18,10 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/editors/physics/dynamicpaint_ops.c + * \ingroup edphys + */ + #include <math.h> #include <stdio.h> #include <string.h> @@ -384,7 +388,7 @@ static int dynamicPaint_initBake(struct bContext *C, struct wmOperator *op) /* Clear bake */ canvas->flags &= ~MOD_DPAINT_BAKING; if (!G.background) { - WM_cursor_restore(win); + WM_cursor_modal_restore(win); } dynamicPaint_freeSurfaceData(surface); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index d6bb394ff79..b0e19d04e35 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -69,6 +69,7 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "ED_object.h" #include "ED_physics.h" #include "ED_mesh.h" #include "ED_particle.h" @@ -2452,7 +2453,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) copy_v3_v3(co, point->keys->co); mul_m4_v3(mat, co); - totn= BLI_kdtree_find_n_nearest(tree, 10, co, NULL, nearest); + totn = BLI_kdtree_find_nearest_n(tree, co, NULL, nearest, 10); for (n=0; n<totn; n++) { /* this needs a custom threshold still */ @@ -3458,7 +3459,7 @@ static int brush_add(PEData *data, short number) float maxd, totw=0.0, weight[3]; psys_particle_on_dm(psmd->dm, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co1, 0, 0, 0, 0, 0); - maxw= BLI_kdtree_find_n_nearest(tree, 3, co1, NULL, ptn); + maxw = BLI_kdtree_find_nearest_n(tree, co1, NULL, ptn, 3); maxd= ptn[maxw-1].dist; @@ -4345,23 +4346,36 @@ static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, static int particle_edit_toggle_poll(bContext *C) { - Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); + Object *ob = CTX_data_active_object(C); - if (!scene || !ob || ob->id.lib) + if (ob == NULL || ob->type != OB_MESH) return 0; - - return (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) || modifiers_findByType(ob, eModifierType_Softbody)); + if (!ob->data || ((ID *)ob->data)->lib) + return 0; + if (CTX_data_edit_object(C)) + return 0; + + return (ob->particlesystem.first || + modifiers_findByType(ob, eModifierType_Cloth) || + modifiers_findByType(ob, eModifierType_Softbody)); } -static int particle_edit_toggle_exec(bContext *C, wmOperator *UNUSED(op)) +static int particle_edit_toggle_exec(bContext *C, wmOperator *op) { - Scene *scene= CTX_data_scene(C); - Object *ob= CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + const int mode_flag = OB_MODE_PARTICLE_EDIT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; + + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } + } - if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) { + if (!is_mode_set) { PTCacheEdit *edit; - ob->mode |= OB_MODE_PARTICLE_EDIT; + ob->mode |= mode_flag; edit= PE_create_current(scene, ob); /* mesh may have changed since last entering editmode. @@ -4373,7 +4387,7 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *UNUSED(op)) WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_PARTICLE, NULL); } else { - ob->mode &= ~OB_MODE_PARTICLE_EDIT; + ob->mode &= ~mode_flag; toggle_particle_cursor(C, 0); WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL); } @@ -4407,7 +4421,7 @@ static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op)) ParticleSystem *psys = psys_get_current(ob); if (psys->edit) { - if (psys->edit->edited || 1) { // XXX okee("Lose changes done in particle mode?")) + if (psys->edit->edited || 1) { PE_free_ptcache_edit(psys->edit); psys->edit = NULL; @@ -4433,6 +4447,11 @@ static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } +static int clear_edited_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + return WM_operator_confirm_message(C, op, "Lose changes done in particle mode? (no undo)"); +} + void PARTICLE_OT_edited_clear(wmOperatorType *ot) { /* identifiers */ @@ -4443,6 +4462,7 @@ void PARTICLE_OT_edited_clear(wmOperatorType *ot) /* api callbacks */ ot->exec = clear_edited_exec; ot->poll = particle_edit_toggle_poll; + ot->invoke = clear_edited_invoke; /* flags */ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c index b9742c9968f..515ac330cc9 100644 --- a/source/blender/editors/physics/physics_pointcache.c +++ b/source/blender/editors/physics/physics_pointcache.c @@ -126,7 +126,7 @@ static int ptcache_bake_all_exec(bContext *C, wmOperator *op) * the job system soon anyways. */ if (win) { baker.progressbar = (void (*)(void *, int))WM_cursor_time; - baker.progressend = (void (*)(void *))WM_cursor_restore; + baker.progressend = (void (*)(void *))WM_cursor_modal_restore; baker.progresscontext = win; } else { @@ -230,7 +230,7 @@ static int ptcache_bake_exec(bContext *C, wmOperator *op) * the job system soon anyways. */ if (win) { baker.progressbar = (void (*)(void *, int))WM_cursor_time; - baker.progressend = (void (*)(void *))WM_cursor_restore; + baker.progressend = (void (*)(void *))WM_cursor_modal_restore; baker.progresscontext = win; } else { diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 3a6bd05df0b..39d6f836815 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -164,7 +164,7 @@ void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volat IMB_partial_display_buffer_update(ibuf, rectf, NULL, rr->rectx, rxmin, rymin, &scene->view_settings, &scene->display_settings, - rxmin, rymin, rxmin + xmax, rymin + ymax, TRUE); + rxmin, rymin, rxmin + xmax, rymin + ymax, true); } /* ****************************** render invoking ***************** */ @@ -212,7 +212,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) Image *ima; View3D *v3d = CTX_wm_view3d(C); Main *mainp = CTX_data_main(C); - unsigned int lay; + unsigned int lay_override; const short is_animation = RNA_boolean_get(op->ptr, "animation"); const short is_write_still = RNA_boolean_get(op->ptr, "write_still"); struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; @@ -226,7 +226,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) } re = RE_NewRender(scene->id.name); - lay = (v3d) ? v3d->lay : scene->lay; + lay_override = (v3d && v3d->lay != scene->lay) ? v3d->lay : 0; G.is_break = FALSE; RE_test_break_cb(re, NULL, render_break); @@ -244,9 +244,9 @@ static int screen_render_exec(bContext *C, wmOperator *op) RE_SetReports(re, op->reports); if (is_animation) - RE_BlenderAnim(re, mainp, scene, camera_override, lay, scene->r.sfra, scene->r.efra, scene->r.frame_step); + RE_BlenderAnim(re, mainp, scene, camera_override, lay_override, scene->r.sfra, scene->r.efra, scene->r.frame_step); else - RE_BlenderFrame(re, mainp, scene, srl, camera_override, lay, scene->r.cfra, is_write_still); + RE_BlenderFrame(re, mainp, scene, srl, camera_override, lay_override, scene->r.cfra, is_write_still); RE_SetReports(re, NULL); @@ -265,11 +265,12 @@ typedef struct RenderJob { wmWindow *win; SceneRenderLayer *srl; struct Object *camera_override; - int lay; + int lay_override; bool v3d_override; short anim, write_still; Image *image; ImageUser iuser; + bool image_outdated; short *stop; short *do_update; float *progress; @@ -409,9 +410,19 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec void *lock; /* only update if we are displaying the slot being rendered */ - if (ima->render_slot != ima->last_render_slot) + if (ima->render_slot != ima->last_render_slot) { + rj->image_outdated = true; return; + } + else if (rj->image_outdated) { + /* update entire render */ + rj->image_outdated = false; + BKE_image_signal(ima, NULL, IMA_SIGNAL_COLORMANAGE); + *(rj->do_update) = TRUE; + return; + } + /* update part of render */ ibuf = BKE_image_acquire_ibuf(ima, &rj->iuser, &lock); if (ibuf) { image_buffer_rect_update(rj->scene, rr, ibuf, renrect); @@ -433,9 +444,9 @@ static void render_startjob(void *rjv, short *stop, short *do_update, float *pro RE_SetReports(rj->re, rj->reports); if (rj->anim) - RE_BlenderAnim(rj->re, rj->main, rj->scene, rj->camera_override, rj->lay, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->r.frame_step); + RE_BlenderAnim(rj->re, rj->main, rj->scene, rj->camera_override, rj->lay_override, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->r.frame_step); else - RE_BlenderFrame(rj->re, rj->main, rj->scene, rj->srl, rj->camera_override, rj->lay, rj->scene->r.cfra, rj->write_still); + RE_BlenderFrame(rj->re, rj->main, rj->scene, rj->srl, rj->camera_override, rj->lay_override, rj->scene->r.cfra, rj->write_still); RE_SetReports(rj->re, NULL); } @@ -491,7 +502,9 @@ static void render_endjob(void *rjv) * engine API, so lets use simple and robust way for now * - sergey - */ - if (rj->scene->r.layers.first != rj->scene->r.layers.last) { + if (rj->scene->r.layers.first != rj->scene->r.layers.last || + rj->image_outdated) + { void *lock; Image *ima = rj->image; ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &rj->iuser, &lock); @@ -551,6 +564,17 @@ static int screen_render_modal(bContext *C, wmOperator *op, const wmEvent *event return OPERATOR_PASS_THROUGH; } +static int screen_render_cancel(bContext *C, wmOperator *op) +{ + wmWindowManager *wm = CTX_wm_manager(C); + Scene *scene = (Scene *) op->customdata; + + /* kill on cancel, because job is using op->reports */ + WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_RENDER); + + return OPERATOR_CANCELLED; +} + /* using context, starts job */ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *event) { @@ -558,14 +582,15 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even Main *mainp; Scene *scene = CTX_data_scene(C); SceneRenderLayer *srl = NULL; - View3D *v3d = CTX_wm_view3d(C); Render *re; wmJob *wm_job; RenderJob *rj; Image *ima; int jobflag; - const short is_animation = RNA_boolean_get(op->ptr, "animation"); - const short is_write_still = RNA_boolean_get(op->ptr, "write_still"); + const bool is_animation = RNA_boolean_get(op->ptr, "animation"); + const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); + const bool use_viewport = RNA_boolean_get(op->ptr, "use_viewport"); + View3D *v3d = use_viewport ? CTX_wm_view3d(C) : NULL; struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; const char *name; Object *active_object = CTX_data_active_object(C); @@ -638,7 +663,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even rj->win = CTX_wm_window(C); rj->srl = srl; rj->camera_override = camera_override; - rj->lay = scene->lay; + rj->lay_override = 0; rj->anim = is_animation; rj->write_still = is_write_still && !is_animation; rj->iuser.scene = scene; @@ -646,15 +671,15 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even rj->reports = op->reports; if (v3d) { - if (rj->lay != v3d->lay) { - rj->lay = v3d->lay; + if (scene->lay != v3d->lay) { + rj->lay_override = v3d->lay; rj->v3d_override = true; } else if (camera_override && camera_override != scene->camera) rj->v3d_override = true; if (v3d->localvd) - rj->lay |= v3d->localvd->lay; + rj->lay_override = scene->lay | v3d->localvd->lay; } /* setup job */ @@ -718,12 +743,14 @@ void RENDER_OT_render(wmOperatorType *ot) /* api callbacks */ ot->invoke = screen_render_invoke; ot->modal = screen_render_modal; + ot->cancel = screen_render_cancel; ot->exec = screen_render_exec; /*ot->poll = ED_operator_screenactive;*/ /* this isn't needed, causes failer in background mode */ RNA_def_boolean(ot->srna, "animation", 0, "Animation", "Render files from the animation range of this scene"); RNA_def_boolean(ot->srna, "write_still", 0, "Write Image", "Save rendered the image to the output path (used only when animation is disabled)"); + RNA_def_boolean(ot->srna, "use_viewport", 0, "Use 3D Viewport", "When inside a 3D viewport, use layers and camera of the viewport"); prop = RNA_def_string(ot->srna, "layer", "", RE_MAXNAME, "Render Layer", "Single render layer to re-render (used only when animation is disabled)"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_string(ot->srna, "scene", "", MAX_ID_NAME - 2, "Scene", "Scene to render, current scene if not specified"); @@ -804,6 +831,11 @@ static bool render_view3d_get_rects(ARegion *ar, View3D *v3d, RegionView3D *rv3d return true; } +static bool render_view3d_is_valid(RenderPreview *rp) +{ + return (rp->rv3d->render_engine != NULL); +} + /* called by renderer, checks job value */ static int render_view3d_break(void *rpv) { @@ -813,8 +845,9 @@ static int render_view3d_break(void *rpv) return 1; /* during render, rv3d->engine can get freed */ - if (rp->rv3d->render_engine == NULL) + if (render_view3d_is_valid(rp) == false) { *rp->stop = 1; + } return *(rp->stop); } @@ -928,8 +961,11 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda RE_Database_Preprocess(re); /* conversion not completed, need to do it again */ - if (!rstats->convertdone) - rp->engine->job_update_flag |= PR_UPDATE_DATABASE; + if (!rstats->convertdone) { + if (render_view3d_is_valid(rp)) { + rp->engine->job_update_flag |= PR_UPDATE_DATABASE; + } + } // printf("dbase update\n"); } @@ -1116,7 +1152,7 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C) /* Try using GLSL display transform. */ if (force_fallback == false) { - if (IMB_colormanagement_setup_glsl_draw(NULL, &scene->display_settings, TRUE)) { + if (IMB_colormanagement_setup_glsl_draw(&scene->view_settings, &scene->display_settings, true, false)) { glEnable(GL_BLEND); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glaDrawPixelsTex(rres.xof, rres.yof, rres.rectx, rres.recty, GL_RGBA, GL_FLOAT, @@ -1134,7 +1170,7 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C) "render_view3d_draw"); IMB_colormanagement_buffer_make_display_space(rres.rectf, display_buffer, rres.rectx, rres.recty, - 4, dither, NULL, &scene->display_settings); + 4, dither, &scene->view_settings, &scene->display_settings); glEnable(GL_BLEND); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index e21e889d99d..21074bdc47c 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -469,7 +469,7 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender) WM_event_remove_timer(oglrender->wm, oglrender->win, oglrender->timer); } - WM_cursor_restore(oglrender->win); + WM_cursor_modal_restore(oglrender->win); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene); @@ -517,7 +517,7 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) return 1; } -static int screen_opengl_render_anim_step(bContext *C, wmOperator *op) +static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); OGLRender *oglrender = op->customdata; @@ -549,12 +549,9 @@ static int screen_opengl_render_anim_step(bContext *C, wmOperator *op) BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, TRUE); if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) { - printf("skipping existing frame \"%s\"\n", name); - - /* go to next frame */ - oglrender->nfra += scene->r.frame_step; - - return 1; + BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name); + ok = true; + goto finally; } } @@ -591,7 +588,7 @@ static int screen_opengl_render_anim_step(bContext *C, wmOperator *op) ibuf_save = ibuf; if (is_movie || !BKE_imtype_requires_linear_float(scene->r.im_format.imtype)) { - ibuf_save = IMB_colormanagement_imbuf_for_write(ibuf, TRUE, TRUE, &scene->view_settings, + ibuf_save = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &scene->view_settings, &scene->display_settings, &scene->r.im_format); needs_free = TRUE; @@ -656,6 +653,9 @@ static int screen_opengl_render_anim_step(bContext *C, wmOperator *op) /* movie stats prints have no line break */ printf("\n"); + +finally: /* Step the frame and bail early if needed */ + /* go to next frame */ oglrender->nfra += scene->r.frame_step; @@ -673,7 +673,7 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent { OGLRender *oglrender = op->customdata; int anim = RNA_boolean_get(op->ptr, "animation"); - int ret; + bool ret; switch (event->type) { case ESCKEY: @@ -698,11 +698,12 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent screen_opengl_render_end(C, op->customdata); return OPERATOR_FINISHED; } - else + else { ret = screen_opengl_render_anim_step(C, op); + } /* stop at the end or on error */ - if (ret == 0) { + if (ret == false) { return OPERATOR_FINISHED; } @@ -750,7 +751,7 @@ static int screen_opengl_render_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } else { - int ret = 1; + bool ret = true; if (!screen_opengl_render_anim_initialize(C, op)) return OPERATOR_CANCELLED; diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 4bd8a7d426a..2bf8a48edc4 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -587,6 +587,7 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r ID *parent = (ID *)parentp; MTex *slot = (MTex *)slotp; SpaceButs *sbuts = sa->spacedata.first; + ShaderPreview *sp = WM_jobs_customdata(wm, sa); rcti newrect; int ok; int newx = BLI_rcti_size_x(rect); @@ -608,9 +609,11 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r *rect = newrect; /* start a new preview render job if signalled through sbuts->preview, - * or if no render result was found and no preview render job is running */ + * if no render result was found and no preview render job is running, + * or if the job is running and the size of preview changed */ if ((sbuts->spacetype == SPACE_BUTS && sbuts->preview) || - (!ok && !WM_jobs_test(wm, sa, WM_JOB_TYPE_RENDER_PREVIEW))) + (!ok && !WM_jobs_test(wm, sa, WM_JOB_TYPE_RENDER_PREVIEW)) || + (sp && (ABS(sp->sizex - newx) >= 2 || ABS(sp->sizey - newy) > 2))) { sbuts->preview = 0; ED_preview_shader_job(C, sa, id, parent, slot, newx, newy, PR_BUTS_RENDER); diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 58c244228ed..553a543390f 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -588,6 +588,20 @@ void SCENE_OT_render_layer_remove(wmOperatorType *ot) #ifdef WITH_FREESTYLE +static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportList *reports) +{ + if (!lineset) { + BKE_report(reports, RPT_ERROR, "No active lineset and associated line style to add the modifier to"); + return false; + } + if (!lineset->linestyle) { + BKE_report(reports, RPT_ERROR, "The active lineset does not have a line style (indicating data corruption)"); + return false; + } + + return true; +} + static int freestyle_active_module_poll(bContext *C) { PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings); @@ -860,8 +874,13 @@ static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "No active lineset to add a new line style to"); return OPERATOR_CANCELLED; } - lineset->linestyle->id.us--; - lineset->linestyle = BKE_copy_linestyle(lineset->linestyle); + if (lineset->linestyle) { + lineset->linestyle->id.us--; + lineset->linestyle = BKE_copy_linestyle(lineset->linestyle); + } + else { + lineset->linestyle = BKE_new_linestyle("LineStyle", NULL); + } WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); @@ -890,10 +909,10 @@ static int freestyle_color_modifier_add_exec(bContext *C, wmOperator *op) FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig); int type = RNA_enum_get(op->ptr, "type"); - if (!lineset) { - BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style to add the modifier to"); + if (!freestyle_linestyle_check_report(lineset, op->reports)) { return OPERATOR_CANCELLED; } + if (BKE_add_linestyle_color_modifier(lineset->linestyle, type) == NULL) { BKE_report(op->reports, RPT_ERROR, "Unknown line color modifier type"); return OPERATOR_CANCELLED; @@ -929,10 +948,10 @@ static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op) FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig); int type = RNA_enum_get(op->ptr, "type"); - if (!lineset) { - BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style to add the modifier to"); + if (!freestyle_linestyle_check_report(lineset, op->reports)) { return OPERATOR_CANCELLED; } + if (BKE_add_linestyle_alpha_modifier(lineset->linestyle, type) == NULL) { BKE_report(op->reports, RPT_ERROR, "Unknown alpha transparency modifier type"); return OPERATOR_CANCELLED; @@ -968,10 +987,10 @@ static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op) FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig); int type = RNA_enum_get(op->ptr, "type"); - if (!lineset) { - BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style to add the modifier to"); + if (!freestyle_linestyle_check_report(lineset, op->reports)) { return OPERATOR_CANCELLED; } + if (BKE_add_linestyle_thickness_modifier(lineset->linestyle, type) == NULL) { BKE_report(op->reports, RPT_ERROR, "Unknown line thickness modifier type"); return OPERATOR_CANCELLED; @@ -1007,10 +1026,10 @@ static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op) FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig); int type = RNA_enum_get(op->ptr, "type"); - if (!lineset) { - BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style to add the modifier to"); + if (!freestyle_linestyle_check_report(lineset, op->reports)) { return OPERATOR_CANCELLED; } + if (BKE_add_linestyle_geometry_modifier(lineset->linestyle, type) == NULL) { BKE_report(op->reports, RPT_ERROR, "Unknown stroke geometry modifier type"); return OPERATOR_CANCELLED; @@ -1060,8 +1079,7 @@ static int freestyle_modifier_remove_exec(bContext *C, wmOperator *op) PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier); LineStyleModifier *modifier = ptr.data; - if (!lineset) { - BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style the modifier belongs to"); + if (!freestyle_linestyle_check_report(lineset, op->reports)) { return OPERATOR_CANCELLED; } @@ -1110,8 +1128,7 @@ static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op) PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier); LineStyleModifier *modifier = ptr.data; - if (!lineset) { - BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style the modifier belongs to"); + if (!freestyle_linestyle_check_report(lineset, op->reports)) { return OPERATOR_CANCELLED; } @@ -1161,8 +1178,7 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op) LineStyleModifier *modifier = ptr.data; int dir = RNA_enum_get(op->ptr, "direction"); - if (!lineset) { - BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style the modifier belongs to"); + if (!freestyle_linestyle_check_report(lineset, op->reports)) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index e805b3f30fc..fccce0357a4 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1446,7 +1446,6 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type) } if (sl) { - /* swap regions */ slold->regionbase = sa->regionbase; sa->regionbase = sl->regionbase; @@ -1696,8 +1695,10 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char * /* Note: this code scales fine, but because of rounding differences, positions of elements * flip +1 or -1 pixel compared to redoing the entire layout again. * Leaving in commented code for future tests */ - /* uiScalePanels(ar, BLI_rctf_size_x(&v2d->cur)); - break; */ +#if 0 + uiScalePanels(ar, BLI_rctf_size_x(&v2d->cur)); + break; +#endif } else { break; @@ -1806,7 +1807,7 @@ void ED_region_header_init(ARegion *ar) /* UI_UNIT_Y is defined as U variable now, depending dpi */ int ED_area_headersize(void) { - return (int)(1.3f * UI_UNIT_Y); + return (int)(HEADERY * UI_DPI_FAC); } void ED_region_info_draw(ARegion *ar, const char *text, int block, float fill_color[4]) diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 723dce5e226..70e5aab6628 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -1091,15 +1091,18 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter, if (ibuf->rect_float) { if (ibuf->float_colorspace) { ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, - ibuf->float_colorspace, TRUE); + ibuf->float_colorspace, + true, false); } else { - ok = IMB_colormanagement_setup_glsl_draw(view_settings, display_settings, TRUE); + ok = IMB_colormanagement_setup_glsl_draw(view_settings, display_settings, + true, false); } } else { ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, - ibuf->rect_colorspace, FALSE); + ibuf->rect_colorspace, + false, false); } if (ok) { @@ -1157,57 +1160,3 @@ void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int glaDrawImBuf_glsl(ibuf, x, y, zoomfilter, view_settings, display_settings); } - -/* Transform buffer from role to scene linear space using GLSL OCIO conversion - * - * See IMB_colormanagement_setup_transform_from_role_glsl description for - * some more details - * - * NOTE: this only works for RGBA buffers! - */ -int glaBufferTransformFromRole_glsl(float *buffer, int width, int height, int role) -{ - GPUOffScreen *ofs; - char err_out[256]; - rcti display_rect; - - ofs = GPU_offscreen_create(width, height, err_out); - - if (!ofs) - return FALSE; - - GPU_offscreen_bind(ofs); - - if (!IMB_colormanagement_setup_transform_from_role_glsl(role, TRUE)) { - GPU_offscreen_unbind(ofs); - GPU_offscreen_free(ofs); - return FALSE; - } - - BLI_rcti_init(&display_rect, 0, width, 0, height); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - - glaDefine2DArea(&display_rect); - - glaDrawPixelsTex(0, 0, width, height, GL_RGBA, GL_FLOAT, - GL_NEAREST, buffer); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - GPU_offscreen_read_pixels(ofs, GL_FLOAT, buffer); - - IMB_colormanagement_finish_glsl_transform(); - - /* unbind */ - GPU_offscreen_unbind(ofs); - GPU_offscreen_free(ofs); - - return TRUE; -} diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 498762f1603..356db174c2f 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -327,10 +327,12 @@ static void screen_delarea(bContext *C, bScreen *sc, ScrArea *sa) static short testsplitpoint(ScrArea *sa, char dir, float fac) { short x, y; + const short area_min_x = AREAMINX; + const short area_min_y = ED_area_headersize(); // area big enough? - if (dir == 'v' && (sa->v4->vec.x - sa->v1->vec.x <= 2 * AREAMINX)) return 0; - if (dir == 'h' && (sa->v2->vec.y - sa->v1->vec.y <= 2 * AREAMINY)) return 0; + if (dir == 'v' && (sa->v4->vec.x - sa->v1->vec.x <= 2 * area_min_x)) return 0; + if (dir == 'h' && (sa->v2->vec.y - sa->v1->vec.y <= 2 * area_min_y)) return 0; // to be sure CLAMP(fac, 0.0f, 1.0f); @@ -338,10 +340,10 @@ static short testsplitpoint(ScrArea *sa, char dir, float fac) if (dir == 'h') { y = sa->v1->vec.y + fac * (sa->v2->vec.y - sa->v1->vec.y); - if (y - sa->v1->vec.y < AREAMINY) - y = sa->v1->vec.y + AREAMINY; - else if (sa->v2->vec.y - y < AREAMINY) - y = sa->v2->vec.y - AREAMINY; + if (y - sa->v1->vec.y < area_min_y) + y = sa->v1->vec.y + area_min_y; + else if (sa->v2->vec.y - y < area_min_y) + y = sa->v2->vec.y - area_min_y; else y -= (y % AREAGRID); return y; @@ -349,10 +351,10 @@ static short testsplitpoint(ScrArea *sa, char dir, float fac) else { x = sa->v1->vec.x + fac * (sa->v4->vec.x - sa->v1->vec.x); - if (x - sa->v1->vec.x < AREAMINX) - x = sa->v1->vec.x + AREAMINX; - else if (sa->v4->vec.x - x < AREAMINX) - x = sa->v4->vec.x - AREAMINX; + if (x - sa->v1->vec.x < area_min_x) + x = sa->v1->vec.x + area_min_x; + else if (sa->v4->vec.x - x < area_min_x) + x = sa->v4->vec.x - area_min_x; else x -= (x % AREAGRID); return x; @@ -1007,8 +1009,6 @@ void ED_screen_do_listen(bContext *C, wmNotifier *note) win->screen->do_draw = TRUE; break; case NC_SCREEN: - if (note->data == ND_SUBWINACTIVE) - uiFreeActiveButtons(C, win->screen); if (note->action == NA_EDITED) win->screen->do_draw = win->screen->do_refresh = TRUE; break; @@ -1333,7 +1333,11 @@ void ED_screen_set_subwinactive(bContext *C, wmEvent *event) /* notifier invokes freeing the buttons... causing a bit too much redraws */ if (oldswin != scr->subwinactive) { region_cursor_set(win, scr->subwinactive, TRUE); - WM_event_add_notifier(C, NC_SCREEN | ND_SUBWINACTIVE, scr); + + /* this used to be a notifier, but needs to be done immediate + * because it can undo setting the right button as active due + * to delayed notifier handling */ + uiFreeActiveButtons(C, win->screen); } else region_cursor_set(win, scr->subwinactive, FALSE); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 3066b733fc5..fbdd90312dd 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -696,28 +696,39 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) { sActionzoneData *sad = op->customdata; - int deltax, deltay; - int mindelta = sad->az->type == AZONE_REGION ? 1 : 12; switch (event->type) { case MOUSEMOVE: + { + bool is_gesture; + + const int delta_x = (event->x - sad->x); + const int delta_y = (event->y - sad->y); + /* calculate gesture direction */ - deltax = (event->x - sad->x); - deltay = (event->y - sad->y); - - if (deltay > ABS(deltax)) + if (delta_y > ABS(delta_x)) sad->gesture_dir = 'n'; - else if (deltax > ABS(deltay)) + else if (delta_x > ABS(delta_y)) sad->gesture_dir = 'e'; - else if (deltay < -ABS(deltax)) + else if (delta_y < -ABS(delta_x)) sad->gesture_dir = 's'; else sad->gesture_dir = 'w'; + if (sad->az->type == AZONE_AREA) { + /* once we drag outside the actionzone, register a gesture + * check we're not on an edge so join finds the other area */ + is_gesture = ((is_in_area_actionzone(sad->sa1, &event->x) != sad->az) && + (screen_find_active_scredge(CTX_wm_screen(C), event->x, event->y) == NULL)); + } + else { + const int delta_min = 1; + is_gesture = (ABS(delta_x) > delta_min || ABS(delta_y) > delta_min); + } + /* gesture is large enough? */ - if (ABS(deltax) > mindelta || ABS(deltay) > mindelta) { - - /* second area, for join */ + if (is_gesture) { + /* second area, for join when (sa1 != sa2) */ sad->sa2 = screen_areahascursor(CTX_wm_screen(C), event->x, event->y); /* apply sends event */ actionzone_apply(C, op, sad->az->type); @@ -726,6 +737,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_FINISHED; } break; + } case ESCKEY: actionzone_exit(op); return OPERATOR_CANCELLED; @@ -807,7 +819,7 @@ static int area_swap_init(wmOperator *op, const wmEvent *event) static void area_swap_exit(bContext *C, wmOperator *op) { - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); if (op->customdata) MEM_freeN(op->customdata); op->customdata = NULL; @@ -826,7 +838,7 @@ static int area_swap_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_PASS_THROUGH; /* add modal handler */ - WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR); + WM_cursor_modal_set(CTX_wm_window(C), BC_SWAPAREA_CURSOR); WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; @@ -1396,7 +1408,7 @@ static void area_split_exit(bContext *C, wmOperator *op) op->customdata = NULL; } - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); /* this makes sure aligned edges will result in aligned grabbing */ @@ -3928,9 +3940,11 @@ void ED_keymap_screen(wmKeyConfig *keyconf) /* render */ - WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "use_viewport", TRUE); kmi = WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "animation", TRUE); + RNA_boolean_set(kmi->ptr, "use_viewport", TRUE); WM_keymap_add_item(keymap, "RENDER_OT_view_cancel", ESCKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "RENDER_OT_view_show", F11KEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "RENDER_OT_play_rendered_anim", F11KEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index 584d4cef133..dbe1197436b 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -77,6 +77,18 @@ typedef struct ScreenshotData { ImageFormatData im_format; } ScreenshotData; +static void screenshot_read_pixels(int x, int y, int w, int h, unsigned char *rect) +{ + int i; + + glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect); + glFinish(); + + /* clear alpha, it is not set to a meaningful value in opengl */ + for (i = 0, rect += 3; i < w * h; i++, rect += 4) + *rect = 255; +} + /* get shot from frontbuffer */ static unsigned int *screenshot(bContext *C, int *dumpsx, int *dumpsy) { @@ -93,8 +105,7 @@ static unsigned int *screenshot(bContext *C, int *dumpsx, int *dumpsy) dumprect = MEM_mallocN(sizeof(int) * (*dumpsx) * (*dumpsy), "dumprect"); glReadBuffer(GL_FRONT); - glReadPixels(x, y, *dumpsx, *dumpsy, GL_RGBA, GL_UNSIGNED_BYTE, dumprect); - glFinish(); + screenshot_read_pixels(x, y, *dumpsx, *dumpsy, (unsigned char*)dumprect); glReadBuffer(GL_BACK); } @@ -316,8 +327,7 @@ static void screenshot_updatejob(void *sjv) if (sj->dumprect == NULL) { dumprect = MEM_mallocN(sizeof(int) * sj->dumpsx * sj->dumpsy, "dumprect"); - glReadPixels(sj->x, sj->y, sj->dumpsx, sj->dumpsy, GL_RGBA, GL_UNSIGNED_BYTE, dumprect); - glFinish(); + screenshot_read_pixels(sj->x, sj->y, sj->dumpsx, sj->dumpsy, (unsigned char *)dumprect); sj->dumprect = dumprect; } diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 2c1f5b620c4..c18afd066fa 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -643,21 +643,17 @@ static void paint_draw_cursor_overlay(UnifiedPaintSettings *ups, Brush *brush, } if (load_tex_cursor(brush, vc, zoom)) { + bool do_pop = false; + float center[2]; glEnable(GL_BLEND); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDepthMask(GL_FALSE); glDepthFunc(GL_ALWAYS); - /* scale based on tablet pressure */ - if (ups->draw_pressure && BKE_brush_use_size_pressure(vc->scene, brush)) { - glTranslatef(0.5f, 0.5f, 0); - glScalef(1.0f / ups->pressure_value, 1.0f / ups->pressure_value, 1); - glTranslatef(-0.5f, -0.5f, 0); - } - if (ups->draw_anchored) { const float *aim = ups->anchored_initial_mouse; + copy_v2_v2(center, aim); quad.xmin = aim[0] - ups->anchored_size; quad.ymin = aim[1] - ups->anchored_size; quad.xmax = aim[0] + ups->anchored_size; @@ -665,12 +661,25 @@ static void paint_draw_cursor_overlay(UnifiedPaintSettings *ups, Brush *brush, } else { const int radius = BKE_brush_size_get(vc->scene, brush) * zoom; + center[0] = x; + center[1] = y; + quad.xmin = x - radius; quad.ymin = y - radius; quad.xmax = x + radius; quad.ymax = y + radius; } + /* scale based on tablet pressure */ + if (ups->draw_pressure && BKE_brush_use_size_pressure(vc->scene, brush)) { + do_pop = true; + glPushMatrix(); + glLoadIdentity(); + glTranslatef(center[0], center[1], 0); + glScalef(ups->pressure_value, ups->pressure_value, 1); + glTranslatef(-center[0], -center[1], 0); + } + glColor4f(U.sculpt_paint_overlay_col[0], U.sculpt_paint_overlay_col[1], U.sculpt_paint_overlay_col[2], @@ -687,6 +696,9 @@ static void paint_draw_cursor_overlay(UnifiedPaintSettings *ups, Brush *brush, glTexCoord2f(0, 1); glVertex2f(quad.xmin, quad.ymax); glEnd(); + + if (do_pop) + glPopMatrix(); } } diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index db6380e920f..345db7a0ed0 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -71,18 +71,6 @@ #include <assert.h> -static int planes_contain_v3(float (*planes)[4], int totplane, const float p[3]) -{ - int i; - - for (i = 0; i < totplane; i++) { - if (dot_v3v3(planes[i], p) + planes[i][3] > 0) - return 0; - } - - return 1; -} - /* return true if the element should be hidden/shown */ static int is_effected(PartialVisArea area, float planes[4][4], @@ -95,7 +83,7 @@ static int is_effected(PartialVisArea area, return mask > 0.5f; } else { - int inside = planes_contain_v3(planes, 4, co); + bool inside = isect_point_planes_v3(planes, 4, co); return ((inside && area == PARTIALVIS_INSIDE) || (!inside && area == PARTIALVIS_OUTSIDE)); } @@ -235,20 +223,20 @@ static void partialvis_update_grids(Object *ob, } static void partialvis_update_bmesh_verts(BMesh *bm, - GHash *verts, - PartialVisAction action, - PartialVisArea area, - float planes[4][4], - int *any_changed, - int *any_visible) + GSet *verts, + PartialVisAction action, + PartialVisArea area, + float planes[4][4], + int *any_changed, + int *any_visible) { - GHashIterator gh_iter; + GSetIterator gs_iter; - GHASH_ITER (gh_iter, verts) { - BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + GSET_ITER (gs_iter, verts) { + BMVert *v = BLI_gsetIterator_getKey(&gs_iter); float *vmask = CustomData_bmesh_get(&bm->vdata, - v->head.data, - CD_PAINT_MASK); + v->head.data, + CD_PAINT_MASK); /* hide vertex if in the hide volume */ if (is_effected(area, planes, v->co, *vmask)) { @@ -272,7 +260,7 @@ static void partialvis_update_bmesh(Object *ob, float planes[4][4]) { BMesh *bm; - GHash *unique, *other; + GSet *unique, *other; int any_changed = 0, any_visible = 0; bm = BKE_pbvh_get_bmesh(pbvh); diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index fcf00d4ab2c..910a49a8f7d 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -82,6 +82,7 @@ #include "UI_view2d.h" #include "ED_image.h" +#include "ED_object.h" #include "ED_screen.h" #include "ED_sculpt.h" #include "ED_uvedit.h" @@ -962,24 +963,9 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_RUNNING_MODAL; } -/* same as image_paint_poll but fail when face mask mode is enabled */ -static int image_paint_sample_color_poll(bContext *C) +static int sample_color_poll(bContext *C) { - if (image_paint_poll(C)) { - if (CTX_wm_view3d(C)) { - Object *obact = CTX_data_active_object(C); - if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { - Mesh *me = BKE_mesh_from_object(obact); - if (me) { - return !(me->editflag & ME_EDIT_PAINT_FACE_SEL); - } - } - } - - return 1; - } - - return 0; + return (image_paint_poll(C) || vertex_paint_poll(C)); } void PAINT_OT_sample_color(wmOperatorType *ot) @@ -993,7 +979,7 @@ void PAINT_OT_sample_color(wmOperatorType *ot) ot->exec = sample_color_exec; ot->invoke = sample_color_invoke; ot->modal = sample_color_modal; - ot->poll = image_paint_sample_color_poll; + ot->poll = sample_color_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1006,9 +992,12 @@ void PAINT_OT_sample_color(wmOperatorType *ot) static int texture_paint_toggle_poll(bContext *C) { - if (CTX_data_edit_object(C)) + Object *ob = CTX_data_active_object(C); + if (ob == NULL || ob->type != OB_MESH) return 0; - if (CTX_data_active_object(C) == NULL) + if (!ob->data || ((ID *)ob->data)->lib) + return 0; + if (CTX_data_edit_object(C)) return 0; return 1; @@ -1018,25 +1007,20 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - Mesh *me = NULL; - - if (ob == NULL) - return OPERATOR_CANCELLED; - - if (BKE_object_obdata_is_libdata(ob)) { - BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata"); - return OPERATOR_CANCELLED; + const int mode_flag = OB_MODE_TEXTURE_PAINT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; + Mesh *me; + + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } } me = BKE_mesh_from_object(ob); - if (!(ob->mode & OB_MODE_TEXTURE_PAINT) && !me) { - BKE_report(op->reports, RPT_ERROR, "Can only enter texture paint mode for mesh objects"); - return OPERATOR_CANCELLED; - } - - if (ob->mode & OB_MODE_TEXTURE_PAINT) { - ob->mode &= ~OB_MODE_TEXTURE_PAINT; + if (ob->mode & mode_flag) { + ob->mode &= ~mode_flag; if (U.glreslimit != 0) GPU_free_images(); @@ -1045,7 +1029,7 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) toggle_paint_cursor(C, 0); } else { - ob->mode |= OB_MODE_TEXTURE_PAINT; + ob->mode |= mode_flag; if (me->mtface == NULL) me->mtface = CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT, diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index db55dc271f1..c90f9756707 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -3883,7 +3883,7 @@ static void *do_projectpaint_thread(void *ph_v) float mask = ((float)projPixel->mask) * (1.0f / 65535.0f); straight_uchar_to_premul_float(newColor_f, projPixel->newColor.ch); - IMB_colormanagement_colorspace_to_scene_linear_v4(newColor_f, TRUE, ps->reproject_ibuf->rect_colorspace); + IMB_colormanagement_colorspace_to_scene_linear_v4(newColor_f, true, ps->reproject_ibuf->rect_colorspace); mul_v4_v4fl(newColor_f, newColor_f, mask); blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, @@ -4164,7 +4164,7 @@ void paint_proj_stroke(bContext *C, void *pps, const float prev_pos[2], const fl view3d_operator_needs_opengl(C); - if (!ED_view3d_autodist(scene, ps->ar, v3d, mval_i, cursor, false)) + if (!ED_view3d_autodist(scene, ps->ar, v3d, mval_i, cursor, false, NULL)) return; ED_region_tag_redraw(ps->ar); @@ -4279,9 +4279,6 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m return ps; } - /* needed so multiple threads don't try to initialize the brush at once (can leak memory) */ - curvemapping_initialize(ps->brush->curve); - paint_brush_init_tex(ps->brush); ps->source = PROJ_SRC_VIEW; diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index bdf542526ee..0b0607babc1 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -1011,7 +1011,8 @@ typedef enum { RC_COLOR = 1, RC_ROTATION = 2, RC_ZOOM = 4, - RC_WEIGHT = 8 + RC_WEIGHT = 8, + RC_SECONDARY_ROTATION = 16 } RCFlags; static void set_brush_rc_path(PointerRNA *ptr, const char *brush_path, @@ -1043,7 +1044,10 @@ static void set_brush_rc_props(PointerRNA *ptr, const char *paint, RNA_string_set(ptr, "data_path_secondary", ""); } set_brush_rc_path(ptr, brush_path, "color_path", "cursor_color_add"); - set_brush_rc_path(ptr, brush_path, "rotation_path", "texture_slot.angle"); + if (flags & RC_SECONDARY_ROTATION) + set_brush_rc_path(ptr, brush_path, "rotation_path", "mask_texture_slot.angle"); + else + set_brush_rc_path(ptr, brush_path, "rotation_path", "texture_slot.angle"); RNA_string_set(ptr, "image_id", brush_path); if (flags & RC_COLOR) @@ -1055,6 +1059,11 @@ static void set_brush_rc_props(PointerRNA *ptr, const char *paint, else RNA_string_set(ptr, "zoom_path", ""); + if (flags & RC_SECONDARY_ROTATION) + RNA_boolean_set(ptr, "secondary_tex", true); + else + RNA_boolean_set(ptr, "secondary_tex", false); + MEM_freeN(brush_path); } @@ -1064,6 +1073,7 @@ static void ed_keymap_paint_brush_radial_control(wmKeyMap *keymap, const char *p wmKeyMapItem *kmi; /* only size needs to follow zoom, strength shows fixed size circle */ int flags_nozoom = flags & (~RC_ZOOM); + int flags_noradial_secondary = flags & (~(RC_SECONDARY_ROTATION | RC_ZOOM)); kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0); set_brush_rc_props(kmi->ptr, paint, "size", "use_unified_size", flags); @@ -1078,7 +1088,12 @@ static void ed_keymap_paint_brush_radial_control(wmKeyMap *keymap, const char *p if (flags & RC_ROTATION) { kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0); - set_brush_rc_props(kmi->ptr, paint, "texture_slot.angle", NULL, flags_nozoom); + set_brush_rc_props(kmi->ptr, paint, "texture_slot.angle", NULL, flags_noradial_secondary); + } + + if (flags & RC_SECONDARY_ROTATION) { + kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); + set_brush_rc_props(kmi->ptr, paint, "mask_texture_slot.angle", NULL, flags_nozoom); } } @@ -1265,7 +1280,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) ed_keymap_paint_brush_switch(keymap, "image_paint"); ed_keymap_paint_brush_size(keymap, "tool_settings.image_paint.brush.size"); - ed_keymap_paint_brush_radial_control(keymap, "image_paint", RC_COLOR | RC_ZOOM | RC_ROTATION); + ed_keymap_paint_brush_radial_control(keymap, "image_paint", RC_COLOR | RC_ZOOM | RC_ROTATION | RC_SECONDARY_ROTATION); ed_keymap_stencil(keymap); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 36e1b1feb38..973f6555deb 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -46,6 +46,7 @@ #include "BKE_context.h" #include "BKE_paint.h" #include "BKE_brush.h" +#include "BKE_colortools.h" #include "WM_api.h" #include "WM_types.h" @@ -184,7 +185,8 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode, 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_RANDOM)) && + (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA) || + (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)) && !(brush->flag & BRUSH_RAKE)) { if (brush->flag & BRUSH_RANDOM_ROTATION) @@ -477,6 +479,9 @@ PaintStroke *paint_stroke_new(bContext *C, stroke->redraw = redraw; stroke->done = done; stroke->event_type = event_type; /* for modal, return event */ + + /* initialize here to avoid initialization conflict with threaded strokes */ + curvemapping_initialize(br->curve); BKE_paint_set_overlay_override(br->overlay_flags); diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c index e406d4f5c3b..50a79005ee3 100644 --- a/source/blender/editors/sculpt_paint/paint_undo.c +++ b/source/blender/editors/sculpt_paint/paint_undo.c @@ -124,6 +124,30 @@ static void undo_stack_push_end(UndoStack *stack) { UndoElem *uel; uintptr_t totmem, maxmem; + int totundo = 0; + + /* first limit to undo steps */ + uel = stack->elems.last; + + while (uel) { + totundo++; + if (totundo > U.undosteps) break; + uel = uel->prev; + } + + if (uel) { + UndoElem *first; + + /* in case the undo steps are zero, the current pointer will be invalid */ + if (uel == stack->current) + stack->current = NULL; + + do { + first = stack->elems.first; + undo_elem_free(stack, first); + BLI_freelinkN(&stack->elems, first); + } while (first != uel); + } if (U.undomemory != 0) { /* limit to maximum memory (afterwards, we can't know in advance) */ diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index d376bd3180f..bfc431baea5 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -441,7 +441,7 @@ static int paint_select_linked_pick_invoke(bContext *C, wmOperator *op, const wm void PAINT_OT_face_select_linked_pick(wmOperatorType *ot) { ot->name = "Select Linked Pick"; - ot->description = "Select linked faces"; + ot->description = "Select linked faces under the cursor"; ot->idname = "PAINT_OT_face_select_linked_pick"; ot->invoke = paint_select_linked_pick_invoke; diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 2c654507015..122dbae6129 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -61,6 +61,7 @@ #include "BKE_object_deform.h" #include "BKE_paint.h" #include "BKE_report.h" +#include "BKE_colortools.h" #include "WM_api.h" #include "WM_types.h" @@ -68,12 +69,14 @@ #include "GPU_buffers.h" #include "ED_armature.h" +#include "ED_object.h" #include "ED_mesh.h" #include "ED_screen.h" #include "ED_view3d.h" #include "paint_intern.h" /* own include */ + /* check if we can do partial updates and have them draw realtime * (without rebuilding the 'derivedFinal') */ static int vertex_paint_use_fast_update_check(Object *ob) @@ -916,15 +919,13 @@ static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co co, co_ss, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { - float delta[2]; - float dist_squared; - float factor = 1.0; + const float dist_squared = len_squared_v2v2(mval, co_ss); - sub_v2_v2v2(delta, mval, co_ss); - dist_squared = dot_v2v2(delta, delta); /* len squared */ if (dist_squared <= brush_size_pressure * brush_size_pressure) { Brush *brush = BKE_paint_brush(&vp->paint); const float dist = sqrtf(dist_squared); + float factor; + if (brush->mtex.tex && rgba) { if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) { BKE_brush_sample_tex_3D(vc->scene, brush, co, rgba, 0, NULL); @@ -935,6 +936,9 @@ static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co } factor = rgba[3]; } + else { + factor = 1.0f; + } return factor * BKE_brush_curve_strength_clamp(brush, dist, brush_size_pressure); } } @@ -2025,41 +2029,28 @@ static void do_weight_paint_vertex( /* *************** set wpaint operator ****************** */ -static int wpaint_mode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* toggle */ +/** + * \note Keep in sync with #vpaint_mode_toggle_exec + */ +static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); + const int mode_flag = OB_MODE_WEIGHT_PAINT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; Scene *scene = CTX_data_scene(C); VPaint *wp = scene->toolsettings->wpaint; Mesh *me; - - me = BKE_mesh_from_object(ob); - if (ob->id.lib || me == NULL) return OPERATOR_PASS_THROUGH; - - if (ob->mode & OB_MODE_WEIGHT_PAINT) ob->mode &= ~OB_MODE_WEIGHT_PAINT; - else ob->mode |= OB_MODE_WEIGHT_PAINT; - - - /* Weightpaint works by overriding colors in mesh, - * so need to make sure we recalc on enter and - * exit (exit needs doing regardless because we - * should redeform). - */ - DAG_id_tag_update(&me->id, 0); - - if (ob->mode & OB_MODE_WEIGHT_PAINT) { - if (wp == NULL) - wp = scene->toolsettings->wpaint = new_vpaint(1); - BKE_paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT); - paint_cursor_start(C, weight_paint_poll); - - mesh_octree_table(ob, NULL, NULL, 's'); - - ED_vgroup_sync_from_pose(ob); + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } } - else { - mesh_octree_table(NULL, NULL, NULL, 'e'); - mesh_mirrtopo_table(NULL, 'e'); + + me = BKE_mesh_from_object(ob); + + if (ob->mode & mode_flag) { + ob->mode &= ~mode_flag; if (me->editflag & ME_EDIT_PAINT_VERT_SEL) { BKE_mesh_flush_select_from_verts(me); @@ -2067,10 +2058,35 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* togg else if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { BKE_mesh_flush_select_from_polys(me); } + + /* weight paint spesific */ + mesh_octree_table(NULL, NULL, NULL, 'e'); + mesh_mirrtopo_table(NULL, 'e'); + } + else { + ob->mode |= mode_flag; + + if (wp == NULL) + wp = scene->toolsettings->wpaint = new_vpaint(1); + + paint_cursor_start(C, weight_paint_poll); + + BKE_paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT); + + /* weight paint spesific */ + mesh_octree_table(ob, NULL, NULL, 's'); + ED_vgroup_sync_from_pose(ob); } + /* Weightpaint works by overriding colors in mesh, + * so need to make sure we recalc on enter and + * exit (exit needs doing regardless because we + * should redeform). + */ + DAG_id_tag_update(&me->id, 0); + WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); - + return OPERATOR_FINISHED; } @@ -2078,12 +2094,12 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* togg static int paint_poll_test(bContext *C) { Object *ob = CTX_data_active_object(C); - if (CTX_data_edit_object(C)) - return 0; - if (CTX_data_active_object(C) == NULL) + if (ob == NULL || ob->type != OB_MESH) return 0; if (!ob->data || ((ID *)ob->data)->lib) return 0; + if (CTX_data_edit_object(C)) + return 0; return 1; } @@ -2633,7 +2649,7 @@ void PAINT_OT_weight_set(wmOperatorType *ot) /* api callbacks */ ot->exec = weight_paint_set_exec; - ot->poll = mask_paint_poll; /* it was facemask_paint_poll */ + ot->poll = mask_paint_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2641,40 +2657,41 @@ void PAINT_OT_weight_set(wmOperatorType *ot) /* ************ set / clear vertex paint mode ********** */ - -static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) /* toggle */ +/** + * \note Keep in sync with #wpaint_mode_toggle_exec + */ +static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); + const int mode_flag = OB_MODE_VERTEX_PAINT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; Scene *scene = CTX_data_scene(C); VPaint *vp = scene->toolsettings->vpaint; Mesh *me; - - me = BKE_mesh_from_object(ob); - - if (me == NULL || BKE_object_obdata_is_libdata(ob)) { - ob->mode &= ~OB_MODE_VERTEX_PAINT; - return OPERATOR_PASS_THROUGH; - } - - if (me && me->mloopcol == NULL) { - make_vertexcol(ob); + + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } } + + me = BKE_mesh_from_object(ob); /* toggle: end vpaint */ - if (ob->mode & OB_MODE_VERTEX_PAINT) { - - ob->mode &= ~OB_MODE_VERTEX_PAINT; + if (is_mode_set) { + ob->mode &= ~mode_flag; if (me->editflag & ME_EDIT_PAINT_FACE_SEL) { BKE_mesh_flush_select_from_polys(me); } } else { - ob->mode |= OB_MODE_VERTEX_PAINT; - /* Turn off weight painting */ - if (ob->mode & OB_MODE_WEIGHT_PAINT) - wpaint_mode_toggle_exec(C, op); - + ob->mode |= mode_flag; + + if (me->mloopcol == NULL) { + make_vertexcol(ob); + } + if (vp == NULL) vp = scene->toolsettings->vpaint = new_vpaint(0); @@ -3407,6 +3424,9 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) ToolSettings *ts = CTX_data_tool_settings(C); VPaint *wp = ts->wpaint; struct Brush *brush = BKE_paint_brush(&wp->paint); + + curvemapping_initialize(brush->curve); + data.brush = brush; data.weightpaint = BKE_brush_weight_get(scene, brush); } @@ -3460,7 +3480,7 @@ void PAINT_OT_weight_gradient(wmOperatorType *ot) /* identifiers */ ot->name = "Weight Gradient"; ot->idname = "PAINT_OT_weight_gradient"; - ot->description = "Sample a line and show it in Scope panels"; + ot->description = "Draw a line to apply a weight gradient to selected vertices"; /* api callbacks */ ot->invoke = paint_weight_gradient_invoke; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 2edd00c015d..53357b2616b 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -70,6 +70,7 @@ #include "BKE_node.h" #include "BKE_object.h" #include "BKE_subsurf.h" +#include "BKE_colortools.h" #include "BIF_glutil.h" @@ -77,6 +78,7 @@ #include "WM_types.h" #include "ED_sculpt.h" +#include "ED_object.h" #include "ED_screen.h" #include "ED_view3d.h" #include "ED_util.h" /* for crazyspace correction */ @@ -91,6 +93,7 @@ #include "GPU_buffers.h" #include "bmesh.h" +#include "bmesh_tools.h" #include <math.h> #include <stdlib.h> @@ -150,6 +153,7 @@ MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob) { Mesh *me = (Mesh *)ob->data; ModifierData *md; + VirtualModifierData virtualModifierData; if (ob->sculpt && ob->sculpt->bm) { /* can't combine multires and dynamic topology */ @@ -161,7 +165,7 @@ MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob) return NULL; } - for (md = modifiers_getVirtualModifierList(ob); md; md = md->next) { + for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) { if (md->type == eModifierType_Multires) { MultiresModifierData *mmd = (MultiresModifierData *)md; @@ -180,8 +184,9 @@ MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob) static int sculpt_has_active_modifiers(Scene *scene, Object *ob) { ModifierData *md; + VirtualModifierData virtualModifierData; - md = modifiers_getVirtualModifierList(ob); + md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* exception for shape keys because we can edit those */ for (; md; md = md->next) { @@ -198,6 +203,7 @@ static int sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) ModifierData *md; Mesh *me = (Mesh *)ob->data; MultiresModifierData *mmd = sculpt_multires_active(scene, ob); + VirtualModifierData virtualModifierData; if (mmd || ob->sculpt->bm) return 0; @@ -206,7 +212,7 @@ static int sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr) return 1; - md = modifiers_getVirtualModifierList(ob); + md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* exception for shape keys because we can edit those */ for (; md; md = md->next) { @@ -327,7 +333,7 @@ typedef struct { /* Original coordinate, normal, and mask */ const float *co; float mask; - short no[3]; + const short *no; } SculptOrigVertData; @@ -378,11 +384,10 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data, } if (orig_data->normals) { - copy_v3_v3_short(orig_data->no, orig_data->normals[iter->i]); + orig_data->no = orig_data->normals[iter->i]; } else { - /* TODO: log doesn't store normals yet */ - normal_float_to_short_v3(orig_data->no, iter->bm_vert->no); + orig_data->no = BM_log_original_vert_no(orig_data->bm_log, iter->bm_vert); } } else if (orig_data->unode->type == SCULPT_UNDO_MASK) { @@ -664,10 +669,10 @@ static int sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float loca } } -static float frontface(Brush *brush, const float sculpt_normal[3], +static float frontface(Brush *br, const float sculpt_normal[3], const short no[3], const float fno[3]) { - if (brush->flag & BRUSH_FRONTFACE) { + if (br->flag & BRUSH_FRONTFACE) { float dot; if (no) { @@ -944,7 +949,8 @@ static float tex_strength(SculptSession *ss, Brush *br, const float fno[3], const float mask) { - const Scene *scene = ss->cache->vc->scene; + StrokeCache *cache = ss->cache; + const Scene *scene = cache->vc->scene; MTex *mtex = &br->mtex; float avg = 1; float rgba[4]; @@ -966,12 +972,12 @@ static float tex_strength(SculptSession *ss, Brush *br, * position in order to project it. This insures that the * brush texture will be oriented correctly. */ - flip_v3_v3(symm_point, point, ss->cache->mirror_symmetry_pass); + flip_v3_v3(symm_point, point, cache->mirror_symmetry_pass); - if (ss->cache->radial_symmetry_pass) - mul_m4_v3(ss->cache->symm_rot_mat_inv, symm_point); + if (cache->radial_symmetry_pass) + mul_m4_v3(cache->symm_rot_mat_inv, symm_point); - ED_view3d_project_float_v2_m4(ss->cache->vc->ar, symm_point, point_2d, ss->cache->projection_mat); + ED_view3d_project_float_v2_m4(cache->vc->ar, symm_point, point_2d, cache->projection_mat); /* still no symmetry supported for other paint modes. * Sculpt does it DIY */ @@ -979,7 +985,7 @@ static float tex_strength(SculptSession *ss, Brush *br, /* Similar to fixed mode, but projects from brush angle * rather than view direction */ - mul_m4_v3(ss->cache->brush_local_mat, symm_point); + mul_m4_v3(cache->brush_local_mat, symm_point); x = symm_point[0]; y = symm_point[1]; @@ -1001,7 +1007,7 @@ static float tex_strength(SculptSession *ss, Brush *br, } /* Falloff curve */ - avg *= BKE_brush_curve_strength(br, len, ss->cache->radius); + avg *= BKE_brush_curve_strength(br, len, cache->radius); avg *= frontface(br, sculpt_normal, vno, fno); @@ -1073,8 +1079,9 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], floa static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nodes, int totnode) { - SculptSession *ss = ob->sculpt; float out_flip[3] = {0.0f, 0.0f, 0.0f}; + + SculptSession *ss = ob->sculpt; int n, original; /* Grab brush requires to test on original data (see r33888 and @@ -2274,7 +2281,10 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to SculptSession *ss = ob->sculpt; int n; - float count = 0; + int count = 0; + int count_flip = 0; + + float fc_flip[3] = {0.0, 0.0, 0.0}; (void)sd; /* unused w/o openmp */ @@ -2286,7 +2296,9 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to SculptBrushTest test; SculptUndoNode *unode; float private_fc[3] = {0.0f, 0.0f, 0.0f}; + float private_fc_flip[3] = {0.0f, 0.0f, 0.0f}; int private_count = 0; + int private_count_flip = 0; unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS); sculpt_brush_test_init(ss, &test); @@ -2295,8 +2307,17 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, unode->co[vd.i])) { - add_v3_v3(private_fc, unode->co[vd.i]); - private_count++; + float fno[3]; + + normal_short_to_float_v3(fno, unode->no[vd.i]); + if (dot_v3v3(ss->cache->view_normal, fno) > 0) { + add_v3_v3(private_fc, unode->co[vd.i]); + private_count++; + } + else { + add_v3_v3(private_fc_flip, unode->co[vd.i]); + private_count_flip++; + } } } BKE_pbvh_vertex_iter_end; @@ -2305,8 +2326,31 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, vd.co)) { - add_v3_v3(private_fc, vd.co); - private_count++; + /* for area normal */ + if (vd.no) { + float fno[3]; + + normal_short_to_float_v3(fno, vd.no); + + if (dot_v3v3(ss->cache->view_normal, fno) > 0) { + add_v3_v3(private_fc, vd.co); + private_count++; + } + else { + add_v3_v3(private_fc_flip, vd.co); + private_count_flip++; + } + } + else { + if (dot_v3v3(ss->cache->view_normal, vd.fno) > 0) { + add_v3_v3(private_fc, vd.co); + private_count++; + } + else { + add_v3_v3(private_fc_flip, vd.co); + private_count_flip++; + } + } } } BKE_pbvh_vertex_iter_end; @@ -2315,11 +2359,17 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to #pragma omp critical { add_v3_v3(fc, private_fc); + add_v3_v3(fc_flip, private_fc_flip); count += private_count; + count_flip += private_count_flip; } } - - mul_v3_fl(fc, 1.0f / count); + if (count != 0) + mul_v3_fl(fc, 1.0f / count); + else if (count_flip != 0) + mul_v3_v3fl(fc, fc_flip, 1.0f / count_flip); + else + zero_v3(fc); } /* this calculates flatten center and area normal together, @@ -2333,9 +2383,11 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, /* for area normal */ float out_flip[3] = {0.0f, 0.0f, 0.0f}; + float fc_flip[3] = {0.0f, 0.0f, 0.0f}; /* for flatten center */ - float count = 0; + int count = 0; + int count_flipped = 0; (void)sd; /* unused w/o openmp */ @@ -2353,7 +2405,9 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, float private_an[3] = {0.0f, 0.0f, 0.0f}; float private_out_flip[3] = {0.0f, 0.0f, 0.0f}; float private_fc[3] = {0.0f, 0.0f, 0.0f}; + float private_fc_flip[3] = {0.0f, 0.0f, 0.0f}; int private_count = 0; + int private_count_flip = 0; unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS); sculpt_brush_test_init(ss, &test); @@ -2366,11 +2420,17 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, float fno[3]; normal_short_to_float_v3(fno, unode->no[vd.i]); - add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno); - /* for flatten center */ - add_v3_v3(private_fc, unode->co[vd.i]); - private_count++; + if (dot_v3v3(ss->cache->view_normal, fno) > 0) { + add_v3_v3(private_an, fno); + add_v3_v3(private_fc, unode->co[vd.i]); + private_count++; + } + else { + add_v3_v3(private_out_flip, fno); + add_v3_v3(private_fc_flip, unode->co[vd.i]); + private_count_flip++; + } } } BKE_pbvh_vertex_iter_end; @@ -2384,15 +2444,30 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, float fno[3]; normal_short_to_float_v3(fno, vd.no); - add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno); + + if (dot_v3v3(ss->cache->view_normal, fno) > 0) { + add_v3_v3(private_an, fno); + add_v3_v3(private_fc, vd.co); + private_count++; + } + else { + add_v3_v3(private_out_flip, fno); + add_v3_v3(private_fc_flip, vd.co); + private_count_flip++; + } } else { - add_norm_if(ss->cache->view_normal, private_an, private_out_flip, vd.fno); + if (dot_v3v3(ss->cache->view_normal, vd.fno) > 0) { + add_v3_v3(private_an, vd.fno); + add_v3_v3(private_fc, vd.co); + private_count++; + } + else { + add_v3_v3(private_out_flip, vd.fno); + add_v3_v3(private_fc_flip, vd.co); + private_count_flip++; + } } - - /* for flatten center */ - add_v3_v3(private_fc, vd.co); - private_count++; } } BKE_pbvh_vertex_iter_end; @@ -2406,7 +2481,9 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, /* for flatten center */ add_v3_v3(fc, private_fc); + add_v3_v3(fc_flip, private_fc); count += private_count; + count_flipped += private_count_flip; } } @@ -2417,12 +2494,12 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, normalize_v3(an); /* for flatten center */ - if (count != 0) { + if (count != 0) mul_v3_fl(fc, 1.0f / count); - } - else { + else if (count_flipped != 0) + mul_v3_v3fl(fc, fc_flip, 1.0f / count_flipped); + else zero_v3(fc); - } } static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float an[3], float fc[3]) @@ -3422,7 +3499,7 @@ static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss) /* Need to allocate a bigger buffer for bigger brush size */ ss->texcache_side = 2 * radius; if (!ss->texcache || ss->texcache_side > ss->texcache_actual) { - ss->texcache = BKE_brush_gen_texture_cache(brush, radius); + ss->texcache = BKE_brush_gen_texture_cache(brush, radius, false); ss->texcache_actual = ss->texcache_side; ss->tex_pool = BKE_image_pool_new(); } @@ -3716,16 +3793,28 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio Brush *brush = BKE_paint_brush(&sd->paint); ViewContext *vc = paint_stroke_view_context(op->customdata); Object *ob = CTX_data_active_object(C); - float rot[3][3], scale[3], loc[3]; + float mat[3][3]; + float viewDir[3] = {0.0f, 0.0f, 1.0f}; + float max_scale; int i; int mode; ss->cache = cache; /* Set scaling adjustment */ - cache->scale[0] = 1.0f / ob->size[0]; - cache->scale[1] = 1.0f / ob->size[1]; - cache->scale[2] = 1.0f / ob->size[2]; + if (brush->sculpt_tool == SCULPT_TOOL_LAYER) { + max_scale = 1.0f; + } + else { + max_scale = 0.0f; + for (i = 0; i < 3; i ++) { + max_scale = max_ff(max_scale, fabsf(ob->size[i])); + } + } + cache->scale[0] = max_scale / ob->size[0]; + cache->scale[1] = max_scale / ob->size[1]; + cache->scale[2] = max_scale / ob->size[2]; + cache->plane_trim_squared = brush->plane_trim * brush->plane_trim; @@ -3768,6 +3857,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio brush = br; cache->saved_smooth_size = BKE_brush_size_get(scene, brush); BKE_brush_size_set(scene, brush, size); + curvemapping_initialize(brush->curve); } } } @@ -3784,12 +3874,13 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio /* cache projection matrix */ ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat); - mat4_to_loc_rot_size(loc, rot, scale, ob->obmat); - /* transposing an orthonormal matrix inverts */ - transpose_m3(rot); - ED_view3d_global_to_vector(cache->vc->rv3d, cache->vc->rv3d->twmat[3], cache->true_view_normal); - /* This takes care of rotated mesh. Instead of rotating every normal, we inverse rotate view normal. */ - mul_m3_v3(rot, cache->true_view_normal); + invert_m4_m4(ob->imat, ob->obmat); + copy_m3_m4(mat, cache->vc->rv3d->viewinv); + mul_m3_v3(mat, viewDir); + copy_m3_m4(mat, ob->imat); + mul_m3_v3(mat, viewDir); + normalize_v3_v3(cache->true_view_normal, viewDir); + /* Initialize layer brush displacements and persistent coords */ if (brush->sculpt_tool == SCULPT_TOOL_LAYER) { /* not supported yet for multires or dynamic topology */ @@ -3823,10 +3914,10 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio cache->original = 1; } - if (ELEM8(brush->sculpt_tool, + if (ELEM9(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB, SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, - SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_ROTATE)) + SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_ROTATE, SCULPT_TOOL_FLATTEN)) { if (!(brush->flag & BRUSH_ACCUMULATE)) { cache->original = 1; @@ -4561,7 +4652,9 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot) static void sculpt_dynamic_topology_triangulate(BMesh *bm) { - BM_mesh_triangulate(bm, false, false, NULL, NULL); + if (bm->totloop != bm->totface * 3) { + BM_mesh_triangulate(bm, false, false, NULL, NULL); + } } void sculpt_pbvh_clear(Object *ob) @@ -4595,10 +4688,7 @@ void sculpt_dynamic_topology_enable(bContext *C) Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; Mesh *me = ob->data; - const BMAllocTemplate allocsize = {me->totvert, - me->totedge, - me->totloop, - me->totpoly}; + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me); sculpt_pbvh_clear(ob); @@ -4800,8 +4890,8 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op)) /* Symmetrize and re-triangulate */ BMO_op_callf(ss->bm, BMO_FLAG_DEFAULTS, - "symmetrize input=%avef direction=%i", - sd->symmetrize_direction); + "symmetrize input=%avef direction=%i dist=%f", + sd->symmetrize_direction, 0.00001f); sculpt_dynamic_topology_triangulate(ss->bm); /* Finish undo */ @@ -4849,7 +4939,7 @@ int ED_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) if (mmd && !CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) { GridPaintMask *gmask; int level = max_ii(1, mmd->sculptlvl); - int gridsize = ccg_gridsize(level); + int gridsize = BKE_ccg_gridsize(level); int gridarea = gridsize * gridsize; int i, j; @@ -4907,21 +4997,31 @@ int ED_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) return ret; } -static int sculpt_mode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) +static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); - Mesh *me = ob->data; + const int mode_flag = OB_MODE_SCULPT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; + Mesh *me; MultiresModifierData *mmd = sculpt_multires_active(scene, ob); int flush_recalc = 0; + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } + } + + me = BKE_mesh_from_object(ob); + /* multires in sculpt mode could have different from object mode subdivision level */ flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl; /* if object has got active modifiers, it's dm could be different in sculpt mode */ flush_recalc |= sculpt_has_active_modifiers(scene, ob); - if (ob->mode & OB_MODE_SCULPT) { + if (is_mode_set) { if (mmd) multires_force_update(ob); @@ -4936,13 +5036,13 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) } /* Leave sculptmode */ - ob->mode &= ~OB_MODE_SCULPT; + ob->mode &= ~mode_flag; free_sculptsession(ob); } else { /* Enter sculptmode */ - ob->mode |= OB_MODE_SCULPT; + ob->mode |= mode_flag; /* Remove dynamic-topology flag; this will be enabled if the * file was saved with dynamic topology on, but we don't diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index 9c73d4d9477..7a973d8c1ae 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -45,6 +45,7 @@ #include "BKE_brush.h" #include "BKE_paint.h" +#include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_main.h" #include "BKE_depsgraph.h" @@ -538,6 +539,8 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm op->customdata = data; + curvemapping_initialize(ts->uvsculpt->paint.brush->curve); + if (data) { int counter = 0, i; ARegion *ar = CTX_wm_region(C); @@ -662,6 +665,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { int offset1, itmp1 = uv_element_offset_from_face_get(data->elementMap, efa, l, island_index, do_island_optimization); int offset2, itmp2 = uv_element_offset_from_face_get(data->elementMap, efa, l->next, island_index, do_island_optimization); + char *flag; /* Skip edge if not found(unlikely) or not on valid island */ if (itmp1 == -1 || itmp2 == -1) @@ -682,8 +686,8 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm edges[counter].uv2 = offset1; } /* Hack! Set the value of the key to its flag. Now we can set the flag when an edge exists twice :) */ - if (BLI_ghash_haskey(edgeHash, &edges[counter])) { - char *flag = BLI_ghash_lookup(edgeHash, &edges[counter]); + flag = BLI_ghash_lookup(edgeHash, &edges[counter]); + if (flag) { *flag = 1; } else { diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 51e740e539f..8508123f942 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -150,20 +150,31 @@ static void set_texture_context(const bContext *C, SpaceButs *sbuts) bool valid_particles = ED_texture_context_check_particles(C); bool valid_others = ED_texture_context_check_others(C); + /* this is similar to direct user action, no need to keep "better" ctxt in _prev */ if ((sbuts->mainb == BCONTEXT_WORLD) && valid_world) { - sbuts->texture_context = SB_TEXC_WORLD; + sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_WORLD; } else if ((sbuts->mainb == BCONTEXT_MATERIAL) && valid_material) { - sbuts->texture_context = SB_TEXC_MATERIAL; + sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_MATERIAL; } else if ((sbuts->mainb == BCONTEXT_DATA) && valid_lamp) { - sbuts->texture_context = SB_TEXC_LAMP; + sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_LAMP; } else if ((sbuts->mainb == BCONTEXT_PARTICLE) && valid_particles) { - sbuts->texture_context = SB_TEXC_PARTICLES; + sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_PARTICLES; } else if ((ELEM(sbuts->mainb, BCONTEXT_MODIFIER, BCONTEXT_PHYSICS)) && valid_others) { - sbuts->texture_context = SB_TEXC_OTHER; + sbuts->texture_context = sbuts->texture_context_prev = SB_TEXC_OTHER; + } + /* Else, try to revive a previous "better" ctxt... */ + else if ((sbuts->texture_context_prev != sbuts->texture_context) && + (((sbuts->texture_context_prev == SB_TEXC_WORLD) && valid_world) || + ((sbuts->texture_context_prev == SB_TEXC_MATERIAL) && valid_material) || + ((sbuts->texture_context_prev == SB_TEXC_LAMP) && valid_lamp) || + ((sbuts->texture_context_prev == SB_TEXC_PARTICLES) && valid_particles) || + ((sbuts->texture_context_prev == SB_TEXC_OTHER) && valid_others))) + { + sbuts->texture_context = sbuts->texture_context_prev; } /* Else, just be sure that current context is valid! */ else if (((sbuts->texture_context == SB_TEXC_WORLD) && !valid_world) || @@ -172,13 +183,9 @@ static void set_texture_context(const bContext *C, SpaceButs *sbuts) ((sbuts->texture_context == SB_TEXC_PARTICLES) && !valid_particles) || ((sbuts->texture_context == SB_TEXC_OTHER) && !valid_others)) { - if (valid_others) { - sbuts->texture_context = SB_TEXC_OTHER; - } - else if (valid_world) { - sbuts->texture_context = SB_TEXC_WORLD; - } - else if (valid_material) { + /* this is default fallback, do keep "better" ctxt in _prev */ + sbuts->texture_context_prev = sbuts->texture_context; + if (valid_material) { sbuts->texture_context = SB_TEXC_MATERIAL; } else if (valid_lamp) { @@ -187,6 +194,12 @@ static void set_texture_context(const bContext *C, SpaceButs *sbuts) else if (valid_particles) { sbuts->texture_context = SB_TEXC_PARTICLES; } + else if (valid_world) { + sbuts->texture_context = SB_TEXC_WORLD; + } + else if (valid_others) { + sbuts->texture_context = SB_TEXC_OTHER; + } } } } diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index 18248f4775b..50bb8a0e061 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -238,7 +238,8 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) { MarkerUpdateCb *cb = (MarkerUpdateCb *) arg_cb; MovieTrackingMarker *marker; - int width, height, ok = FALSE; + int width, height; + bool ok = false; BKE_movieclip_get_size(cb->clip, cb->user, &width, &height); @@ -252,7 +253,7 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) DAG_id_tag_update(&cb->clip->id, 0); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); - ok = TRUE; + ok = true; } else if (event == B_MARKER_PAT_DIM) { float dim[2], pat_dim[2], pat_min[2], pat_max[2]; @@ -276,7 +277,7 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) BKE_tracking_marker_clamp(cb->marker, CLAMP_PAT_DIM); - ok = TRUE; + ok = true; } else if (event == B_MARKER_SEARCH_POS) { float delta[2], side[2]; @@ -292,7 +293,7 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) BKE_tracking_marker_clamp(cb->marker, CLAMP_SEARCH_POS); - ok = TRUE; + ok = true; } else if (event == B_MARKER_SEARCH_DIM) { float dim[2], search_dim[2]; @@ -313,12 +314,12 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) BKE_tracking_marker_clamp(cb->marker, CLAMP_SEARCH_DIM); - ok = TRUE; + ok = true; } else if (event == B_MARKER_FLAG) { marker->flag = cb->marker_flag; - ok = TRUE; + ok = true; } else if (event == B_MARKER_OFFSET) { float offset[2], delta[2]; @@ -337,7 +338,7 @@ static void marker_block_handler(bContext *C, void *arg_cb, int event) DAG_id_tag_update(&cb->clip->id, 0); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); - ok = TRUE; + ok = true; } if (ok) diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index d1fd5093974..3c9eb1fe79e 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -111,6 +111,62 @@ static void draw_keyframe(int frame, int cfra, int sfra, float framelen, int wid } } +static int generic_track_get_markersnr(MovieTrackingTrack *track, MovieTrackingPlaneTrack *plane_track) +{ + if (track) { + return track->markersnr; + } + else if (plane_track) { + return plane_track->markersnr; + } + + return 0; +} + +static int generic_track_get_marker_framenr(MovieTrackingTrack *track, MovieTrackingPlaneTrack *plane_track, + int marker_index) +{ + if (track) { + BLI_assert(marker_index < track->markersnr); + return track->markers[marker_index].framenr; + } + else if (plane_track) { + BLI_assert(marker_index < plane_track->markersnr); + return plane_track->markers[marker_index].framenr; + } + + return 0; +} + +static bool generic_track_is_marker_enabled(MovieTrackingTrack *track, MovieTrackingPlaneTrack *plane_track, + int marker_index) +{ + if (track) { + BLI_assert(marker_index < track->markersnr); + return (track->markers[marker_index].flag & MARKER_DISABLED) == 0; + } + else if (plane_track) { + return true; + } + + return false; +} + +static bool generic_track_is_marker_keyframed(MovieTrackingTrack *track, MovieTrackingPlaneTrack *plane_track, + int marker_index) +{ + if (track) { + BLI_assert(marker_index < track->markersnr); + return (track->markers[marker_index].flag & MARKER_TRACKED) == 0; + } + else if (plane_track) { + BLI_assert(marker_index < plane_track->markersnr); + return (plane_track->markers[marker_index].flag & PLANE_MARKER_TRACKED) == 0; + } + + return false; +} + static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Scene *scene) { float x; @@ -119,6 +175,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc MovieTracking *tracking = &clip->tracking; MovieTrackingObject *act_object = BKE_tracking_object_get_active(tracking); MovieTrackingTrack *act_track = BKE_tracking_track_get_active(&clip->tracking); + MovieTrackingPlaneTrack *act_plane_track = BKE_tracking_plane_track_get_active(&clip->tracking); MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking); glEnable(GL_BLEND); @@ -143,34 +200,31 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc } /* track */ - if (act_track) { - MovieTrackingTrack *track = act_track; - + if (act_track || act_plane_track) { for (i = sfra - clip->start_frame + 1, a = 0; i <= efra - clip->start_frame + 1; i++) { int framenr; - MovieTrackingMarker *marker; + int markersnr = generic_track_get_markersnr(act_track, act_plane_track); - while (a < track->markersnr) { - if (track->markers[a].framenr >= i) + while (a < markersnr) { + int marker_framenr = generic_track_get_marker_framenr(act_track, act_plane_track, a); + + if (marker_framenr >= i) break; - if (a < track->markersnr - 1 && track->markers[a + 1].framenr > i) + if (a < markersnr - 1 && generic_track_get_marker_framenr(act_track, act_plane_track, a + 1) > i) break; a++; } - if (a < track->markersnr) - marker = &track->markers[a]; - else - marker = &track->markers[track->markersnr - 1]; + a = min_ii(a, markersnr - 1); - if ((marker->flag & MARKER_DISABLED) == 0) { - framenr = marker->framenr; + if (generic_track_is_marker_enabled(act_track, act_plane_track, a)) { + framenr = generic_track_get_marker_framenr(act_track, act_plane_track, a); if (framenr != i) glColor4ub(128, 128, 0, 96); - else if ((marker->flag & MARKER_TRACKED) == 0) + else if (generic_track_is_marker_keyframed(act_track, act_plane_track, a)) glColor4ub(255, 255, 0, 196); else glColor4ub(255, 255, 0, 96); @@ -188,11 +242,11 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc glColor4ub(255, 0, 0, 96); for (i = sfra, a = 0; i <= efra; i++) { - int ok = FALSE; + bool ok = false; while (a < n) { if (cameras[a].framenr == i) { - ok = TRUE; + ok = true; break; } else if (cameras[a].framenr > i) { @@ -233,11 +287,11 @@ static void draw_movieclip_notes(SpaceClip *sc, ARegion *ar) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; char str[256] = {0}; - int block = FALSE; + bool block = false; if (tracking->stats) { BLI_strncpy(str, tracking->stats->message, sizeof(str)); - block = TRUE; + block = true; } else { if (sc->flag & SC_LOCK_SELECTION) @@ -250,48 +304,52 @@ static void draw_movieclip_notes(SpaceClip *sc, ARegion *ar) } } +static void draw_movieclip_muted(ARegion *ar, int width, int height, float zoomx, float zoomy) +{ + int x, y; + + /* find window pixel coordinates of origin */ + UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y); + + glColor3f(0.0f, 0.0f, 0.0f); + glRectf(x, y, x + zoomx * width, y + zoomy * height); +} + static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, ImBuf *ibuf, int width, int height, float zoomx, float zoomy) { + MovieClip *clip = ED_space_clip_get_clip(sc); + int filter = GL_LINEAR; int x, y; /* find window pixel coordinates of origin */ UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y); - if (sc->flag & SC_MUTE_FOOTAGE) { - glColor3f(0.0f, 0.0f, 0.0f); - glRectf(x, y, x + zoomx * width, y + zoomy * height); - } - else { - MovieClip *clip = ED_space_clip_get_clip(sc); - int filter = GL_LINEAR; + /* checkerboard for case alpha */ + if (ibuf->planes == 32) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - /* checkerboard for case alpha */ - if (ibuf->planes == 32) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - fdrawcheckerboard(x, y, x + zoomx * ibuf->x, y + zoomy * ibuf->y); - } + fdrawcheckerboard(x, y, x + zoomx * ibuf->x, y + zoomy * ibuf->y); + } - /* non-scaled proxy shouldn't use filtering */ - if ((clip->flag & MCLIP_USE_PROXY) == 0 || - ELEM(sc->user.render_size, MCLIP_PROXY_RENDER_SIZE_FULL, MCLIP_PROXY_RENDER_SIZE_100)) - { - filter = GL_NEAREST; - } + /* non-scaled proxy shouldn't use filtering */ + if ((clip->flag & MCLIP_USE_PROXY) == 0 || + ELEM(sc->user.render_size, MCLIP_PROXY_RENDER_SIZE_FULL, MCLIP_PROXY_RENDER_SIZE_100)) + { + filter = GL_NEAREST; + } - /* set zoom */ - glPixelZoom(zoomx * width / ibuf->x, zoomy * height / ibuf->y); + /* set zoom */ + glPixelZoom(zoomx * width / ibuf->x, zoomy * height / ibuf->y); - glaDrawImBuf_glsl_ctx(C, ibuf, x, y, filter); + glaDrawImBuf_glsl_ctx(C, ibuf, x, y, filter); - /* reset zoom */ - glPixelZoom(1.0f, 1.0f); + /* reset zoom */ + glPixelZoom(1.0f, 1.0f); - if (ibuf->planes == 32) - glDisable(GL_BLEND); - } + if (ibuf->planes == 32) + glDisable(GL_BLEND); } static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int height, float zoomx, float zoomy) @@ -443,7 +501,7 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT float marker_pos[2], int width, int height) { int tiny = sc->flag & SC_SHOW_TINY_MARKER; - int show_search = FALSE; + bool show_search = false; float px[2]; UI_ThemeColor(TH_MARKER_OUTLINE); @@ -506,8 +564,8 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT glEnd(); } - show_search = TRACK_VIEW_SELECTED(sc, track) && - ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0); + show_search = (TRACK_VIEW_SELECTED(sc, track) && + ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0)) != 0; if (sc->flag & SC_SHOW_MARKER_SEARCH && show_search) { glBegin(GL_LINE_LOOP); glVertex2f(marker->search_min[0], marker->search_min[1]); @@ -546,7 +604,7 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra float marker_pos[2], int width, int height, int act, int sel) { int tiny = sc->flag & SC_SHOW_TINY_MARKER; - int show_search = 0; + bool show_search = false; float col[3], scol[3], px[2]; track_colors(track, act, col, scol); @@ -661,8 +719,8 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra } /* search */ - show_search = TRACK_VIEW_SELECTED(sc, track) && - ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0); + show_search = (TRACK_VIEW_SELECTED(sc, track) && + ((marker->flag & MARKER_DISABLED) == 0 || (sc->flag & SC_SHOW_MARKER_PATTERN) == 0)) != 0; if ((track->search_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_SEARCH) && show_search) { if (track->flag & TRACK_LOCKED) { if (act) @@ -950,24 +1008,154 @@ static void draw_marker_texts(SpaceClip *sc, MovieTrackingTrack *track, MovieTra } } -static void view2d_to_region_float(View2D *v2d, float x, float y, float *regionx, float *regiony) +static void plane_track_colors(bool is_active, float color[3], float selected_color[3]) +{ + UI_GetThemeColor3fv(TH_MARKER, color); + + if (is_active) + UI_GetThemeColor3fv(TH_ACT_MARKER, selected_color); + else + UI_GetThemeColor3fv(TH_SEL_MARKER, selected_color); +} + +static void getArrowEndPoint(const int width, const int height, const float zoom, + const float start_corner[2], const float end_corner[2], + float end_point[2]) { - /* express given coordinates as proportional values */ - x = -v2d->cur.xmin / BLI_rctf_size_x(&v2d->cur); - y = -v2d->cur.ymin / BLI_rctf_size_y(&v2d->cur); + float direction[2]; + float max_length; + + sub_v2_v2v2(direction, end_corner, start_corner); - /* convert proportional distances to screen coordinates */ - *regionx = v2d->mask.xmin + x * BLI_rcti_size_x(&v2d->mask); - *regiony = v2d->mask.ymin + y * BLI_rcti_size_y(&v2d->mask); + direction[0] *= width; + direction[1] *= height; + max_length = len_v2(direction); + normalize_v2(direction); + mul_v2_fl(direction, min_ff(32.0f / zoom, max_length)); + direction[0] /= width; + direction[1] /= height; + + add_v2_v2v2(end_point, start_corner, direction); } +static void draw_plane_marker_ex(SpaceClip *sc, MovieTrackingPlaneTrack *plane_track, + MovieTrackingPlaneMarker *plane_marker, bool is_active_track, + bool draw_outline, int width, int height) +{ + bool tiny = (sc->flag & SC_SHOW_TINY_MARKER) != 0; + bool is_selected_track = plane_track->flag & SELECT; + float px[2]; + + if (draw_outline) { + UI_ThemeColor(TH_MARKER_OUTLINE); + } + else { + float color[3], selected_color[3]; + plane_track_colors(is_active_track, color, selected_color); + if (is_selected_track) { + glColor3fv(selected_color); + } + else { + glColor3fv(color); + } + } + + px[0] = 1.0f / width / sc->zoom; + px[1] = 1.0f / height / sc->zoom; + + if (draw_outline) { + if (!tiny) { + glLineWidth(3.0f); + } + } + else if (tiny) { + glLineStipple(3, 0xaaaa); + glEnable(GL_LINE_STIPPLE); + } + + /* Draw rectangle itself. */ + glBegin(GL_LINE_LOOP); + glVertex2fv(plane_marker->corners[0]); + glVertex2fv(plane_marker->corners[1]); + glVertex2fv(plane_marker->corners[2]); + glVertex2fv(plane_marker->corners[3]); + glEnd(); + + /* Draw axis. */ + if (!draw_outline) { + float end_point[2]; + glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT); + + getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[1], end_point); + glColor3f(1.0, 0.0, 0.0f); + glBegin(GL_LINES); + glVertex2fv(plane_marker->corners[0]); + glVertex2fv(end_point); + glEnd(); + + getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[3], end_point); + glColor3f(0.0, 1.0, 0.0f); + glBegin(GL_LINES); + glVertex2fv(plane_marker->corners[0]); + glVertex2fv(end_point); + glEnd(); + + glPopAttrib(); + } + + /* Draw sliders. */ + if (is_selected_track) { + int i; + for (i = 0; i < 4; i++) { + draw_marker_slide_square(plane_marker->corners[i][0], plane_marker->corners[i][1], + 3.0f * px[0], 3.0f * px[1], draw_outline, px); + } + } + + if (draw_outline) { + if (!tiny) { + glLineWidth(1.0f); + } + } + else if (tiny) { + glDisable(GL_LINE_STIPPLE); + } +} + +static void draw_plane_marker_outline(SpaceClip *sc, MovieTrackingPlaneTrack *plane_track, + MovieTrackingPlaneMarker *plane_marker, int width, int height) +{ + draw_plane_marker_ex(sc, plane_track, plane_marker, false, true, width, height); +} + +static void draw_plane_marker(SpaceClip *sc, MovieTrackingPlaneTrack *plane_track, + MovieTrackingPlaneMarker *plane_marker, bool is_active_track, + int width, int height) +{ + draw_plane_marker_ex(sc, plane_track, plane_marker, is_active_track, false, width, height); +} + +static void draw_plane_track(SpaceClip *sc, MovieTrackingPlaneTrack *plane_track, + int framenr, bool is_active_track, int width, int height) +{ + MovieTrackingPlaneMarker *plane_marker; + + plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); + + draw_plane_marker_outline(sc, plane_track, plane_marker, width, height); + draw_plane_marker(sc, plane_track, plane_marker, is_active_track, width, height); +} + +/* Draw all kind of tracks. */ static void draw_tracking_tracks(SpaceClip *sc, ARegion *ar, MovieClip *clip, int width, int height, float zoomx, float zoomy) { float x, y; MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); MovieTrackingTrack *track, *act_track; + MovieTrackingPlaneTrack *plane_track, *active_plane_track; MovieTrackingMarker *marker; int framenr = ED_space_clip_get_clip_frame_number(sc); int undistort = sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT; @@ -980,7 +1168,7 @@ static void draw_tracking_tracks(SpaceClip *sc, ARegion *ar, MovieClip *clip, * to avoid this flickering, calculate base point in the same way as it happens * in UI_view2d_to_region_no_clip, but do it in floats here */ - view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y); + UI_view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y); glPushMatrix(); glTranslatef(x, y, 0); @@ -1160,6 +1348,15 @@ static void draw_tracking_tracks(SpaceClip *sc, ARegion *ar, MovieClip *clip, glDisable(GL_POINT_SMOOTH); } + /* Draw plane tracks */ + active_plane_track = BKE_tracking_plane_track_get_active(tracking); + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + draw_plane_track(sc, plane_track, framenr, plane_track == active_plane_track, width, height); + } + glPopMatrix(); if (sc->flag & SC_SHOW_NAMES) { @@ -1214,7 +1411,7 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip, if ((sc->flag & SC_SHOW_GRID) == 0 && (sc->flag & SC_MANUAL_CALIBRATION) == 0) return; - view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y); + UI_view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y); glPushMatrix(); glTranslatef(x, y, 0); @@ -1409,7 +1606,7 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar) { MovieClip *clip = ED_space_clip_get_clip(sc); Scene *scene = CTX_data_scene(C); - ImBuf *ibuf; + ImBuf *ibuf = NULL; int width, height; float zoomx, zoomy; @@ -1447,7 +1644,7 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar) mul_serie_m4(sc->unistabmat, smat, sc->stabmat, ismat, NULL, NULL, NULL, NULL, NULL); } } - else { + else if ((sc->flag & SC_MUTE_FOOTAGE) == 0) { ibuf = ED_space_clip_get_buffer(sc); zero_v2(sc->loc); @@ -1460,6 +1657,9 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar) draw_movieclip_buffer(C, sc, ar, ibuf, width, height, zoomx, zoomy); IMB_freeImBuf(ibuf); } + else if (sc->flag & SC_MUTE_FOOTAGE) { + draw_movieclip_muted(ar, width, height, zoomx, zoomy); + } else { ED_region_grid_draw(ar, zoomx, zoomy); } diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 08d0af817a8..0d64a3ce594 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -262,15 +262,15 @@ ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale /* returns color in SRGB */ /* matching ED_space_image_color_sample() */ -int ED_space_clip_color_sample(SpaceClip *sc, ARegion *ar, int mval[2], float r_col[3]) +bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *ar, int mval[2], float r_col[3]) { ImBuf *ibuf; float fx, fy, co[2]; - int ret = FALSE; + bool ret = false; ibuf = ED_space_clip_get_buffer(sc); if (!ibuf) { - return FALSE; + return false; } /* map the mouse coords to the backdrop image space */ @@ -290,12 +290,12 @@ int ED_space_clip_color_sample(SpaceClip *sc, ARegion *ar, int mval[2], float r_ if (ibuf->rect_float) { fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x)); linearrgb_to_srgb_v3_v3(r_col, fp); - ret = TRUE; + ret = true; } else if (ibuf->rect) { cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x); rgb_uchar_to_float(r_col, cp); - ret = TRUE; + ret = true; } } @@ -325,11 +325,12 @@ void ED_clip_update_frame(const Main *mainp, int cfra) } } -static int selected_boundbox(SpaceClip *sc, float min[2], float max[2]) +static bool selected_boundbox(SpaceClip *sc, float min[2], float max[2]) { MovieClip *clip = ED_space_clip_get_clip(sc); MovieTrackingTrack *track; - int width, height, ok = FALSE; + int width, height; + bool ok = false; ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); int framenr = ED_space_clip_get_clip_frame_number(sc); @@ -362,7 +363,7 @@ static int selected_boundbox(SpaceClip *sc, float min[2], float max[2]) minmax_v2v2_v2(min, max, pos); - ok = TRUE; + ok = true; } } @@ -372,7 +373,7 @@ static int selected_boundbox(SpaceClip *sc, float min[2], float max[2]) return ok; } -int ED_clip_view_selection(const bContext *C, ARegion *ar, int fit) +bool ED_clip_view_selection(const bContext *C, ARegion *ar, bool fit) { SpaceClip *sc = CTX_wm_space_clip(C); int w, h, frame_width, frame_height; @@ -381,10 +382,10 @@ int ED_clip_view_selection(const bContext *C, ARegion *ar, int fit) ED_space_clip_get_size(sc, &frame_width, &frame_height); if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL)) - return FALSE; + return false; if (!selected_boundbox(sc, min, max)) - return FALSE; + return false; /* center view */ clip_view_center_to_point(sc, (max[0] + min[0]) / (2 * frame_width), @@ -412,7 +413,7 @@ int ED_clip_view_selection(const bContext *C, ARegion *ar, int fit) sc->zoom = newzoom; } - return TRUE; + return true; } void ED_clip_point_undistorted_pos(SpaceClip *sc, const float co[2], float r_co[2]) @@ -500,22 +501,22 @@ void ED_clip_mouse_pos(SpaceClip *sc, ARegion *ar, const int mval[2], float co[2 ED_clip_point_stable_pos(sc, ar, mval[0], mval[1], &co[0], &co[1]); } -int ED_space_clip_check_show_trackedit(SpaceClip *sc) +bool ED_space_clip_check_show_trackedit(SpaceClip *sc) { if (sc) { return ELEM3(sc->mode, SC_MODE_TRACKING, SC_MODE_RECONSTRUCTION, SC_MODE_DISTORTION); } - return FALSE; + return false; } -int ED_space_clip_check_show_maskedit(SpaceClip *sc) +bool ED_space_clip_check_show_maskedit(SpaceClip *sc) { if (sc) { return sc->mode == SC_MODE_MASKEDIT; } - return FALSE; + return false; } /* ******** clip editing functions ******** */ diff --git a/source/blender/editors/space_clip/clip_graph_draw.c b/source/blender/editors/space_clip/clip_graph_draw.c index 973200dc340..173d65ee4fc 100644 --- a/source/blender/editors/space_clip/clip_graph_draw.c +++ b/source/blender/editors/space_clip/clip_graph_draw.c @@ -126,7 +126,7 @@ static void tracking_segment_end_cb(void *UNUSED(userdata)) static void tracking_segment_knot_cb(void *userdata, MovieTrackingTrack *track, MovieTrackingMarker *marker, int coord, int scene_framenr, float val) { - struct { MovieTrackingTrack *act_track; int sel; float xscale, yscale, hsize; } *data = userdata; + struct { MovieTrackingTrack *act_track; bool sel; float xscale, yscale, hsize; } *data = userdata; int sel = 0, sel_flag; if (track != data->act_track) @@ -151,7 +151,7 @@ static void draw_tracks_curves(View2D *v2d, SpaceClip *sc) MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); int width, height; - struct { MovieTrackingTrack *act_track; int sel; float xscale, yscale, hsize; } userdata; + struct { MovieTrackingTrack *act_track; bool sel; float xscale, yscale, hsize; } userdata; BKE_movieclip_get_size(clip, &sc->user, &width, &height); @@ -160,7 +160,7 @@ static void draw_tracks_curves(View2D *v2d, SpaceClip *sc) /* non-selected knot handles */ userdata.hsize = UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE); - userdata.sel = FALSE; + userdata.sel = false; userdata.act_track = act_track; UI_view2d_getscale(v2d, &userdata.xscale, &userdata.yscale); clip_graph_tracking_values_iterate(sc, sc->flag & SC_SHOW_GRAPH_SEL_ONLY, sc->flag & SC_SHOW_GRAPH_HIDDEN, diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c index edc6ac1ecf7..393f92f5af5 100644 --- a/source/blender/editors/space_clip/clip_graph_ops.c +++ b/source/blender/editors/space_clip/clip_graph_ops.c @@ -96,8 +96,8 @@ static void toggle_selection_cb(void *userdata, MovieTrackingMarker *marker) /******************** mouse select operator ********************/ typedef struct { - int coord, /* coordinate index of found entuty (0 = X-axis, 1 = Y-axis) */ - has_prev; /* if there's valid coordinate of previous point of curve segment */ + int coord; /* coordinate index of found entuty (0 = X-axis, 1 = Y-axis) */ + bool has_prev; /* if there's valid coordinate of previous point of curve segment */ float min_dist, /* minimal distance between mouse and currently found entuty */ mouse_co[2], /* mouse coordinate */ @@ -134,7 +134,7 @@ static void find_nearest_tracking_segment_end_cb(void *userdata) { MouseSelectUserData *data = userdata; - data->has_prev = FALSE; + data->has_prev = false; } static void find_nearest_tracking_knot_cb(void *userdata, MovieTrackingTrack *track, @@ -163,7 +163,7 @@ static void mouse_select_init_data(MouseSelectUserData *userdata, float *co) copy_v2_v2(userdata->mouse_co, co); } -static int mouse_select_knot(bContext *C, float co[2], int extend) +static bool mouse_select_knot(bContext *C, float co[2], bool extend) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); @@ -200,15 +200,15 @@ static int mouse_select_knot(bContext *C, float co[2], int extend) else userdata.marker->flag |= MARKER_GRAPH_SEL_Y; - return TRUE; + return true; } } } - return FALSE; + return false; } -static int mouse_select_curve(bContext *C, float co[2], int extend) +static bool mouse_select_curve(bContext *C, float co[2], bool extend) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); @@ -242,15 +242,15 @@ static int mouse_select_curve(bContext *C, float co[2], int extend) toggle_selection_cb); } - return TRUE; + return true; } - return FALSE; + return false; } -static int mouse_select(bContext *C, float co[2], int extend) +static int mouse_select(bContext *C, float co[2], bool extend) { - int sel = FALSE; + bool sel = false; /* first try to select knot on selected curves */ sel = mouse_select_knot(C, co, extend); @@ -269,7 +269,7 @@ static int mouse_select(bContext *C, float co[2], int extend) static int select_exec(bContext *C, wmOperator *op) { float co[2]; - int extend = RNA_boolean_get(op->ptr, "extend"); + bool extend = RNA_boolean_get(op->ptr, "extend"); RNA_float_get_array(op->ptr, "location", co); @@ -313,7 +313,8 @@ void CLIP_OT_graph_select(wmOperatorType *ot) typedef struct BorderSelectuserData { rctf rect; - int change, mode, extend; + int mode; + bool change, extend; } BorderSelectuserData; static void border_select_cb(void *userdata, MovieTrackingTrack *UNUSED(track), @@ -352,13 +353,17 @@ static int border_select_graph_exec(bContext *C, wmOperator *op) BorderSelectuserData userdata; rcti rect; + if (act_track == NULL) { + return OPERATOR_CANCELLED; + } + /* get rectangle from operator */ WM_operator_properties_border_to_rcti(op, &rect); UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &userdata.rect.xmin, &userdata.rect.ymin); UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &userdata.rect.xmax, &userdata.rect.ymax); - userdata.change = FALSE; + userdata.change = false; userdata.mode = RNA_int_get(op->ptr, "gesture_mode"); userdata.extend = RNA_boolean_get(op->ptr, "extend"); @@ -466,11 +471,10 @@ static int delete_curve_exec(bContext *C, wmOperator *UNUSED(op)) SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; - ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); if (act_track) - clip_delete_track(C, clip, tracksbase, act_track); + clip_delete_track(C, clip, act_track); return OPERATOR_FINISHED; } @@ -498,7 +502,6 @@ static int delete_knot_exec(bContext *C, wmOperator *UNUSED(op)) SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; - ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); if (act_track) { @@ -508,7 +511,7 @@ static int delete_knot_exec(bContext *C, wmOperator *UNUSED(op)) MovieTrackingMarker *marker = &act_track->markers[a]; if (marker->flag & MARKER_GRAPH_SEL) - clip_delete_marker(C, clip, tracksbase, act_track, marker); + clip_delete_marker(C, clip, act_track, marker); else a++; } diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index 51cb83eecad..39af856d280 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -112,6 +112,8 @@ void CLIP_OT_prefetch(struct wmOperatorType *ot); void CLIP_OT_set_scene_frames(wmOperatorType *ot); +void CLIP_OT_cursor_set(struct wmOperatorType *ot); + /* clip_toolbar.c */ struct ARegion *ED_clip_has_properties_region(struct ScrArea *sa); void CLIP_OT_tools(struct wmOperatorType *ot); @@ -132,8 +134,8 @@ void clip_graph_tracking_values_iterate(struct SpaceClip *sc, int selected_only, void clip_graph_tracking_iterate(struct SpaceClip *sc, int selected_only, int include_hidden, void *userdata, void (*func)(void *userdata, struct MovieTrackingMarker *marker)); -void clip_delete_track(struct bContext *C, struct MovieClip *clip, struct ListBase *tracksbase, struct MovieTrackingTrack *track); -void clip_delete_marker(struct bContext *C, struct MovieClip *clip, struct ListBase *tracksbase, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker); +void clip_delete_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track); +void clip_delete_marker(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker); void clip_view_center_to_point(SpaceClip *sc, float x, float y); @@ -193,6 +195,12 @@ void CLIP_OT_tracking_object_remove(struct wmOperatorType *ot); void CLIP_OT_copy_tracks(struct wmOperatorType *ot); void CLIP_OT_paste_tracks(struct wmOperatorType *ot); +void CLIP_OT_create_plane_track(struct wmOperatorType *ot); +void CLIP_OT_slide_plane_marker(struct wmOperatorType *ot); + +void CLIP_OT_keyframe_insert(struct wmOperatorType *ot); +void CLIP_OT_keyframe_delete(struct wmOperatorType *ot); + /* tracking_select.c */ void CLIP_OT_select(struct wmOperatorType *ot); void CLIP_OT_select_all(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index de19df9abe2..a76f4364492 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -181,7 +181,7 @@ static int open_exec(bContext *C, wmOperator *op) PointerRNA fileptr; PropertyRNA *prop; char dir_only[FILE_MAX], file_only[FILE_MAX]; - int relative = RNA_boolean_get(op->ptr, "relative_path"); + bool relative = RNA_boolean_get(op->ptr, "relative_path"); RNA_string_get(op->ptr, "directory", dir_only); if (relative) @@ -335,7 +335,7 @@ static void view_pan_init(bContext *C, wmOperator *op, const wmEvent *event) ViewPanData *vpd; op->customdata = vpd = MEM_callocN(sizeof(ViewPanData), "ClipViewPanData"); - WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR); vpd->x = event->x; vpd->y = event->y; @@ -353,7 +353,7 @@ static void view_pan_init(bContext *C, wmOperator *op, const wmEvent *event) WM_event_add_modal_handler(C, op); } -static void view_pan_exit(bContext *C, wmOperator *op, int cancel) +static void view_pan_exit(bContext *C, wmOperator *op, bool cancel) { ViewPanData *vpd = op->customdata; @@ -363,7 +363,7 @@ static void view_pan_exit(bContext *C, wmOperator *op, int cancel) ED_region_tag_redraw(CTX_wm_region(C)); } - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); MEM_freeN(op->customdata); } @@ -490,7 +490,7 @@ static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event) ViewZoomData *vpd; op->customdata = vpd = MEM_callocN(sizeof(ViewZoomData), "ClipViewZoomData"); - WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR); vpd->x = event->x; vpd->y = event->y; @@ -502,7 +502,7 @@ static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event) WM_event_add_modal_handler(C, op); } -static void view_zoom_exit(bContext *C, wmOperator *op, int cancel) +static void view_zoom_exit(bContext *C, wmOperator *op, bool cancel) { SpaceClip *sc = CTX_wm_space_clip(C); ViewZoomData *vpd = op->customdata; @@ -512,7 +512,7 @@ static void view_zoom_exit(bContext *C, wmOperator *op, int cancel) ED_region_tag_redraw(CTX_wm_region(C)); } - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); MEM_freeN(op->customdata); } @@ -736,7 +736,7 @@ static int view_all_exec(bContext *C, wmOperator *op) ARegion *ar; int w, h, width, height; float aspx, aspy; - int fit_view = RNA_boolean_get(op->ptr, "fit_view"); + bool fit_view = RNA_boolean_get(op->ptr, "fit_view"); float zoomx, zoomy; /* retrieve state */ @@ -782,6 +782,8 @@ static int view_all_exec(bContext *C, wmOperator *op) void CLIP_OT_view_all(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "View All"; ot->idname = "CLIP_OT_view_all"; @@ -792,7 +794,8 @@ void CLIP_OT_view_all(wmOperatorType *ot) ot->poll = ED_space_clip_view_clip_poll; /* properties */ - RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport"); + prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /********************** view selected operator *********************/ @@ -943,7 +946,8 @@ typedef struct ProxyBuildJob { Scene *scene; struct Main *main; MovieClip *clip; - int clip_flag, stop; + int clip_flag; + bool stop; struct IndexBuildContext *index_context; } ProxyJob; @@ -1123,10 +1127,10 @@ static void *do_proxy_thread(void *data_v) ibuf = IMB_ibImageFromMemory(mem, size, IB_rect | IB_multilayer | IB_alphamode_detect, NULL, "proxy frame"); BKE_movieclip_build_proxy_frame_for_ibuf(data->clip, ibuf, NULL, cfra, - data->build_sizes, data->build_count, FALSE); + data->build_sizes, data->build_count, false); BKE_movieclip_build_proxy_frame_for_ibuf(data->clip, ibuf, data->distortion, cfra, - data->build_undistort_sizes, data->build_undistort_count, TRUE); + data->build_undistort_sizes, data->build_undistort_count, true); IMB_freeImBuf(ibuf); @@ -1455,6 +1459,59 @@ void CLIP_OT_set_scene_frames(wmOperatorType *ot) ot->exec = clip_set_scene_frames_exec; } +/******************** set 3d cursor operator ********************/ + +static int clip_set_2d_cursor_exec(bContext *C, wmOperator *op) +{ + SpaceClip *sclip = CTX_wm_space_clip(C); + bool show_cursor = false; + + show_cursor |= sclip->mode == SC_MODE_MASKEDIT; + show_cursor |= sclip->around == V3D_CURSOR; + + if (!show_cursor) { + return OPERATOR_CANCELLED; + } + + RNA_float_get_array(op->ptr, "location", sclip->cursor); + + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CLIP, NULL); + + return OPERATOR_FINISHED; +} + +static int clip_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceClip *sclip = CTX_wm_space_clip(C); + float location[2]; + + ED_clip_mouse_pos(sclip, ar, event->mval, location); + RNA_float_set_array(op->ptr, "location", location); + + return clip_set_2d_cursor_exec(C, op); +} + +void CLIP_OT_cursor_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set 2D Cursor"; + ot->description = "Set 2D cursor location"; + ot->idname = "CLIP_OT_cursor_set"; + + /* api callbacks */ + ot->exec = clip_set_2d_cursor_exec; + ot->invoke = clip_set_2d_cursor_invoke; + ot->poll = ED_space_clip_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", + "Cursor location in normalized clip coordinates", -10.0f, 10.0f); +} + /********************** macroses *********************/ void ED_operatormacros_clip(void) diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index d7a9b1c0cb6..635aa388541 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -76,7 +76,8 @@ void clip_graph_tracking_values_iterate_track( BKE_movieclip_get_size(clip, &sc->user, &width, &height); for (coord = 0; coord < 2; coord++) { - int i, open = FALSE, prevfra = 0; + int i, prevfra = 0; + bool open = false; float prevval = 0.0f; for (i = 0; i < track->markersnr; i++) { @@ -88,7 +89,7 @@ void clip_graph_tracking_values_iterate_track( if (segment_end) segment_end(userdata); - open = FALSE; + open = false; } continue; @@ -98,7 +99,7 @@ void clip_graph_tracking_values_iterate_track( if (segment_start) segment_start(userdata, track, coord); - open = TRUE; + open = true; prevval = marker->pos[coord]; } @@ -175,13 +176,16 @@ void clip_graph_tracking_iterate(SpaceClip *sc, int selected_only, int include_h } } -void clip_delete_track(bContext *C, MovieClip *clip, ListBase *tracksbase, MovieTrackingTrack *track) +void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track) { MovieTracking *tracking = &clip->tracking; MovieTrackingStabilization *stab = &tracking->stabilization; MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); + MovieTrackingPlaneTrack *plane_track, *next_plane_track; + ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); - int has_bundle = FALSE, update_stab = FALSE; + bool has_bundle = false, update_stab = false; if (track == act_track) tracking->act_track = NULL; @@ -189,12 +193,57 @@ void clip_delete_track(bContext *C, MovieClip *clip, ListBase *tracksbase, Movie if (track == stab->rot_track) { stab->rot_track = NULL; - update_stab = TRUE; + update_stab = true; } /* handle reconstruction display in 3d viewport */ if (track->flag & TRACK_HAS_BUNDLE) - has_bundle = TRUE; + has_bundle = true; + + /* Make sure no plane will use freed track */ + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = next_plane_track) + { + bool found = false; + int i; + + next_plane_track = plane_track->next; + + for (i = 0; i < plane_track->point_tracksnr; i++) { + if (plane_track->point_tracks[i] == track) { + found = true; + break; + } + } + + if (!found) { + continue; + } + + if (plane_track->point_tracksnr > 4) { + int track_index; + MovieTrackingTrack **new_point_tracks; + + new_point_tracks = MEM_mallocN(sizeof(*new_point_tracks) * plane_track->point_tracksnr, + "new point tracks array"); + + for (i = 0, track_index = 0; i < plane_track->point_tracksnr; i++) { + if (plane_track->point_tracks[i] != track) { + new_point_tracks[track_index++] = plane_track->point_tracks[i]; + } + } + + MEM_freeN(plane_track->point_tracks); + plane_track->point_tracks = new_point_tracks; + plane_track->point_tracksnr--; + } + else { + /* Delete planes with less than 3 point tracks in it. */ + BKE_tracking_plane_track_free(plane_track); + BLI_freelinkN(plane_tracks_base, plane_track); + } + } BKE_tracking_track_free(track); BLI_freelinkN(tracksbase, track); @@ -212,11 +261,11 @@ void clip_delete_track(bContext *C, MovieClip *clip, ListBase *tracksbase, Movie WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); } -void clip_delete_marker(bContext *C, MovieClip *clip, ListBase *tracksbase, - MovieTrackingTrack *track, MovieTrackingMarker *marker) +void clip_delete_marker(bContext *C, MovieClip *clip, MovieTrackingTrack *track, + MovieTrackingMarker *marker) { if (track->markersnr == 1) { - clip_delete_track(C, clip, tracksbase, track); + clip_delete_track(C, clip, track); } else { BKE_tracking_marker_delete(track, marker->framenr); diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 562a8584560..3ede63adb72 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -56,6 +56,7 @@ #include "ED_screen.h" #include "ED_clip.h" #include "ED_transform.h" +#include "ED_uvedit.h" /* just for draw_image_cursor */ #include "IMB_imbuf.h" @@ -442,6 +443,7 @@ static void clip_operatortypes(void) WM_operatortype_append(CLIP_OT_view_ndof); WM_operatortype_append(CLIP_OT_prefetch); WM_operatortype_append(CLIP_OT_set_scene_frames); + WM_operatortype_append(CLIP_OT_cursor_set); /* ** clip_toolbar.c ** */ WM_operatortype_append(CLIP_OT_tools); @@ -517,6 +519,13 @@ static void clip_operatortypes(void) WM_operatortype_append(CLIP_OT_copy_tracks); WM_operatortype_append(CLIP_OT_paste_tracks); + /* Plane tracker */ + WM_operatortype_append(CLIP_OT_create_plane_track); + WM_operatortype_append(CLIP_OT_slide_plane_marker); + + WM_operatortype_append(CLIP_OT_keyframe_insert); + WM_operatortype_append(CLIP_OT_keyframe_delete); + /* ** clip_graph_ops.c ** */ /* graph editing */ @@ -685,6 +694,12 @@ static void clip_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "CLIP_OT_hide_tracks_clear", HKEY, KM_PRESS, KM_ALT, 0); + /* plane tracks */ + WM_keymap_add_item(keymap, "CLIP_OT_slide_plane_marker", LEFTMOUSE, KM_PRESS, 0, 0); + + WM_keymap_add_item(keymap, "CLIP_OT_keyframe_insert", IKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "CLIP_OT_keyframe_delete", IKEY, KM_PRESS, KM_ALT, 0); + /* clean-up */ WM_keymap_add_item(keymap, "CLIP_OT_join_tracks", JKEY, KM_PRESS, KM_CTRL, 0); @@ -717,6 +732,26 @@ static void clip_keymap(struct wmKeyConfig *keyconf) RNA_enum_set(kmi->ptr, "action", TRACK_CLEAR_ALL); RNA_boolean_set(kmi->ptr, "clear_active", FALSE); + /* Cursor */ + WM_keymap_add_item(keymap, "CLIP_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0); + + /* pivot point */ + 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", COMMAKEY, KM_PRESS, KM_CTRL, 0); /* 2.4x allowed Comma+Shift too, rather not use both */ + RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point"); + RNA_string_set(kmi->ptr, "value", "MEDIAN_POINT"); + + 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"); + /* ******** Hotkeys avalaible for preview region only ******** */ keymap = WM_keymap_find(keyconf, "Clip Graph Editor", SPACE_CLIP, 0); @@ -847,36 +882,36 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ARegion *ar_preview = ED_clip_has_preview_region(C, sa); ARegion *ar_properties = ED_clip_has_properties_region(sa); ARegion *ar_channels = ED_clip_has_channels_region(sa); - int main_visible = FALSE, preview_visible = FALSE, tools_visible = FALSE; - int tool_props_visible = FALSE, properties_visible = FALSE, channels_visible = FALSE; - int view_changed = FALSE; + bool main_visible = false, preview_visible = false, tools_visible = false; + bool tool_props_visible = false, properties_visible = false, channels_visible = false; + bool view_changed = false; switch (sc->view) { case SC_VIEW_CLIP: - main_visible = TRUE; - preview_visible = FALSE; - tools_visible = TRUE; - tool_props_visible = TRUE; - properties_visible = TRUE; - channels_visible = FALSE; + main_visible = true; + preview_visible = false; + tools_visible = true; + tool_props_visible = true; + properties_visible = true; + channels_visible = false; break; case SC_VIEW_GRAPH: - main_visible = FALSE; - preview_visible = TRUE; - tools_visible = FALSE; - tool_props_visible = FALSE; - properties_visible = FALSE; - channels_visible = FALSE; + main_visible = false; + preview_visible = true; + tools_visible = false; + tool_props_visible = false; + properties_visible = false; + channels_visible = false; reinit_preview_region(C, ar_preview); break; case SC_VIEW_DOPESHEET: - main_visible = FALSE; - preview_visible = TRUE; - tools_visible = FALSE; - tool_props_visible = FALSE; - properties_visible = FALSE; - channels_visible = TRUE; + main_visible = false; + preview_visible = true; + tools_visible = false; + tool_props_visible = false; + properties_visible = false; + channels_visible = true; reinit_preview_region(C, ar_preview); break; @@ -886,12 +921,12 @@ static void clip_refresh(const bContext *C, ScrArea *sa) if (ar_main && (ar_main->flag & RGN_FLAG_HIDDEN)) { ar_main->flag &= ~RGN_FLAG_HIDDEN; ar_main->v2d.flag &= ~V2D_IS_INITIALISED; - view_changed = TRUE; + view_changed = true; } if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) { ar_main->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } else { @@ -899,11 +934,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_main->flag |= RGN_FLAG_HIDDEN; ar_main->v2d.flag &= ~V2D_IS_INITIALISED; WM_event_remove_handlers((bContext *)C, &ar_main->handlers); - view_changed = TRUE; + view_changed = true; } if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) { ar_main->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } @@ -911,11 +946,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) if (ar_properties && (ar_properties->flag & RGN_FLAG_HIDDEN)) { ar_properties->flag &= ~RGN_FLAG_HIDDEN; ar_properties->v2d.flag &= ~V2D_IS_INITIALISED; - view_changed = TRUE; + view_changed = true; } if (ar_properties && ar_properties->alignment != RGN_ALIGN_RIGHT) { ar_properties->alignment = RGN_ALIGN_RIGHT; - view_changed = TRUE; + view_changed = true; } } else { @@ -923,11 +958,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_properties->flag |= RGN_FLAG_HIDDEN; ar_properties->v2d.flag &= ~V2D_IS_INITIALISED; WM_event_remove_handlers((bContext *)C, &ar_properties->handlers); - view_changed = TRUE; + view_changed = true; } if (ar_properties && ar_properties->alignment != RGN_ALIGN_NONE) { ar_properties->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } @@ -935,11 +970,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) if (ar_tools && (ar_tools->flag & RGN_FLAG_HIDDEN)) { ar_tools->flag &= ~RGN_FLAG_HIDDEN; ar_tools->v2d.flag &= ~V2D_IS_INITIALISED; - view_changed = TRUE; + view_changed = true; } if (ar_tools && ar_tools->alignment != RGN_ALIGN_LEFT) { ar_tools->alignment = RGN_ALIGN_LEFT; - view_changed = TRUE; + view_changed = true; } } else { @@ -947,11 +982,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_tools->flag |= RGN_FLAG_HIDDEN; ar_tools->v2d.flag &= ~V2D_IS_INITIALISED; WM_event_remove_handlers((bContext *)C, &ar_tools->handlers); - view_changed = TRUE; + view_changed = true; } if (ar_tools && ar_tools->alignment != RGN_ALIGN_NONE) { ar_tools->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } @@ -959,11 +994,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) if (ar_tool_props && (ar_tool_props->flag & RGN_FLAG_HIDDEN)) { ar_tool_props->flag &= ~RGN_FLAG_HIDDEN; ar_tool_props->v2d.flag &= ~V2D_IS_INITIALISED; - view_changed = TRUE; + view_changed = true; } if (ar_tool_props && (ar_tool_props->alignment != (RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV))) { ar_tool_props->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; - view_changed = TRUE; + view_changed = true; } } else { @@ -971,11 +1006,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_tool_props->flag |= RGN_FLAG_HIDDEN; ar_tool_props->v2d.flag &= ~V2D_IS_INITIALISED; WM_event_remove_handlers((bContext *)C, &ar_tool_props->handlers); - view_changed = TRUE; + view_changed = true; } if (ar_tool_props && ar_tool_props->alignment != RGN_ALIGN_NONE) { ar_tool_props->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } @@ -984,11 +1019,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_preview->flag &= ~RGN_FLAG_HIDDEN; ar_preview->v2d.flag &= ~V2D_IS_INITIALISED; ar_preview->v2d.cur = ar_preview->v2d.tot; - view_changed = TRUE; + view_changed = true; } if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) { ar_preview->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } else { @@ -996,11 +1031,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_preview->flag |= RGN_FLAG_HIDDEN; ar_preview->v2d.flag &= ~V2D_IS_INITIALISED; WM_event_remove_handlers((bContext *)C, &ar_preview->handlers); - view_changed = TRUE; + view_changed = true; } if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) { ar_preview->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } @@ -1008,11 +1043,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) if (ar_channels && (ar_channels->flag & RGN_FLAG_HIDDEN)) { ar_channels->flag &= ~RGN_FLAG_HIDDEN; ar_channels->v2d.flag &= ~V2D_IS_INITIALISED; - view_changed = TRUE; + view_changed = true; } if (ar_channels && ar_channels->alignment != RGN_ALIGN_LEFT) { ar_channels->alignment = RGN_ALIGN_LEFT; - view_changed = TRUE; + view_changed = true; } } else { @@ -1020,11 +1055,11 @@ static void clip_refresh(const bContext *C, ScrArea *sa) ar_channels->flag |= RGN_FLAG_HIDDEN; ar_channels->v2d.flag &= ~V2D_IS_INITIALISED; WM_event_remove_handlers((bContext *)C, &ar_channels->handlers); - view_changed = TRUE; + view_changed = true; } if (ar_channels && ar_channels->alignment != RGN_ALIGN_NONE) { ar_channels->alignment = RGN_ALIGN_NONE; - view_changed = TRUE; + view_changed = true; } } @@ -1109,6 +1144,9 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar) /* draw entirely, view changes should be handled here */ SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); + float aspx, aspy, zoomx, zoomy, x, y; + int width, height; + bool show_cursor = false; /* if tracking is in progress, we should synchronize framenr from clipuser * so latest tracked frame would be shown */ @@ -1140,29 +1178,43 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar) clip_draw_main(C, sc, ar); - if (sc->mode == SC_MODE_MASKEDIT) { + /* TODO(sergey): would be nice to find a way to de-duplicate all this space conversions */ + UI_view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y); + ED_space_clip_get_size(sc, &width, &height); + ED_space_clip_get_zoom(sc, ar, &zoomx, &zoomy); + ED_space_clip_get_aspect(sc, &aspx, &aspy); + if (sc->mode == SC_MODE_MASKEDIT) { Mask *mask = CTX_data_edit_mask(C); if (mask) { ScrArea *sa = CTX_wm_area(C); - int width, height; - float aspx, aspy; - ED_mask_get_size(sa, &width, &height); - ED_space_clip_get_aspect(sc, &aspx, &aspy); + int mask_width, mask_height; + ED_mask_get_size(sa, &mask_width, &mask_height); ED_mask_draw_region(mask, ar, sc->mask_info.draw_flag, sc->mask_info.draw_type, - width, height, + mask_width, mask_height, aspx, aspy, TRUE, TRUE, sc->stabmat, C); } + } - + show_cursor |= sc->mode == SC_MODE_MASKEDIT; + show_cursor |= sc->around == V3D_CURSOR; + + if (show_cursor) { + glPushMatrix(); + glTranslatef(x, y, 0); + glScalef(zoomx, zoomy, 0); + glMultMatrixf(sc->stabmat); + glScalef(width, height, 0); + draw_image_cursor(ar, sc->cursor); + glPopMatrix(); } if (sc->flag & SC_SHOW_GPENCIL) { /* Grease Pencil */ - clip_draw_grease_pencil((bContext *)C, TRUE); + clip_draw_grease_pencil((bContext *)C, true); } /* reset view matrix */ @@ -1170,7 +1222,7 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar) if (sc->flag & SC_SHOW_GPENCIL) { /* draw Grease Pencil - screen space only */ - clip_draw_grease_pencil((bContext *)C, FALSE); + clip_draw_grease_pencil((bContext *)C, false); } } diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index f3d070452a5..246ea7fe140 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -34,6 +34,7 @@ #include "DNA_camera_types.h" #include "DNA_constraint_types.h" #include "DNA_gpencil_types.h" +#include "DNA_mask_types.h" #include "DNA_movieclip_types.h" #include "DNA_object_types.h" /* SELECT */ #include "DNA_scene_types.h" @@ -55,6 +56,8 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_library.h" +#include "BKE_mask.h" +#include "BKE_node.h" #include "BKE_sound.h" #include "WM_api.h" @@ -88,6 +91,7 @@ static bool add_marker(const bContext *C, float x, float y) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); MovieTrackingTrack *track; int width, height; int framenr = ED_space_clip_get_clip_frame_number(sc); @@ -101,8 +105,10 @@ static bool add_marker(const bContext *C, float x, float y) track = BKE_tracking_track_add(tracking, tracksbase, x, y, framenr, width, height); BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, 0); + BKE_tracking_plane_tracks_deselect_all(plane_tracks_base); clip->tracking.act_track = track; + clip->tracking.act_plane_track = NULL; return true; } @@ -234,13 +240,31 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); MovieTrackingTrack *track = tracksbase->first, *next; + MovieTrackingPlaneTrack *plane_track, *next_plane_track; + bool modified = false; + + /* Delete selected plane tracks. */ + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = next_plane_track) + { + next_plane_track = plane_track->next; + + if (plane_track->flag & SELECT) { + BKE_tracking_plane_track_free(plane_track); + BLI_freelinkN(plane_tracks_base, plane_track); + modified = true; + } + } + /* Remove selected point tracks (they'll also be removed from planes which uses them). */ while (track) { next = track->next; if (TRACK_VIEW_SELECTED(sc, track)) - clip_delete_track(C, clip, tracksbase, track); + clip_delete_track(C, clip, track); track = next; } @@ -248,6 +272,10 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) /* nothing selected now, unlock view so it can be scrolled nice again */ sc->flag &= ~SC_LOCK_SELECTION; + if (modified) { + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); + } + return OPERATOR_FINISHED; } @@ -274,7 +302,9 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op)) SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); MovieTrackingTrack *track = tracksbase->first, *next; + MovieTrackingPlaneTrack *plane_track, *plane_track_next; int framenr = ED_space_clip_get_clip_frame_number(sc); int has_selection = 0; @@ -287,13 +317,34 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op)) if (marker) { has_selection |= track->markersnr > 1; - clip_delete_marker(C, clip, tracksbase, track, marker); + clip_delete_marker(C, clip, track, marker); } } track = next; } + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track_next) + { + plane_track_next = plane_track->next; + + if (plane_track->flag & SELECT) { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, framenr); + + if (plane_marker) { + if (plane_track->markersnr == 1) { + BKE_tracking_plane_track_free(plane_track); + BLI_freelinkN(plane_tracks_base, plane_track); + } + else { + BKE_tracking_plane_marker_delete(plane_track, framenr); + } + } + } + } + if (!has_selection) { /* nothing selected now, unlock view so it can be scrolled nice again */ sc->flag &= ~SC_LOCK_SELECTION; @@ -542,14 +593,14 @@ static int mouse_on_tilt(SpaceClip *sc, MovieTrackingMarker *marker, float co[2] return mouse_on_slide_zone(sc, marker, TRACK_AREA_PAT, co, slider, 0.0f, width, height); } -static int slide_check_corners(float (*corners)[2]) +static bool slide_check_corners(float (*corners)[2]) { int i, next, prev; float cross = 0.0f; float p[2] = {0.0f, 0.0f}; if (!isect_point_quad_v2(p, corners[0], corners[1], corners[2], corners[3])) - return FALSE; + return false; for (i = 0; i < 4; i++) { float v1[2], v2[2], cur_cross; @@ -567,12 +618,12 @@ static int slide_check_corners(float (*corners)[2]) cross = cur_cross; } else if (cross * cur_cross < 0.0f) { - return FALSE; + return false; } } } - return TRUE; + return true; } static void hide_cursor(bContext *C) @@ -613,25 +664,25 @@ MovieTrackingTrack *tracking_marker_check_slide(bContext *C, const wmEvent *even while (track) { if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) { MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); - int ok = FALSE; + bool ok = false; if ((marker->flag & MARKER_DISABLED) == 0) { if (mouse_on_offset(sc, track, marker, co, width, height)) { area = TRACK_AREA_POINT; action = SLIDE_ACTION_POS; - ok = TRUE; + ok = true; } if (!ok && (sc->flag & SC_SHOW_MARKER_SEARCH)) { if (mouse_on_corner(sc, marker, TRACK_AREA_SEARCH, co, 1, 0.0f, width, height)) { area = TRACK_AREA_SEARCH; action = SLIDE_ACTION_OFFSET; - ok = TRUE; + ok = true; } else if (mouse_on_corner(sc, marker, TRACK_AREA_SEARCH, co, 0, 0.0f, width, height)) { area = TRACK_AREA_SEARCH; action = SLIDE_ACTION_SIZE; - ok = TRUE; + ok = true; } } @@ -642,7 +693,7 @@ MovieTrackingTrack *tracking_marker_check_slide(bContext *C, const wmEvent *even area = TRACK_AREA_PAT; action = SLIDE_ACTION_POS; corner = current_corner; - ok = TRUE; + ok = true; } else { #if 0 @@ -651,18 +702,18 @@ MovieTrackingTrack *tracking_marker_check_slide(bContext *C, const wmEvent *even if (mouse_on_corner(sc, marker, TRACK_AREA_PAT, co, 1, 12.0f, width, height)) { area = TRACK_AREA_PAT; action = SLIDE_ACTION_OFFSET; - ok = TRUE; + ok = true; } if (!ok && mouse_on_corner(sc, marker, TRACK_AREA_PAT, co, 0, 12.0f, width, height)) { area = TRACK_AREA_PAT; action = SLIDE_ACTION_SIZE; - ok = TRUE; + ok = true; } #endif if (!ok && mouse_on_tilt(sc, marker, co, width, height)) { area = TRACK_AREA_PAT; action = SLIDE_ACTION_TILT_SIZE; - ok = TRUE; + ok = true; } } } @@ -727,6 +778,7 @@ static int slide_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event MovieTracking *tracking = &clip->tracking; tracking->act_track = slidedata->track; + tracking->act_plane_track = NULL; op->customdata = slidedata; @@ -760,6 +812,32 @@ static void cancel_mouse_slide(SlideMarkerData *data) } } +static void apply_mouse_slide(bContext *C, SlideMarkerData *data) +{ + if (data->area == TRACK_AREA_POINT) { + SpaceClip *sc = CTX_wm_space_clip(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTrackingPlaneTrack *plane_track; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); + int framenr = ED_space_clip_get_clip_frame_number(sc); + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) { + int i; + for (i = 0; i < plane_track->point_tracksnr; i++) { + if (plane_track->point_tracks[i] == data->track) { + BKE_tracking_track_plane_from_existing_motion(plane_track, framenr); + break; + } + } + } + } + } +} + static void free_slide_data(SlideMarkerData *data) { if (data->old_markers) @@ -955,6 +1033,7 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event) case LEFTMOUSE: if (event->val == KM_RELEASE) { + apply_mouse_slide(C, op->customdata); free_slide_data(op->customdata); show_cursor(C); @@ -1093,18 +1172,18 @@ static void track_init_markers(SpaceClip *sc, MovieClip *clip, int *frames_limit *frames_limit_r = frames_limit; } -static int track_markers_check_direction(int backwards, int curfra, int efra) +static bool track_markers_check_direction(int backwards, int curfra, int efra) { if (backwards) { if (curfra < efra) - return FALSE; + return false; } else { if (curfra > efra) - return FALSE; + return false; } - return TRUE; + return true; } static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backwards) @@ -1215,7 +1294,7 @@ static void track_markers_updatejob(void *tmv) BKE_tracking_context_sync(tmj->context); } -static void track_markers_freejob(void *tmv) +static void track_markers_endjob(void *tmv) { TrackMarkersJob *tmj = (TrackMarkersJob *)tmv; @@ -1224,10 +1303,15 @@ static void track_markers_freejob(void *tmv) ED_update_for_newframe(tmj->main, tmj->scene, 0); BKE_tracking_context_sync(tmj->context); - BKE_tracking_context_free(tmj->context); + BKE_tracking_context_finish(tmj->context); WM_main_add_notifier(NC_SCENE | ND_FRAME, tmj->scene); +} +static void track_markers_freejob(void *tmv) +{ + TrackMarkersJob *tmj = (TrackMarkersJob *)tmv; + BKE_tracking_context_free(tmj->context); MEM_freeN(tmj); } @@ -1281,6 +1365,7 @@ static int track_markers_exec(bContext *C, wmOperator *op) } BKE_tracking_context_sync(context); + BKE_tracking_context_finish(context); BKE_tracking_context_free(context); /* update scene current frame to the lastes tracked frame */ @@ -1337,7 +1422,7 @@ static int track_markers_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS else WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | NA_EVALUATED, 0); - WM_jobs_callbacks(wm_job, track_markers_startjob, NULL, track_markers_updatejob, NULL); + WM_jobs_callbacks(wm_job, track_markers_startjob, NULL, track_markers_updatejob, track_markers_endjob); G.is_break = FALSE; @@ -1822,13 +1907,13 @@ static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip) Object *camera = scene->camera; Base *base; - if (camera && BKE_object_movieclip_get(scene, camera, 0) == clip) + if (camera && BKE_object_movieclip_get(scene, camera, false) == clip) return camera; base = scene->base.first; while (base) { if (base->object->type == OB_CAMERA) { - if (BKE_object_movieclip_get(scene, base->object, 0) == clip) { + if (BKE_object_movieclip_get(scene, base->object, false) == clip) { camera = base->object; break; } @@ -1908,7 +1993,7 @@ static int count_selected_bundles(bContext *C) static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat[4][4]) { bConstraint *con; - int found = FALSE; + bool found = false; for (con = ob->constraints.first; con; con = con->next) { bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); @@ -1927,7 +2012,7 @@ static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat mul_m4_m4m4(invmat, invmat, data->invmat); - found = TRUE; + found = true; } } @@ -2047,7 +2132,7 @@ static void set_axis(Scene *scene, Object *ob, MovieClip *clip, MovieTrackingOb { Object *camera = get_camera_with_movieclip(scene, clip); int is_camera = tracking_object->flag & TRACKING_OBJECT_CAMERA; - int flip = FALSE; + bool flip = false; float mat[4][4], vec[3], obmat[4][4], dvec[3]; BKE_object_to_mat4(ob, obmat); @@ -2075,7 +2160,7 @@ static void set_axis(Scene *scene, Object *ob, MovieClip *clip, MovieTrackingOb if (axis == 'X') { if (fabsf(dvec[1]) < 1e-3f) { - flip = TRUE; + flip = true; mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f; mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f; @@ -2099,7 +2184,7 @@ static void set_axis(Scene *scene, Object *ob, MovieClip *clip, MovieTrackingOb } else { if (fabsf(dvec[0]) < 1e-3f) { - flip = TRUE; + flip = true; mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f; mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f; @@ -2320,7 +2405,7 @@ static int set_axis_exec(bContext *C, wmOperator *op) track = tracksbase->first; while (track) { - if (TRACK_VIEW_SELECTED(sc, track)) + if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE)) break; track = track->next; @@ -3670,3 +3755,446 @@ void CLIP_OT_paste_tracks(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/********************** Create plane track operator *********************/ + +static int create_plane_track_tracks_exec(bContext *C, wmOperator *op) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTracking *tracking = &clip->tracking; + MovieTrackingPlaneTrack *plane_track; + ListBase *tracks_base = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + int framenr = ED_space_clip_get_clip_frame_number(sc); + + plane_track = BKE_tracking_plane_track_add(tracking, plane_tracks_base, tracks_base, framenr); + + if (plane_track == NULL) { + BKE_report(op->reports, RPT_ERROR, "Need at least 4 selected point tracks to create a plane"); + return OPERATOR_CANCELLED; + } + else { + BKE_tracking_tracks_deselect_all(tracks_base); + + plane_track->flag |= SELECT; + clip->tracking.act_track = NULL; + clip->tracking.act_plane_track = plane_track; + + /* Copute homoraphies and apply them on marker's corner, so we've got + * quite nice motion from the very beginning. + */ + BKE_tracking_track_plane_from_existing_motion(plane_track, framenr); + } + + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); + + return OPERATOR_FINISHED; +} + +void CLIP_OT_create_plane_track(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Create Plane Track"; + ot->description = "Create new plane track out of selected point tracks"; + ot->idname = "CLIP_OT_create_plane_track"; + + /* api callbacks */ + ot->exec = create_plane_track_tracks_exec; + ot->poll = ED_space_clip_tracking_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************** Slide plane marker corner operator *********************/ + +typedef struct SlidePlaneMarkerData { + MovieTrackingPlaneTrack *plane_track; + MovieTrackingPlaneMarker *plane_marker; + int width, height; + int corner_index; + float *corner; + int previous_mval[2]; + float previous_corner[2]; + float old_corner[2]; + bool accurate; +} SlidePlaneMarkerData; + +static bool mouse_on_plane_slide_zone(SpaceClip *sc, float co[2], float slide_zone[2], int width, int height) +{ + const float size = 12.0f; + float dx, dy; + + dx = size / width / sc->zoom; + dy = size / height / sc->zoom; + + return IN_RANGE_INCL(co[0], slide_zone[0] - dx, slide_zone[0] + dx) && + IN_RANGE_INCL(co[1], slide_zone[1] - dy, slide_zone[1] + dy); +} + +static MovieTrackingPlaneTrack *tracking_plane_marker_check_slide(bContext *C, const wmEvent *event, int *corner_r) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + ARegion *ar = CTX_wm_region(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTrackingPlaneTrack *plane_track; + int width, height; + float co[2]; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); + int framenr = ED_space_clip_get_clip_frame_number(sc); + + ED_space_clip_get_size(sc, &width, &height); + + if (width == 0 || height == 0) { + return NULL; + } + + ED_clip_mouse_pos(sc, ar, event->mval, co); + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (plane_track->flag & SELECT) { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); + bool ok = false; + int i; + + for (i = 0; i < 4; i++) { + if (mouse_on_plane_slide_zone(sc, co, plane_marker->corners[i], width, height)) { + if (corner_r) { + *corner_r = i; + } + ok = true; + break; + } + } + + if (ok) { + return plane_track; + } + } + } + + return NULL; +} + +static void *slide_plane_marker_customdata(bContext *C, const wmEvent *event) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + ARegion *ar = CTX_wm_region(C); + MovieTrackingPlaneTrack *plane_track; + int width, height; + float co[2]; + SlidePlaneMarkerData *customdata = NULL; + int framenr = ED_space_clip_get_clip_frame_number(sc); + int corner; + + ED_space_clip_get_size(sc, &width, &height); + + if (width == 0 || height == 0) { + return NULL; + } + + ED_clip_mouse_pos(sc, ar, event->mval, co); + + plane_track = tracking_plane_marker_check_slide(C, event, &corner); + if (plane_track) { + MovieTrackingPlaneMarker *plane_marker; + + customdata = MEM_callocN(sizeof(SlidePlaneMarkerData), "slide plane marker data"); + + plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr); + + customdata->plane_track = plane_track; + customdata->plane_marker = plane_marker; + customdata->width = width; + customdata->height = height; + + customdata->previous_mval[0] = event->mval[0]; + customdata->previous_mval[1] = event->mval[1]; + + customdata->corner_index = corner; + customdata->corner = plane_marker->corners[corner]; + + copy_v2_v2(customdata->previous_corner, customdata->corner); + copy_v2_v2(customdata->old_corner, customdata->corner); + } + + return customdata; +} + +static int slide_plane_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + SlidePlaneMarkerData *slidedata = slide_plane_marker_customdata(C, event); + + if (slidedata) { + SpaceClip *sc = CTX_wm_space_clip(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTracking *tracking = &clip->tracking; + + tracking->act_plane_track = slidedata->plane_track; + tracking->act_track = NULL; + + op->customdata = slidedata; + + hide_cursor(C); + WM_event_add_modal_handler(C, op); + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL); + + return OPERATOR_RUNNING_MODAL; + } + + return OPERATOR_PASS_THROUGH; +} + +static void cancel_mouse_slide_plane_marker(SlidePlaneMarkerData *data) +{ + copy_v2_v2(data->corner, data->old_corner); +} + +static void free_slide_plane_marker_data(SlidePlaneMarkerData *data) +{ + MEM_freeN(data); +} + +static void slide_plane_marker_update_homographies(SpaceClip *sc, SlidePlaneMarkerData *data) +{ + int framenr = ED_space_clip_get_clip_frame_number(sc); + + BKE_tracking_track_plane_from_existing_motion(data->plane_track, framenr); +} + +static int slide_plane_marker_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + SlidePlaneMarkerData *data = (SlidePlaneMarkerData *) op->customdata; + float dx, dy, mdelta[2]; + int next_corner_index, prev_corner_index, diag_corner_index; + float *next_corner, *prev_corner, *diag_corner; + float next_edge[2], prev_edge[2], next_diag_edge[2], prev_diag_edge[2]; + + switch (event->type) { + case LEFTCTRLKEY: + case RIGHTCTRLKEY: + case LEFTSHIFTKEY: + case RIGHTSHIFTKEY: + if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY)) + data->accurate = event->val == KM_PRESS; + + /* fall-through */ + case MOUSEMOVE: + mdelta[0] = event->mval[0] - data->previous_mval[0]; + mdelta[1] = event->mval[1] - data->previous_mval[1]; + + dx = mdelta[0] / data->width / sc->zoom; + dy = mdelta[1] / data->height / sc->zoom; + + if (data->accurate) { + dx /= 5.0f; + dy /= 5.0f; + } + + data->corner[0] = data->previous_corner[0] + dx; + data->corner[1] = data->previous_corner[1] + dy; + + + /* + prev_edge + (Corner 3, current) <----------------------- (Corner 2, previous) + | ^ + | | + | | + | | + next_edge | | next_diag_edge + | | + | | + | | + v | + (Corner 0, next) -----------------------> (Corner 1, diagonal) + prev_diag_edge + */ + + next_corner_index = (data->corner_index + 1) % 4; + prev_corner_index = (data->corner_index + 3) % 4; + diag_corner_index = (data->corner_index + 2) % 4; + + next_corner = data->plane_marker->corners[next_corner_index]; + prev_corner = data->plane_marker->corners[prev_corner_index]; + diag_corner = data->plane_marker->corners[diag_corner_index]; + + sub_v2_v2v2(next_edge, next_corner, data->corner); + sub_v2_v2v2(prev_edge, data->corner, prev_corner); + sub_v2_v2v2(next_diag_edge, prev_corner, diag_corner); + sub_v2_v2v2(prev_diag_edge, diag_corner, next_corner); + + if (cross_v2v2(prev_edge, next_edge) < 0.0f) { + closest_to_line_v2(data->corner, data->corner, prev_corner, next_corner); + } + + if (cross_v2v2(next_diag_edge, prev_edge) < 0.0f) { + closest_to_line_v2(data->corner, data->corner, prev_corner, diag_corner); + } + + if (cross_v2v2(next_edge, prev_diag_edge) < 0.0f) { + closest_to_line_v2(data->corner, data->corner, next_corner, diag_corner); + } + + data->previous_mval[0] = event->mval[0]; + data->previous_mval[1] = event->mval[1]; + copy_v2_v2(data->previous_corner, data->corner); + + DAG_id_tag_update(&sc->clip->id, 0); + + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL); + + break; + + case LEFTMOUSE: + if (event->val == KM_RELEASE) { + /* Marker is now keyframed. */ + data->plane_marker->flag &= ~PLANE_MARKER_TRACKED; + + slide_plane_marker_update_homographies(sc, data); + + free_slide_plane_marker_data(op->customdata); + + show_cursor(C); + + DAG_id_tag_update(&sc->clip->id, 0); + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); + + return OPERATOR_FINISHED; + } + + break; + + case ESCKEY: + cancel_mouse_slide_plane_marker(op->customdata); + + free_slide_plane_marker_data(op->customdata); + + show_cursor(C); + + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); + + return OPERATOR_CANCELLED; + } + + return OPERATOR_RUNNING_MODAL; +} + +void CLIP_OT_slide_plane_marker(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Slide Plane Marker"; + ot->description = "Slide plane marker areas"; + ot->idname = "CLIP_OT_slide_plane_marker"; + + /* api callbacks */ + ot->poll = ED_space_clip_tracking_poll; + ot->invoke = slide_plane_marker_invoke; + ot->modal = slide_plane_marker_modal; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING; +} + +/********************** Insert track keyframe operator *********************/ + +static void keyframe_set_flag(bContext *C, bool set) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTracking *tracking = &clip->tracking; + ListBase *tracks_base = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; + int framenr = ED_space_clip_get_clip_frame_number(sc); + + for (track = tracks_base->first; track; track = track->next) { + if (TRACK_VIEW_SELECTED(sc, track)) { + if (set) { + MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr); + marker->flag &= ~MARKER_TRACKED; + } + else { + MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr); + if (marker) { + marker->flag |= MARKER_TRACKED; + } + } + } + } + + for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) { + if (plane_track->flag & SELECT) { + if (set) { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr); + if (plane_marker->flag & PLANE_MARKER_TRACKED) { + plane_marker->flag &= ~PLANE_MARKER_TRACKED; + BKE_tracking_track_plane_from_existing_motion(plane_track, plane_marker->framenr); + } + } + else { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, framenr); + if (plane_marker) { + if ((plane_marker->flag & PLANE_MARKER_TRACKED) == 0) { + plane_marker->flag |= PLANE_MARKER_TRACKED; + BKE_tracking_retrack_plane_from_existing_motion_at_segment(plane_track, plane_marker->framenr); + } + } + } + } + } + + WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); +} + +static int keyframe_insert_exec(bContext *C, wmOperator *UNUSED(op)) +{ + keyframe_set_flag(C, true); + return OPERATOR_FINISHED; +} + +void CLIP_OT_keyframe_insert(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Insert keyframe"; + ot->description = "Insert a keyframe to selected tracks at current frame"; + ot->idname = "CLIP_OT_keyframe_insert"; + + /* api callbacks */ + ot->poll = ED_space_clip_tracking_poll; + ot->exec = keyframe_insert_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************** Delete track keyframe operator *********************/ + +static int keyframe_delete_exec(bContext *C, wmOperator *UNUSED(op)) +{ + keyframe_set_flag(C, false); + return OPERATOR_FINISHED; +} + +void CLIP_OT_keyframe_delete(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete keyframe"; + ot->description = "Delete a keyframe from selected tracks at current frame"; + ot->idname = "CLIP_OT_keyframe_delete"; + + /* api callbacks */ + ot->poll = ED_space_clip_tracking_poll; + ot->exec = keyframe_delete_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index b03209173d8..7cb5f9b5dc0 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -169,6 +169,7 @@ static float dist_to_rect(float co[2], float pos[2], float min[2], float max[2]) return sqrtf(min_ffff(d1, d2, d3, d4)); } +/* Distance to quad defined by it's corners, corners are relative to pos */ static float dist_to_crns(float co[2], float pos[2], float crns[4][2]) { float d1, d2, d3, d4; @@ -184,7 +185,22 @@ static float dist_to_crns(float co[2], float pos[2], float crns[4][2]) return sqrtf(min_ffff(d1, d2, d3, d4)); } -static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbase, float co[2]) +/* Same as above, but all the coordinates are absolute */ +static float dist_to_crns_abs(float co[2], float corners[4][2]) +{ + float d1, d2, d3, d4; + float *v1 = corners[0], *v2 = corners[1]; + float *v3 = corners[2], *v4 = corners[3]; + + d1 = dist_squared_to_line_segment_v2(co, v1, v2); + d2 = dist_squared_to_line_segment_v2(co, v2, v3); + d3 = dist_squared_to_line_segment_v2(co, v3, v4); + d4 = dist_squared_to_line_segment_v2(co, v4, v1); + + return sqrtf(min_ffff(d1, d2, d3, d4)); +} + +static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbase, float co[2], float *distance_r) { MovieTrackingTrack *track = NULL, *cur; float mindist = 0.0f; @@ -221,19 +237,88 @@ static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbas cur = cur->next; } + *distance_r = mindist; + return track; } +static MovieTrackingPlaneTrack *find_nearest_plane_track(SpaceClip *sc, ListBase *plane_tracks_base, + float co[2], float *distance_r) +{ + MovieTrackingPlaneTrack *plane_track = NULL, *current_plane_track; + float min_distance = 0.0f; + int framenr = ED_space_clip_get_clip_frame_number(sc); + + for (current_plane_track = plane_tracks_base->first; + current_plane_track; + current_plane_track = current_plane_track->next) + { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(current_plane_track, framenr); + + if ((current_plane_track->flag & TRACK_HIDDEN) == 0) { + float distance = dist_to_crns_abs(co, plane_marker->corners); + if (plane_track == NULL || distance < min_distance) { + plane_track = current_plane_track; + min_distance = distance; + } + } + } + + *distance_r = min_distance; + + return plane_track; +} + +static void delect_all_tracks(ListBase *tracks_base) +{ + MovieTrackingTrack *track; + for (track = tracks_base->first; + track; + track = track->next) + { + BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT); + } +} + +static void delect_all_plane_tracks(ListBase *plane_tracks_base) +{ + MovieTrackingPlaneTrack *plane_track; + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + plane_track->flag &= ~SELECT; + } +} + static int mouse_select(bContext *C, float co[2], int extend) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); - MovieTrackingTrack *track = NULL; /* selected marker */ + MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; + float distance_to_track, distance_to_plane_track; + + track = find_nearest_track(sc, tracksbase, co, &distance_to_track); + plane_track = find_nearest_plane_track(sc, plane_tracks_base, co, &distance_to_plane_track); + + /* Between track and plane we choose closest to the mouse for selection here. */ + if (track && plane_track) { + if (distance_to_track < distance_to_plane_track) { + plane_track = NULL; + } + else { + track = NULL; + } + } - track = find_nearest_track(sc, tracksbase, co); + if (!extend) { + delect_all_plane_tracks(plane_tracks_base); + } if (track) { int area = track_mouse_area(C, co, track); @@ -242,10 +327,13 @@ static int mouse_select(bContext *C, float co[2], int extend) area = TRACK_AREA_ALL; if (extend && TRACK_AREA_SELECTED(track, area)) { - if (track == act_track) + if (track == act_track) { BKE_tracking_track_deselect(track, area); - else + } + else { clip->tracking.act_track = track; + clip->tracking.act_plane_track = NULL; + } } else { if (area == TRACK_AREA_POINT) @@ -253,8 +341,26 @@ static int mouse_select(bContext *C, float co[2], int extend) BKE_tracking_track_select(tracksbase, track, area, extend); clip->tracking.act_track = track; + clip->tracking.act_plane_track = NULL; } } + else if (plane_track) { + if (!extend) { + delect_all_tracks(tracksbase); + } + + if (plane_track->flag & SELECT) { + if (extend) { + plane_track->flag &= ~SELECT; + } + } + else { + plane_track->flag |= SELECT; + } + + clip->tracking.act_track = NULL; + clip->tracking.act_plane_track = plane_track; + } if (!extend) { sc->xlockof = 0.0f; @@ -350,10 +456,13 @@ static int border_select_exec(bContext *C, wmOperator *op) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); rcti rect; rctf rectf; - int change = FALSE, mode, extend; + bool change = false; + int mode, extend; int framenr = ED_space_clip_get_clip_frame_number(sc); /* get rectangle from operator */ @@ -382,13 +491,40 @@ static int border_select_exec(bContext *C, wmOperator *op) BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT); } - change = TRUE; + change = true; } } track = track->next; } + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) { + MovieTrackingPlaneMarker *plane_marker = + BKE_tracking_plane_marker_get(plane_track, framenr); + int i; + + for (i = 0; i < 4; i++) { + if (BLI_rctf_isect_pt_v(&rectf, plane_marker->corners[i])) { + if (mode == GESTURE_MODAL_SELECT) { + plane_track->flag |= SELECT; + } + else { + plane_track->flag &= ~SELECT; + } + } + else if (!extend) { + plane_track->flag &= ~SELECT; + } + } + + change = true; + } + } + if (change) { BKE_tracking_dopesheet_tag_update(tracking); @@ -430,9 +566,11 @@ static int do_lasso_select_marker(bContext *C, const int mcords[][2], const shor MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); rcti rect; - int change = FALSE; + bool change = false; int framenr = ED_space_clip_get_clip_frame_number(sc); /* get rectangle from operator */ @@ -459,13 +597,44 @@ static int do_lasso_select_marker(bContext *C, const int mcords[][2], const shor BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT); } - change = TRUE; + change = true; } } track = track->next; } + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) { + MovieTrackingPlaneMarker *plane_marker = + BKE_tracking_plane_marker_get(plane_track, framenr); + int i; + + for (i = 0; i < 4; i++) { + float screen_co[2]; + + /* marker in screen coords */ + ED_clip_point_stable_pos__reverse(sc, ar, plane_marker->corners[i], screen_co); + + if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) && + BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) + { + if (select) { + plane_track->flag |= SELECT; + } + else { + plane_track->flag &= ~SELECT; + } + } + } + + change = true; + } + } + if (change) { BKE_tracking_dopesheet_tag_update(tracking); @@ -518,17 +687,22 @@ void CLIP_OT_select_lasso(wmOperatorType *ot) /********************** circle select operator *********************/ -static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2]) +static int point_inside_ellipse(float point[2], float offset[2], float ellipse[2]) { /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ float x, y; - x = (marker->pos[0] - offset[0]) * ellipse[0]; - y = (marker->pos[1] - offset[1]) * ellipse[1]; + x = (point[0] - offset[0]) * ellipse[0]; + y = (point[1] - offset[1]) * ellipse[1]; return x * x + y * y < 1.0f; } +static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2]) +{ + return point_inside_ellipse(marker->pos, offset, ellipse); +} + static int circle_select_exec(bContext *C, wmOperator *op) { SpaceClip *sc = CTX_wm_space_clip(C); @@ -537,8 +711,11 @@ static int circle_select_exec(bContext *C, wmOperator *op) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); - int x, y, radius, width, height, mode, change = FALSE; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + int x, y, radius, width, height, mode; + bool change = false; float zoomx, zoomy, offset[2], ellipse[2]; int framenr = ED_space_clip_get_clip_frame_number(sc); @@ -570,13 +747,37 @@ static int circle_select_exec(bContext *C, wmOperator *op) else BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT); - change = TRUE; + change = true; } } track = track->next; } + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) { + MovieTrackingPlaneMarker *plane_marker = + BKE_tracking_plane_marker_get(plane_track, framenr); + int i; + + for (i = 0; i < 4; i++) { + if (point_inside_ellipse(plane_marker->corners[i], offset, ellipse)) { + if (mode == GESTURE_MODAL_SELECT) { + plane_track->flag |= SELECT; + } + else { + plane_track->flag &= ~SELECT; + } + } + } + + change = true; + } + } + if (change) { BKE_tracking_dopesheet_tag_update(tracking); @@ -619,16 +820,18 @@ static int select_all_exec(bContext *C, wmOperator *op) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *track = NULL; /* selected track */ + MovieTrackingPlaneTrack *plane_track = NULL; /* selected plane track */ MovieTrackingMarker *marker; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); int action = RNA_enum_get(op->ptr, "action"); int framenr = ED_space_clip_get_clip_frame_number(sc); - int has_selection = FALSE; + bool has_selection = false; if (action == SEL_TOGGLE) { action = SEL_SELECT; - track = tracksbase->first; - while (track) { + + for (track = tracksbase->first; track; track = track->next) { if (TRACK_VIEW_SELECTED(sc, track)) { marker = BKE_tracking_marker_get(track, framenr); @@ -637,13 +840,20 @@ static int select_all_exec(bContext *C, wmOperator *op) break; } } + } - track = track->next; + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (plane_track->flag & SELECT) { + action = SEL_DESELECT; + break; + } } } - track = tracksbase->first; - while (track) { + for (track = tracksbase->first; track; track = track->next) { if ((track->flag & TRACK_HIDDEN) == 0) { marker = BKE_tracking_marker_get(track, framenr); @@ -669,9 +879,30 @@ static int select_all_exec(bContext *C, wmOperator *op) } if (TRACK_VIEW_SELECTED(sc, track)) - has_selection = TRUE; + has_selection = true; + } - track = track->next; + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) { + switch (action) { + case SEL_SELECT: + plane_track->flag |= SELECT; + break; + case SEL_DESELECT: + plane_track->flag &= ~SELECT; + break; + case SEL_INVERT: + plane_track->flag ^= SELECT; + break; + } + } + + if (plane_track->flag & SELECT) { + has_selection = true; + } } if (!has_selection) @@ -716,7 +947,7 @@ static int select_groped_exec(bContext *C, wmOperator *op) track = tracksbase->first; while (track) { - int ok = FALSE; + bool ok = false; marker = BKE_tracking_marker_get(track, framenr); diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c index c10ea96096f..289986d7fba 100644 --- a/source/blender/editors/space_console/console_ops.c +++ b/source/blender/editors/space_console/console_ops.c @@ -681,6 +681,7 @@ static int console_clear_exec(bContext *C, wmOperator *op) if (history) { while (sc->history.first) console_history_free(sc, sc->history.first); + console_history_verify(C); } console_textview_update_rect(sc, ar); diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index 88a04197847..5c8d1e84fd5 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -317,6 +317,7 @@ static void console_keymap(struct wmKeyConfig *keyconf) RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", BACKSPACEKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_PREV_WORD); WM_keymap_add_item(keymap, "CONSOLE_OT_clear_line", RETKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "CONSOLE_OT_clear_line", PADENTER, KM_PRESS, KM_SHIFT, 0); #ifdef WITH_PYTHON kmi = WM_keymap_add_item(keymap, "CONSOLE_OT_execute", RETKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 240106d37d5..d01286442be 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -65,7 +65,7 @@ void FILE_OT_select_all_toggle(struct wmOperatorType *ot); void FILE_OT_select_border(struct wmOperatorType *ot); void FILE_OT_select_bookmark(struct wmOperatorType *ot); void FILE_OT_bookmark_add(struct wmOperatorType *ot); -void FILE_OT_delete_bookmark(struct wmOperatorType *ot); +void FILE_OT_bookmark_delete(struct wmOperatorType *ot); void FILE_OT_reset_recent(wmOperatorType *ot); void FILE_OT_hidedot(struct wmOperatorType *ot); void FILE_OT_execute(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index e3270d9ce8e..a97b3b1d719 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -503,14 +503,14 @@ static int bookmark_delete_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void FILE_OT_delete_bookmark(wmOperatorType *ot) +void FILE_OT_bookmark_delete(wmOperatorType *ot) { PropertyRNA *prop; /* identifiers */ ot->name = "Delete Bookmark"; ot->description = "Delete selected bookmark"; - ot->idname = "FILE_OT_delete_bookmark"; + ot->idname = "FILE_OT_bookmark_delete"; /* api callbacks */ ot->exec = bookmark_delete_exec; diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index d6f644ab330..f4161c7da1c 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -115,12 +115,13 @@ static void file_panel_category(const bContext *C, Panel *pa, FSMenuCategory cat /* create list item */ but = uiDefIconTextButS(block, LISTROW, 0, icon, dir, 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, nr, 0, i, 0, 0, entry); uiButSetFunc(but, file_panel_cb, entry, NULL); + uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ uiButSetFlag(but, UI_ICON_LEFT | UI_TEXT_LEFT); /* create delete button */ if (allow_delete && fsmenu_can_save(fsmenu, category, i)) { uiBlockSetEmboss(block, UI_EMBOSSN); - uiItemIntO(layout, "", ICON_X, "FILE_OT_delete_bookmark", "index", i); + uiItemIntO(layout, "", ICON_X, "FILE_OT_bookmark_delete", "index", i); uiBlockSetEmboss(block, UI_EMBOSS); } } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 8f25ac38963..19a6296993d 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -152,17 +152,27 @@ static ImBuf *gSpecialFileImages[SPECIAL_IMG_MAX]; /* ******************* SORT ******************* */ +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 false; +} + static int compare_name(const void *a1, const void *a2) { const struct direntry *entry1 = a1, *entry2 = a2; /* type is equal to stat.st_mode */ - if (S_ISDIR(entry1->type)) { - if (S_ISDIR(entry2->type) == 0) return (-1); + if (compare_is_directory(entry1)) { + if (compare_is_directory(entry2) == 0) return (-1); } else { - if (S_ISDIR(entry2->type)) return (1); + if (compare_is_directory(entry2)) return (1); } if (S_ISREG(entry1->type)) { if (S_ISREG(entry2->type) == 0) return (-1); @@ -188,11 +198,11 @@ static int compare_date(const void *a1, const void *a2) /* type is equal to stat.st_mode */ - if (S_ISDIR(entry1->type)) { - if (S_ISDIR(entry2->type) == 0) return (-1); + if (compare_is_directory(entry1)) { + if (compare_is_directory(entry2) == 0) return (-1); } else { - if (S_ISDIR(entry2->type)) return (1); + if (compare_is_directory(entry2)) return (1); } if (S_ISREG(entry1->type)) { if (S_ISREG(entry2->type) == 0) return (-1); @@ -221,11 +231,11 @@ static int compare_size(const void *a1, const void *a2) /* type is equal to stat.st_mode */ - if (S_ISDIR(entry1->type)) { - if (S_ISDIR(entry2->type) == 0) return (-1); + if (compare_is_directory(entry1)) { + if (compare_is_directory(entry2) == 0) return (-1); } else { - if (S_ISDIR(entry2->type)) return (1); + if (compare_is_directory(entry2)) return (1); } if (S_ISREG(entry1->type)) { if (S_ISREG(entry2->type) == 0) return (-1); @@ -262,11 +272,11 @@ static int compare_extension(const void *a1, const void *a2) /* type is equal to stat.st_mode */ - if (S_ISDIR(entry1->type)) { - if (S_ISDIR(entry2->type) == 0) return (-1); + if (compare_is_directory(entry1)) { + if (compare_is_directory(entry2) == 0) return (-1); } else { - if (S_ISDIR(entry2->type)) return (1); + if (compare_is_directory(entry2)) return (1); } if (S_ISREG(entry1->type)) { if (S_ISREG(entry2->type) == 0) return (-1); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 85e4d255603..9d762c80405 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -59,6 +59,7 @@ #include "BLI_dynstr.h" #include "BLI_utildefines.h" #include "BLI_fileops_types.h" +#include "BLI_fnmatch.h" #include "BKE_context.h" #include "BKE_global.h" @@ -81,12 +82,6 @@ #include "file_intern.h" #include "filelist.h" -#if defined WIN32 && !defined _LIBC -# include "BLI_fnmatch.h" /* use fnmatch included in blenlib */ -#else -# include <fnmatch.h> -#endif - FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile) { if (!sfile->params) { @@ -115,6 +110,7 @@ short ED_fileselect_set_params(SpaceFile *sfile) /* set the parameters from the operator, if it exists */ if (op) { + PropertyRNA *prop; const short is_files = (RNA_struct_find_property(op->ptr, "files") != NULL); const short is_filepath = (RNA_struct_find_property(op->ptr, "filepath") != NULL); const short is_filename = (RNA_struct_find_property(op->ptr, "filename") != NULL); @@ -163,30 +159,30 @@ short ED_fileselect_set_params(SpaceFile *sfile) } params->filter = 0; - if (RNA_struct_find_property(op->ptr, "filter_blender")) - params->filter |= RNA_boolean_get(op->ptr, "filter_blender") ? BLENDERFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_backup")) - params->filter |= RNA_boolean_get(op->ptr, "filter_backup") ? BLENDERFILE_BACKUP : 0; - if (RNA_struct_find_property(op->ptr, "filter_image")) - params->filter |= RNA_boolean_get(op->ptr, "filter_image") ? IMAGEFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_movie")) - params->filter |= RNA_boolean_get(op->ptr, "filter_movie") ? MOVIEFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_python")) - params->filter |= RNA_boolean_get(op->ptr, "filter_python") ? PYSCRIPTFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_font")) - params->filter |= RNA_boolean_get(op->ptr, "filter_font") ? FTFONTFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_sound")) - params->filter |= RNA_boolean_get(op->ptr, "filter_sound") ? SOUNDFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_text")) - params->filter |= RNA_boolean_get(op->ptr, "filter_text") ? TEXTFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_folder")) - params->filter |= RNA_boolean_get(op->ptr, "filter_folder") ? FOLDERFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_btx")) - params->filter |= RNA_boolean_get(op->ptr, "filter_btx") ? BTXFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_collada")) - params->filter |= RNA_boolean_get(op->ptr, "filter_collada") ? COLLADAFILE : 0; - if (RNA_struct_find_property(op->ptr, "filter_glob")) { - RNA_string_get(op->ptr, "filter_glob", params->filter_glob); + if ((prop = RNA_struct_find_property(op->ptr, "filter_blender"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? BLENDERFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_backup"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? BLENDERFILE_BACKUP : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_image"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? IMAGEFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_movie"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? MOVIEFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_python"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? PYSCRIPTFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_font"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FTFONTFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_sound"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? SOUNDFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_text"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? TEXTFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_folder"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FOLDERFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_btx"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? BTXFILE : 0; + if ((prop = RNA_struct_find_property(op->ptr, "filter_collada"))) + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? COLLADAFILE : 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); } else { diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 6f3d0367574..1a8565a58b1 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -148,7 +148,6 @@ static void file_free(SpaceLink *sl) static void file_init(wmWindowManager *UNUSED(wm), ScrArea *sa) { SpaceFile *sfile = (SpaceFile *)sa->spacedata.first; - //printf("file_init\n"); /* refresh system directory list */ fsmenu_refresh_system_category(fsmenu_get()); @@ -313,7 +312,6 @@ static void file_main_area_draw(const bContext *C, ARegion *ar) /* draw entirely, view changes should be handled here */ SpaceFile *sfile = CTX_wm_space_file(C); FileSelectParams *params = ED_fileselect_get_params(sfile); - FileLayout *layout = NULL; View2D *v2d = &ar->v2d; View2DScrollers *scrollers; @@ -323,15 +321,14 @@ static void file_main_area_draw(const bContext *C, ARegion *ar) if (!sfile->files || filelist_empty(sfile->files)) file_refresh(C, NULL); - layout = ED_fileselect_get_layout(sfile, ar); - /* clear and setup matrix */ UI_GetThemeColor3fv(TH_BACK, col); glClearColor(col[0], col[1], col[2], 0.0); glClear(GL_COLOR_BUFFER_BIT); /* Allow dynamically sliders to be set, saves notifiers etc. */ - if (layout && (layout->flag == FILE_LAYOUT_VER)) { + + if (params->display == FILE_IMGDISPLAY) { v2d->scroll = V2D_SCROLL_RIGHT; v2d->keepofs &= ~V2D_LOCKOFS_Y; v2d->keepofs |= V2D_LOCKOFS_X; @@ -390,7 +387,7 @@ static void file_operatortypes(void) WM_operatortype_append(FILE_OT_refresh); WM_operatortype_append(FILE_OT_bookmark_toggle); WM_operatortype_append(FILE_OT_bookmark_add); - WM_operatortype_append(FILE_OT_delete_bookmark); + WM_operatortype_append(FILE_OT_bookmark_delete); WM_operatortype_append(FILE_OT_reset_recent); WM_operatortype_append(FILE_OT_hidedot); WM_operatortype_append(FILE_OT_filenum); diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 7610f7a9192..23c39a5e99a 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -951,7 +951,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid /* 1) draw curve line */ { /* set color/drawing style for curve itself */ - if (((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) || (fcu->flag & FCURVE_PROTECTED)) { + if (BKE_fcurve_is_protected(fcu)) { /* protected curves (non editable) are drawn with dotted lines */ setlinestyle(2); } diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 9d22d6fcc95..274c06bf871 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -214,7 +214,8 @@ void GRAPH_OT_previewrange_set(wmOperatorType *ot) /* ****************** View-All Operator ****************** */ -static int graphkeys_viewall(bContext *C, const short do_sel_only, const short include_handles) +static int graphkeys_viewall(bContext *C, const short do_sel_only, const short include_handles, + const int smooth_viewtx) { bAnimContext ac; rctf cur_new; @@ -231,7 +232,7 @@ static int graphkeys_viewall(bContext *C, const short do_sel_only, const short i BLI_rctf_scale(&cur_new, 1.1f); - UI_view2d_smooth_view(C, ac.ar, &cur_new); + UI_view2d_smooth_view(C, ac.ar, &cur_new, smooth_viewtx); return OPERATOR_FINISHED; } @@ -240,18 +241,20 @@ static int graphkeys_viewall(bContext *C, const short do_sel_only, const short i static int graphkeys_viewall_exec(bContext *C, wmOperator *op) { - short include_handles = RNA_boolean_get(op->ptr, "include_handles"); + const short include_handles = RNA_boolean_get(op->ptr, "include_handles"); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); /* whole range */ - return graphkeys_viewall(C, FALSE, include_handles); + return graphkeys_viewall(C, false, include_handles, smooth_viewtx); } static int graphkeys_view_selected_exec(bContext *C, wmOperator *op) { - short include_handles = RNA_boolean_get(op->ptr, "include_handles"); + const short include_handles = RNA_boolean_get(op->ptr, "include_handles"); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); /* only selected */ - return graphkeys_viewall(C, TRUE, include_handles); + return graphkeys_viewall(C, true, include_handles, smooth_viewtx); } void GRAPH_OT_view_all(wmOperatorType *ot) @@ -882,8 +885,12 @@ static void delete_graph_keys(bAnimContext *ac) delete_fcurve_keys(fcu); /* Only delete curve too if it won't be doing anything anymore */ - if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) + if ((fcu->totvert == 0) && + (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) && + (fcu->driver == NULL)) + { ANIM_fcurve_delete_from_animdata(ac, adt, fcu); + } } /* free filtered list */ @@ -1676,7 +1683,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op) /* FIXME: there are more complicated methods that will be needed to fix more cases than just some */ for (f = 0; f < 3; f++) { FCurve *fcu = euf->fcurves[f]; - BezTriple *bezt, *prev = NULL; + BezTriple *bezt, *prev; unsigned int i; /* skip if not enough vets to do a decent analysis of... */ @@ -1684,29 +1691,19 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op) continue; /* prev follows bezt, bezt = "current" point to be fixed */ - for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, prev = bezt, bezt++) { - /* our method depends on determining a "difference" from the previous vert */ - if (prev == NULL) - continue; + /* our method depends on determining a "difference" from the previous vert */ + for (i = 1, prev = fcu->bezt, bezt = fcu->bezt + 1; i < fcu->totvert; i++, prev = bezt++) { + const float sign = (prev->vec[1][1] > bezt->vec[1][1]) ? 1.0f : -1.0f; /* > 180 degree flip? */ - if (fabs(prev->vec[1][1] - bezt->vec[1][1]) >= M_PI) { + if ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) { /* 360 degrees to add/subtract frame value until difference is acceptably small that there's no more flip */ - const float fac = 2.0f * (float)M_PI; + const float fac = sign * 2.0f * (float)M_PI; - if (prev->vec[1][1] > bezt->vec[1][1]) { - while (fabsf(bezt->vec[1][1] - prev->vec[1][1]) >= (float)M_PI) { - bezt->vec[0][1] += fac; - bezt->vec[1][1] += fac; - bezt->vec[2][1] += fac; - } - } - else { /* if (prev->vec[1][1] < bezt->vec[1][1]) */ - while (fabsf(bezt->vec[1][1] - prev->vec[1][1]) >= (float)M_PI) { - bezt->vec[0][1] -= fac; - bezt->vec[1][1] -= fac; - bezt->vec[2][1] -= fac; - } + while ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) { + bezt->vec[0][1] += fac; + bezt->vec[1][1] += fac; + bezt->vec[2][1] += fac; } } } diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index cbec3072c44..d87bd9a5077 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -149,17 +149,37 @@ static void deselect_graph_keys(bAnimContext *ac, short test, short sel, short d static int graphkeys_deselectall_exec(bContext *C, wmOperator *op) { bAnimContext ac; + bAnimListElem *ale_active = NULL; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - + + /* find active F-Curve, and preserve this for later + * or else it becomes annoying with the current active + * curve keeps fading out even while you're editing it + */ + ale_active = get_active_fcurve_channel(&ac); + /* 'standard' behavior - check if selected, then apply relevant selection */ if (RNA_boolean_get(op->ptr, "invert")) deselect_graph_keys(&ac, 0, SELECT_INVERT, TRUE); else deselect_graph_keys(&ac, 1, SELECT_ADD, TRUE); + /* restore active F-Curve... */ + if (ale_active) { + FCurve *fcu = (FCurve *)ale_active->data; + + /* all others should not be disabled, so we should be able to just set this directly... + * - selection needs to be set too, or else this won't work... + */ + fcu->flag |= (FCURVE_SELECTED | FCURVE_ACTIVE); + + MEM_freeN(ale_active); + ale_active = NULL; + } + /* set notifier that things have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -1049,10 +1069,7 @@ static tNearestVertInfo *get_best_nearest_fcurve_vert(ListBase *matches) /* if list only has 1 item, remove it from the list and return */ if (matches->first == matches->last) { /* need to remove from the list, otherwise it gets freed and then we can't return it */ - nvi = matches->first; - BLI_remlink(matches, nvi); - - return nvi; + return BLI_pophead(matches); } /* try to find the first selected F-Curve vert, then take the one after it */ @@ -1075,9 +1092,7 @@ static tNearestVertInfo *get_best_nearest_fcurve_vert(ListBase *matches) /* if we're still here, this means that we failed to find anything appropriate in the first pass, * so just take the first item now... */ - nvi = matches->first; - BLI_remlink(matches, nvi); - return nvi; + return BLI_pophead(matches); } /* Find the nearest vertices (either a handle or the keyframe) that are nearest to the mouse cursor (in area coordinates) diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 23c85699b00..89e57955339 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -268,8 +268,6 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int use_def else rgba[3] = linearcol[3]; - (void)color_manage; - if (use_default_view) IMB_colormanagement_pixel_to_display_space_v4(rgba, rgba, NULL, &scene->display_settings); else @@ -360,14 +358,8 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int use_def dx += BLF_width(blf_mono_font, str); } else if (channels >= 3) { - if (fp) { - rgb_to_hsv(fp[0], fp[1], fp[2], &hue, &sat, &val); - rgb_to_yuv(fp[0], fp[1], fp[2], &lum, &u, &v); - } - else if (cp) { - rgb_to_hsv((float)cp[0] / 255.0f, (float)cp[1] / 255.0f, (float)cp[2] / 255.0f, &hue, &sat, &val); - rgb_to_yuv((float)cp[0] / 255.0f, (float)cp[1] / 255.0f, (float)cp[2] / 255.0f, &lum, &u, &v); - } + rgb_to_hsv(finalcol[0], finalcol[1], finalcol[2], &hue, &sat, &val); + rgb_to_yuv(finalcol[0], finalcol[1], finalcol[2], &lum, &u, &v); BLI_snprintf(str, sizeof(str), "H:%-.4f", hue); BLF_position(blf_mono_font, dx, 0.3f * UI_UNIT_X, 0); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 2da3f3adb67..710d5c8cd81 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -245,7 +245,7 @@ static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *even ViewPanData *vpd; op->customdata = vpd = MEM_callocN(sizeof(ViewPanData), "ImageViewPanData"); - WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR); vpd->x = event->x; vpd->y = event->y; @@ -267,7 +267,7 @@ static void image_view_pan_exit(bContext *C, wmOperator *op, int cancel) ED_region_tag_redraw(CTX_wm_region(C)); } - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); MEM_freeN(op->customdata); } @@ -391,7 +391,7 @@ static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *eve ViewZoomData *vpd; op->customdata = vpd = MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData"); - WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR); + WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR); vpd->origx = event->x; vpd->origy = event->y; @@ -425,7 +425,7 @@ static void image_view_zoom_exit(bContext *C, wmOperator *op, int cancel) if (vpd->timer) WM_event_remove_timer(CTX_wm_manager(C), vpd->timer->win, vpd->timer); - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); MEM_freeN(op->customdata); } @@ -646,12 +646,13 @@ void IMAGE_OT_view_ndof(wmOperatorType *ot) * Default behavior is to reset the position of the image and set the zoom to 1 * If the image will not fit within the window rectangle, the zoom is adjusted */ -static int image_view_all_exec(bContext *C, wmOperator *UNUSED(op)) +static int image_view_all_exec(bContext *C, wmOperator *op) { SpaceImage *sima; ARegion *ar; float aspx, aspy, zoomx, zoomy, w, h; int width, height; + int fit_view = RNA_boolean_get(op->ptr, "fit_view"); /* retrieve state */ sima = CTX_wm_space_image(C); @@ -667,14 +668,25 @@ static int image_view_all_exec(bContext *C, wmOperator *UNUSED(op)) width = BLI_rcti_size_x(&ar->winrct) + 1; height = BLI_rcti_size_y(&ar->winrct) + 1; - if ((w >= width || h >= height) && (width > 0 && height > 0)) { - /* find the zoom value that will fit the image in the image space */ - zoomx = width / w; - zoomy = height / h; - sima_zoom_set(sima, ar, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), NULL); + if (fit_view) { + const int margin = 5; /* margin from border */ + + zoomx = (float) width / (w + 2 * margin); + zoomy = (float) height / (h + 2 * margin); + + sima_zoom_set(sima, ar, min_ff(zoomx, zoomy), NULL); + } + else { + if ((w >= width || h >= height) && (width > 0 && height > 0)) { + zoomx = (float) width / w; + zoomy = (float) height / h; + + /* find the zoom value that will fit the image in the image space */ + sima_zoom_set(sima, ar, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), NULL); + } + else + sima_zoom_set(sima, ar, 1.0f, NULL); } - else - sima_zoom_set(sima, ar, 1.0f, NULL); sima->xof = sima->yof = 0.0f; @@ -685,6 +697,8 @@ static int image_view_all_exec(bContext *C, wmOperator *UNUSED(op)) void IMAGE_OT_view_all(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "View All"; ot->idname = "IMAGE_OT_view_all"; @@ -693,6 +707,10 @@ void IMAGE_OT_view_all(wmOperatorType *ot) /* api callbacks */ ot->exec = image_view_all_exec; ot->poll = space_image_main_area_poll; + + /* properties */ + prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /********************** view selected operator *********************/ @@ -1318,7 +1336,7 @@ static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI const char *relbase = ID_BLEND_PATH(CTX_data_main(C), &ima->id); const short relative = (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path")); const short save_copy = (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy")); - const short save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render")); + const bool save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render")); ImageFormatData *imf = &simopts->im_format; short ok = FALSE; @@ -1344,7 +1362,7 @@ static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI } } - colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, TRUE, &imf->view_settings, &imf->display_settings, imf); + colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf); if (simopts->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { Scene *scene = CTX_data_scene(C); @@ -1786,6 +1804,8 @@ static int image_new_exec(bContext *C, wmOperator *op) BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE); + WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima); + return OPERATOR_FINISHED; } @@ -2397,6 +2417,9 @@ static int image_sample_line_exec(bContext *C, wmOperator *op) hist->co[1][0] = x2f; hist->co[1][1] = y2f; + /* enable line drawing */ + hist->flag |= HISTO_FLAG_SAMPLELINE; + BKE_histogram_update_sample_line(hist, ibuf, &scene->view_settings, &scene->display_settings); /* reset y zoom */ @@ -2539,7 +2562,7 @@ static void image_record_composite_exit(bContext *C, wmOperator *op) scene->r.cfra = rcd->old_cfra; - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); if (rcd->timer) WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rcd->timer); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index c0ef59e9e25..5a8292abcab 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -277,6 +277,10 @@ static void image_keymap(struct wmKeyConfig *keyconf) keymap = WM_keymap_find(keyconf, "Image", SPACE_IMAGE, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_all", HOMEKEY, KM_PRESS, 0, 0); + + kmi = WM_keymap_add_item(keymap, "IMAGE_OT_view_all", FKEY, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "fit_view", TRUE); + WM_keymap_add_item(keymap, "IMAGE_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MIDDLEMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0); @@ -670,7 +674,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) } else if (sima->mode == SI_MODE_MASK) { mask = ED_space_image_get_mask(sima); - draw_image_cursor(sima, ar); + draw_image_cursor(ar, sima->cursor); } ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); @@ -719,7 +723,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) ED_mask_draw_frames(mask, ar, CFRA, mask->sfra, mask->efra); - draw_image_cursor(sima, ar); + draw_image_cursor(ar, sima->cursor); } /* scrollers? */ diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 98c9c8d15fe..9686c6dfc29 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -115,8 +115,8 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) { int totv = 0, totf = 0, tottri = 0; - if (ob->disp.first) - BKE_displist_count(&ob->disp, &totv, &totf, &tottri); + if (ob->curve_cache && ob->curve_cache->disp.first) + BKE_displist_count(&ob->curve_cache->disp, &totv, &totf, &tottri); totv *= totob; totf *= totob; @@ -194,9 +194,9 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) a = nu->pntsu; while (a--) { stats->totvert += 3; - if (bezt->f1) stats->totvertsel++; - if (bezt->f2) stats->totvertsel++; - if (bezt->f3) stats->totvertsel++; + if (bezt->f1 & SELECT) stats->totvertsel++; + if (bezt->f2 & SELECT) stats->totvertsel++; + if (bezt->f3 & SELECT) stats->totvertsel++; bezt++; } } diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index e53cbdd04af..d4d45af6431 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -57,6 +57,7 @@ static void console_font_begin(TextViewContext *sc) typedef struct ConsoleDrawContext { int cwidth; int lheight; + int lofs; /* text vertical offset */ int console_width; /* number of characters that fit into the width of the console (fixed width) */ int winx; int ymin, ymax; @@ -122,7 +123,6 @@ static int console_wrap_offsets(const char *str, int len, int width, int *lines, static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str_len, const unsigned char fg[3], const unsigned char bg[3], const unsigned char bg_sel[4]) { - int rct_ofs = cdc->lheight / 4; int tot_lines; /* total number of lines for wrapping */ int *offsets; /* offsets of line beginnings for wrapping */ int y_next; @@ -186,13 +186,13 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str if (bg) { glColor3ubv(bg); - glRecti(0, cdc->xy[1] - rct_ofs, cdc->winx, (cdc->xy[1] + (cdc->lheight * tot_lines)) + rct_ofs); + glRecti(0, cdc->xy[1], cdc->winx, (cdc->xy[1] + (cdc->lheight * tot_lines))); } glColor3ubv(fg); /* last part needs no clipping */ - BLF_position(mono, cdc->xy[0], cdc->xy[1], 0); + BLF_position(mono, cdc->xy[0], cdc->lofs + cdc->xy[1], 0); BLF_draw_mono(mono, s, len, cdc->cwidth); if (cdc->sel[0] != cdc->sel[1]) { @@ -208,7 +208,7 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str len = offsets[i] - offsets[i - 1]; s = str + offsets[i - 1]; - BLF_position(mono, cdc->xy[0], cdc->xy[1], 0); + BLF_position(mono, cdc->xy[0], cdc->lofs + cdc->xy[1], 0); BLF_draw_mono(mono, s, len, cdc->cwidth); if (cdc->sel[0] != cdc->sel[1]) { @@ -234,12 +234,12 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str if (bg) { glColor3ubv(bg); - glRecti(0, cdc->xy[1] - rct_ofs, cdc->winx, cdc->xy[1] + cdc->lheight - rct_ofs); + glRecti(0, cdc->xy[1], cdc->winx, cdc->xy[1] + cdc->lheight); } glColor3ubv(fg); - BLF_position(mono, cdc->xy[0], cdc->xy[1], 0); + BLF_position(mono, cdc->xy[0], cdc->lofs + cdc->xy[1], 0); BLF_draw_mono(mono, str, str_len, cdc->cwidth); if (cdc->sel[0] != cdc->sel[1]) { @@ -291,6 +291,7 @@ int textview_draw(TextViewContext *tvc, const int draw, int mval[2], void **mous cdc.cwidth = (int)BLF_fixed_width(mono); assert(cdc.cwidth > 0); cdc.lheight = tvc->lheight; + cdc.lofs = -BLF_descender(mono); /* note, scroll bar must be already subtracted () */ cdc.console_width = (tvc->winx - (CONSOLE_DRAW_MARGIN * 2) ) / cdc.cwidth; CLAMP(cdc.console_width, 1, INT_MAX); /* avoid divide by zero on small windows */ diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h index 653c9b83a50..2f9e518ed47 100644 --- a/source/blender/editors/space_info/textview.h +++ b/source/blender/editors/space_info/textview.h @@ -24,6 +24,8 @@ * \ingroup spinfo */ +#ifndef __TEXTVIEW_H__ +#define __TEXTVIEW_H__ typedef struct TextViewContext { int lheight; @@ -59,3 +61,5 @@ int textview_draw(struct TextViewContext *tvc, const int draw, int mval[2], void #define TVC_LINE_FG (1<<0) #define TVC_LINE_BG (1<<1) + +#endif /* __TEXTVIEW_H__ */ diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c index fadf4c0b113..fac564f33fb 100644 --- a/source/blender/editors/space_logic/logic_ops.c +++ b/source/blender/editors/space_logic/logic_ops.c @@ -739,16 +739,17 @@ static void LOGIC_OT_texface_convert(wmOperatorType *ot) /* ************************ view ********************* */ -static int logic_view_all_exec(bContext *C, wmOperator *UNUSED(op)) +static int logic_view_all_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); rctf cur_new = ar->v2d.tot; float aspect = BLI_rctf_size_y(&ar->v2d.cur) / BLI_rctf_size_x(&ar->v2d.cur); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); /* force the view2d code to zoom to width, not height */ cur_new.ymin = cur_new.ymax - BLI_rctf_size_x(&cur_new) * aspect; - UI_view2d_smooth_view(C, ar, &cur_new); + UI_view2d_smooth_view(C, ar, &cur_new, smooth_viewtx); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 2957edd941b..2c89d6f6448 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -427,8 +427,6 @@ static const char *sensor_name(int type) switch (type) { case SENS_ALWAYS: return "Always"; - case SENS_TOUCH: - return "Touch"; case SENS_NEAR: return "Near"; case SENS_KEYBOARD: @@ -1233,11 +1231,6 @@ static void draw_sensor_ray(uiLayout *layout, PointerRNA *ptr, bContext *C) uiItemR(row, ptr, "use_x_ray", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); } -static void draw_sensor_touch(uiLayout *layout, PointerRNA *ptr) -{ - uiItemR(layout, ptr, "material", 0, NULL, ICON_NONE); -} - static void draw_brick_sensor(uiLayout *layout, PointerRNA *ptr, bContext *C) { uiLayout *box; @@ -1292,9 +1285,6 @@ static void draw_brick_sensor(uiLayout *layout, PointerRNA *ptr, bContext *C) case SENS_RAY: draw_sensor_ray(box, ptr, C); break; - case SENS_TOUCH: - draw_sensor_touch(box, ptr); - break; } } @@ -1465,6 +1455,7 @@ static void draw_actuator_action(uiLayout *layout, PointerRNA *ptr) row = uiLayoutRow(layout, FALSE); uiItemR(row, ptr, "layer", 0, NULL, ICON_NONE); uiItemR(row, ptr, "layer_weight", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "blend_mode", 0, "", ICON_NONE); uiItemPointerR(layout, ptr, "frame_property", &settings_ptr, "properties", NULL, ICON_NONE); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index cf3c0454e6b..f562212f1e2 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -571,7 +571,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED( */ #if 0 /* body */ - uiSetRoundBox(15); + uiSetRoundBox(UI_CNR_ALL); UI_ThemeColor4(TH_NODE); glEnable(GL_BLEND); uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, size); @@ -709,6 +709,8 @@ static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), Poin { uiLayout *row; + uiItemR(layout, ptr, "vector_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemL(layout, IFACE_("Location:"), ICON_NONE); row = uiLayoutRow(layout, TRUE); uiItemR(row, ptr, "translation", 0, "", ICON_NONE); @@ -737,7 +739,7 @@ static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), Po static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, ptr, "vector_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); uiItemR(layout, ptr, "convert_from", 0, "", ICON_NONE); uiItemR(layout, ptr, "convert_to", 0, "", ICON_NONE); } @@ -809,9 +811,13 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin } static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ +{ + uiItemR(layout, ptr, "sky_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "sun_direction", 0, "", ICON_NONE); uiItemR(layout, ptr, "turbidity", 0, NULL, ICON_NONE); + + if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NEW) + uiItemR(layout, ptr, "ground_albedo", 0, NULL, ICON_NONE); } static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -907,11 +913,29 @@ static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), Point uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE); } +static void node_shader_buts_subsurface(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + /* SSS does not work on GPU yet */ + PointerRNA scene = CTX_data_pointer_get(C, "scene"); + if (scene.data) { + PointerRNA cscene = RNA_pointer_get(&scene, "cycles"); + if (cscene.data && RNA_enum_get(&cscene, "device") == 1) + uiItemL(layout, IFACE_("SSS not supported on GPU"), ICON_ERROR); + } + + uiItemR(layout, ptr, "falloff", 0, "", ICON_NONE); +} + static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "component", 0, "", ICON_NONE); } +static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "component", 0, "", ICON_NONE); +} + static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayout *row; @@ -1039,9 +1063,15 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_BSDF_REFRACTION: ntype->uifunc = node_shader_buts_glossy; break; + case SH_NODE_SUBSURFACE_SCATTERING: + ntype->uifunc = node_shader_buts_subsurface; + break; case SH_NODE_BSDF_TOON: ntype->uifunc = node_shader_buts_toon; break; + case SH_NODE_BSDF_HAIR: + ntype->uifunc = node_shader_buts_hair; + break; case SH_NODE_SCRIPT: ntype->uifunc = node_shader_buts_script; ntype->uifuncbut = node_shader_buts_script_details; @@ -1620,12 +1650,14 @@ static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C active_index = RNA_int_get(ptr, "active_input_index"); /* using different collection properties if multilayer format is enabled */ if (multilayer) { - uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "layer_slots", ptr, "active_input_index", 0, 0, 0); + uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "layer_slots", ptr, "active_input_index", + 0, 0, 0, 0); RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr); } else { - uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "file_slots", ptr, "active_input_index", 0, 0, 0); + uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "file_slots", ptr, "active_input_index", + 0, 0, 0, 0); RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr); } @@ -2225,6 +2257,39 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN } } +static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + bNode *node = ptr->data; + + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); + + if (node->id) { + MovieClip *clip = (MovieClip *) node->id; + MovieTracking *tracking = &clip->tracking; + MovieTrackingObject *object; + uiLayout *col; + PointerRNA tracking_ptr; + NodeTrackPosData *data = node->storage; + + RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr); + + col = uiLayoutColumn(layout, FALSE); + uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA); + + object = BKE_tracking_object_get_named(tracking, data->tracking_object); + if (object) { + PointerRNA object_ptr; + + RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr); + + uiItemPointerR(col, ptr, "plane_track_name", &object_ptr, "plane_tracks", "", ICON_ANIM_DATA); + } + else { + uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA); + } + } +} + /* only once called */ static void node_composit_set_butfunc(bNodeType *ntype) { @@ -2444,6 +2509,9 @@ static void node_composit_set_butfunc(bNodeType *ntype) case CMP_NODE_TRACKPOS: ntype->uifunc = node_composit_buts_trackpos; break; + case CMP_NODE_PLANETRACKDEFORM: + ntype->uifunc = node_composit_buts_planetrackdeform; + break; } } @@ -3025,7 +3093,16 @@ int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, floa { float dist, vec[4][2]; float deltax, deltay; + float cursor[2] = {0.0f, 0.0f}; int toreroute, fromreroute; + + /* this function can be called with snode null (via cut_links_intersect) */ + /* XXX map snode->cursor back to view space */ + if (snode) { + cursor[0] = snode->cursor[0] * UI_DPI_FAC; + cursor[1] = snode->cursor[1] * UI_DPI_FAC; + } + /* in v0 and v3 we put begin/end points */ if (link->fromsock) { vec[0][0] = link->fromsock->locx; @@ -3034,7 +3111,7 @@ int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, floa } else { if (snode == NULL) return 0; - copy_v2_v2(vec[0], snode->cursor); + copy_v2_v2(vec[0], cursor); fromreroute = 0; } if (link->tosock) { @@ -3044,7 +3121,7 @@ int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, floa } else { if (snode == NULL) return 0; - copy_v2_v2(vec[3], snode->cursor); + copy_v2_v2(vec[3], cursor); toreroute = 0; } diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index c9618daa7c5..00769975893 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -84,10 +84,6 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx node->locy = locy + 60.0f; /* arbitrary... so its visible, (0,0) is top of node */ nodeSetSelected(node, TRUE); - /* node location is mapped */ - locx /= UI_DPI_FAC; - locy /= UI_DPI_FAC; - node->locx = locx; node->locy = locy + 60.0f; @@ -215,7 +211,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op) int i = 0; /* Get the cut path */ - RNA_BEGIN(op->ptr, itemptr, "path") + RNA_BEGIN (op->ptr, itemptr, "path") { float loc[2]; @@ -417,9 +413,8 @@ static int node_add_mask_poll(bContext *C) return ED_operator_node_editable(C) && snode->nodetree->type == NTREE_COMPOSIT; } -static int node_add_mask_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int node_add_mask_exec(bContext *C, wmOperator *op) { - ARegion *ar = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); bNode *node; ID *mask = NULL; @@ -435,9 +430,6 @@ static int node_add_mask_invoke(bContext *C, wmOperator *op, const wmEvent *even ED_preview_kill_jobs(C); - /* convert mouse coordinates to v2d space */ - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], - &snode->cursor[0], &snode->cursor[1]); node = node_add_node(C, NULL, CMP_NODE_MASK, snode->cursor[0], snode->cursor[1]); if (!node) { @@ -462,7 +454,7 @@ void NODE_OT_add_mask(wmOperatorType *ot) ot->idname = "NODE_OT_add_mask"; /* callbacks */ - ot->invoke = node_add_mask_invoke; + ot->exec = node_add_mask_exec; ot->poll = node_add_mask_poll; /* flags */ diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c index f95e895bef2..53b373e728e 100644 --- a/source/blender/editors/space_node/node_buttons.c +++ b/source/blender/editors/space_node/node_buttons.c @@ -145,13 +145,15 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa) split = uiLayoutRow(row, TRUE); col = uiLayoutColumn(split, TRUE); uiItemL(col, IFACE_("Inputs:"), ICON_NONE); - uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "inputs", &ptr, "inputs", &ptr, "active_input", 0, 0, 0); + uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "inputs", &ptr, "inputs", &ptr, "active_input", + 0, 0, 0, 0); opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&opptr, "in_out", SOCK_IN); col = uiLayoutColumn(split, TRUE); uiItemL(col, IFACE_("Outputs:"), ICON_NONE); - uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "outputs", &ptr, "outputs", &ptr, "active_output", 0, 0, 0); + uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "outputs", &ptr, "outputs", &ptr, "active_output", + 0, 0, 0, 0); opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS); RNA_enum_set(&opptr, "in_out", SOCK_OUT); diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index dce04bb8c42..b991a2c3b5f 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -923,10 +923,13 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN } /* preview */ - if (node->flag & NODE_PREVIEW) { - bNodePreview *preview = previews ? BKE_node_instance_hash_lookup(previews, key) : NULL; - if (preview && preview->rect && !BLI_rctf_is_empty(&node->prvr)) - node_draw_preview(preview, &node->prvr); + if (node->flag & NODE_PREVIEW && previews) { + bNodePreview *preview = BKE_node_instance_hash_lookup(previews, key); + if (preview && (preview->xsize && preview->ysize)) { + if (preview->rect && !BLI_rctf_is_empty(&node->prvr)) { + node_draw_preview(preview, &node->prvr); + } + } } UI_ThemeClearColor(color_id); @@ -1075,31 +1078,31 @@ int node_get_resize_cursor(int directions) return CURSOR_EDIT; } -void node_set_cursor(wmWindow *win, SpaceNode *snode) +void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2]) { bNodeTree *ntree = snode->edittree; bNode *node; bNodeSocket *sock; - int cursor = CURSOR_STD; + int wmcursor = CURSOR_STD; if (ntree) { - if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN | SOCK_OUT)) { + if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN | SOCK_OUT)) { /* pass */ } else { /* check nodes front to back */ for (node = ntree->nodes.last; node; node = node->prev) { - if (BLI_rctf_isect_pt(&node->totr, snode->cursor[0], snode->cursor[1])) + if (BLI_rctf_isect_pt(&node->totr, cursor[0], cursor[1])) break; /* first hit on node stops */ } if (node) { - int dir = node->typeinfo->resize_area_func(node, snode->cursor[0], snode->cursor[1]); - cursor = node_get_resize_cursor(dir); + int dir = node->typeinfo->resize_area_func(node, cursor[0], cursor[1]); + wmcursor = node_get_resize_cursor(dir); } } } - WM_cursor_set(win, cursor); + WM_cursor_set(win, wmcursor); } void node_draw_default(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey key) @@ -1238,7 +1241,7 @@ static void draw_group_overlay(const bContext *C, ARegion *ar) /* shade node groups to separate them visually */ UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70); glEnable(GL_BLEND); - uiSetRoundBox(0); + uiSetRoundBox(UI_CNR_NONE); uiDrawBox(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0); glDisable(GL_BLEND); @@ -1251,6 +1254,7 @@ static void draw_group_overlay(const bContext *C, ARegion *ar) void drawnodespace(const bContext *C, ARegion *ar) { + wmWindow *win = CTX_wm_window(C); View2DScrollers *scrollers; SpaceNode *snode = CTX_wm_space_node(C); View2D *v2d = &ar->v2d; @@ -1259,7 +1263,13 @@ void drawnodespace(const bContext *C, ARegion *ar) glClear(GL_COLOR_BUFFER_BIT); UI_view2d_view_ortho(v2d); - + + /* XXX snode->cursor set in coordspace for placing new nodes, used for drawing noodles too */ + UI_view2d_region_to_view(&ar->v2d, win->eventstate->x - ar->winrct.xmin, win->eventstate->y - ar->winrct.ymin, + &snode->cursor[0], &snode->cursor[1]); + snode->cursor[0] /= UI_DPI_FAC; + snode->cursor[1] /= UI_DPI_FAC; + ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); /* only set once */ diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index b7e9cb0268f..bc0a518b1b0 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -854,14 +854,14 @@ static void node_resize_init(bContext *C, wmOperator *op, const wmEvent *UNUSED( nsw->oldminiwidth = node->miniwidth; nsw->directions = dir; - WM_cursor_modal(CTX_wm_window(C), node_get_resize_cursor(dir)); + WM_cursor_modal_set(CTX_wm_window(C), node_get_resize_cursor(dir)); /* add modal handler */ WM_event_add_modal_handler(C, op); } static void node_resize_exit(bContext *C, wmOperator *op, int UNUSED(cancel)) { - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); MEM_freeN(op->customdata); op->customdata = NULL; @@ -1056,7 +1056,7 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set) /* checks snode->mouse position, and returns found node/socket */ /* type is SOCK_IN and/or SOCK_OUT */ -int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out) +int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, float cursor[2], int in_out) { bNode *node; bNodeSocket *sock; @@ -1068,10 +1068,10 @@ int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **so /* check if we click in a socket */ for (node = snode->edittree->nodes.first; node; node = node->next) { - rect.xmin = snode->cursor[0] - (NODE_SOCKSIZE + 4); - rect.ymin = snode->cursor[1] - (NODE_SOCKSIZE + 4); - rect.xmax = snode->cursor[0] + (NODE_SOCKSIZE + 4); - rect.ymax = snode->cursor[1] + (NODE_SOCKSIZE + 4); + rect.xmin = cursor[0] - (NODE_SOCKSIZE + 4); + rect.ymin = cursor[1] - (NODE_SOCKSIZE + 4); + rect.xmax = cursor[0] + (NODE_SOCKSIZE + 4); + rect.ymax = cursor[1] + (NODE_SOCKSIZE + 4); if (!(node->flag & NODE_HIDDEN)) { /* extra padding inside and out - allow dragging on the text areas too */ @@ -1731,7 +1731,7 @@ static int node_output_file_add_socket_exec(bContext *C, wmOperator *op) node = nodeGetActive(snode->edittree); } - if (!node) + if (!node || node->type != CMP_NODE_OUTPUT_FILE) return OPERATOR_CANCELLED; RNA_string_get(op->ptr, "file_path", file_path); @@ -1777,7 +1777,7 @@ static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *U node = nodeGetActive(snode->edittree); } - if (!node) + if (!node || node->type != CMP_NODE_OUTPUT_FILE) return OPERATOR_CANCELLED; if (!ntreeCompositOutputFileRemoveActiveSocket(ntree, node)) @@ -1819,7 +1819,7 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op) else if (snode && snode->edittree) node = nodeGetActive(snode->edittree); - if (!node) + if (!node || node->type != CMP_NODE_OUTPUT_FILE) return OPERATOR_CANCELLED; nimf = node->storage; @@ -2087,17 +2087,6 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int node_clipboard_paste_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ARegion *ar = CTX_wm_region(C); - SpaceNode *snode = CTX_wm_space_node(C); - - /* convert mouse coordinates to v2d space */ - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &snode->cursor[0], &snode->cursor[1]); - - return node_clipboard_paste_exec(C, op); -} - void NODE_OT_clipboard_paste(wmOperatorType *ot) { /* identifiers */ @@ -2107,7 +2096,6 @@ void NODE_OT_clipboard_paste(wmOperatorType *ot) /* api callbacks */ ot->exec = node_clipboard_paste_exec; - ot->invoke = node_clipboard_paste_invoke; ot->poll = ED_operator_node_editable; /* flags */ diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 1a2e90e5522..176b81f9503 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -84,7 +84,7 @@ void node_draw_nodetree(const struct bContext *C, struct ARegion *ar, struct Spa struct bNodeTree *ntree, bNodeInstanceKey parent_key); void drawnodespace(const bContext *C, ARegion *ar); -void node_set_cursor(struct wmWindow *win, struct SpaceNode *snode); +void node_set_cursor(struct wmWindow *win, struct SpaceNode *snode, float cursor[2]); /* DPI scaled coords */ void node_to_view(struct bNode *node, float x, float y, float *rx, float *ry); void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry); @@ -122,13 +122,15 @@ void NODE_OT_select_same_type_step(struct wmOperatorType *ot); void NODE_OT_find_node(struct wmOperatorType *ot); /* node_view.c */ -int space_node_view_flag(struct bContext *C, SpaceNode *snode, ARegion *ar, const int node_flag); +int space_node_view_flag(struct bContext *C, SpaceNode *snode, ARegion *ar, + const int node_flag, const int smooth_viewtx); void NODE_OT_view_all(struct wmOperatorType *ot); void NODE_OT_view_selected(struct wmOperatorType *ot); void NODE_OT_backimage_move(struct wmOperatorType *ot); void NODE_OT_backimage_zoom(struct wmOperatorType *ot); +void NODE_OT_backimage_fit(struct wmOperatorType *ot); void NODE_OT_backimage_sample(struct wmOperatorType *ot); /* drawnode.c */ @@ -182,7 +184,7 @@ int composite_node_editable(struct bContext *C); int node_has_hidden_sockets(bNode *node); void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set); int node_render_changed_exec(bContext *, struct wmOperator *); -int node_find_indicated_socket(struct SpaceNode *snode, struct bNode **nodep, struct bNodeSocket **sockp, int in_out); +int node_find_indicated_socket(struct SpaceNode *snode, struct bNode **nodep, struct bNodeSocket **sockp, float cursor[2], int in_out); void NODE_OT_duplicate(struct wmOperatorType *ot); void NODE_OT_delete(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 566bb1600cc..f0d3deb24df 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -98,6 +98,7 @@ void node_operatortypes(void) WM_operatortype_append(NODE_OT_backimage_move); WM_operatortype_append(NODE_OT_backimage_zoom); + WM_operatortype_append(NODE_OT_backimage_fit); WM_operatortype_append(NODE_OT_backimage_sample); WM_operatortype_append(NODE_OT_add_file); @@ -249,6 +250,7 @@ void node_keymap(struct wmKeyConfig *keyconf) RNA_float_set(kmi->ptr, "factor", 0.83333f); kmi = WM_keymap_add_item(keymap, "NODE_OT_backimage_zoom", VKEY, KM_PRESS, KM_ALT, 0); RNA_float_set(kmi->ptr, "factor", 1.2f); + WM_keymap_add_item(keymap, "NODE_OT_backimage_fit", HOMEKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "NODE_OT_backimage_sample", ACTIONMOUSE, KM_PRESS, KM_ALT, 0); kmi = WM_keymap_add_item(keymap, "NODE_OT_link_make", FKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 244b222811e..4b5cc9e42b6 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -443,18 +443,19 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) bNodeSocket *tsock = NULL; bNodeLink *link; LinkData *linkdata; + float cursor[2]; int in_out; in_out = nldrag->in_out; UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], - &snode->cursor[0], &snode->cursor[1]); + &cursor[0], &cursor[1]); switch (event->type) { case MOUSEMOVE: if (in_out == SOCK_OUT) { - if (node_find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) { + if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) { for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) { link = linkdata->data; @@ -480,7 +481,7 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) } } else { - if (node_find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) { + if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) { for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) { link = linkdata->data; @@ -550,7 +551,7 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* return 1 when socket clicked */ -static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach) +static bNodeLinkDrag *node_link_init(SpaceNode *snode, float cursor[2], int detach) { bNode *node; bNodeSocket *sock; @@ -560,7 +561,7 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach) int num_links; /* output indicated? */ - if (node_find_indicated_socket(snode, &node, &sock, SOCK_OUT)) { + if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { nldrag = MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); num_links = nodeCountSocketLinks(snode->edittree, sock); @@ -596,7 +597,7 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach) } } /* or an input? */ - else if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN)) { + else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { nldrag = MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); num_links = nodeCountSocketLinks(snode->edittree, sock); @@ -644,14 +645,16 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) SpaceNode *snode = CTX_wm_space_node(C); ARegion *ar = CTX_wm_region(C); bNodeLinkDrag *nldrag; + float cursor[2]; + int detach = RNA_boolean_get(op->ptr, "detach"); UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], - &snode->cursor[0], &snode->cursor[1]); + &cursor[0], &cursor[1]); ED_preview_kill_jobs(C); - nldrag = node_link_init(snode, detach); + nldrag = node_link_init(snode, cursor, detach); if (nldrag) { op->customdata = nldrag; @@ -762,7 +765,7 @@ static int cut_links_exec(bContext *C, wmOperator *op) float mcoords[256][2]; int i = 0; - RNA_BEGIN(op->ptr, itemptr, "path") + RNA_BEGIN (op->ptr, itemptr, "path") { float loc[2]; @@ -1065,18 +1068,23 @@ void NODE_OT_join(wmOperatorType *ot) /* ****************** Attach ******************* */ -static int node_attach_exec(bContext *C, wmOperator *UNUSED(op)) +static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { + ARegion *ar = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; bNode *frame; + float cursor[2]; + + /* convert mouse coordinates to v2d space */ + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]); /* check nodes front to back */ for (frame = ntree->nodes.last; frame; frame = frame->prev) { /* skip selected, those are the nodes we want to attach */ if ((frame->type != NODE_FRAME) || (frame->flag & NODE_SELECT)) continue; - if (BLI_rctf_isect_pt(&frame->totr, snode->cursor[0], snode->cursor[1])) + if (BLI_rctf_isect_pt(&frame->totr, cursor[0], cursor[1])) break; } if (frame) { @@ -1116,16 +1124,6 @@ static int node_attach_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -static int node_attach_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ARegion *ar = CTX_wm_region(C); - SpaceNode *snode = CTX_wm_space_node(C); - - /* convert mouse coordinates to v2d space */ - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &snode->cursor[0], &snode->cursor[1]); - - return node_attach_exec(C, op); -} void NODE_OT_attach(wmOperatorType *ot) { @@ -1135,7 +1133,7 @@ void NODE_OT_attach(wmOperatorType *ot) ot->idname = "NODE_OT_attach"; /* api callbacks */ - ot->exec = node_attach_exec; + ot->invoke = node_attach_invoke; ot->poll = ED_operator_node_editable; diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index e17699309ef..958a3433337 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -306,24 +306,21 @@ static int node_mouse_select(Main *bmain, SpaceNode *snode, ARegion *ar, const i { bNode *node, *tnode; bNodeSocket *sock, *tsock; - float mx, my; + float cursor[2]; int selected = 0; /* get mouse coordinates in view2d space */ - UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &mx, &my); - /* node_find_indicated_socket uses snode->mx/my */ - snode->cursor[0] = mx; - snode->cursor[1] = my; + UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &cursor[0], &cursor[1]); if (extend) { /* first do socket selection, these generally overlap with nodes. * socket selection only in extend mode. */ - if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN)) { + if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { node_socket_toggle(node, sock, 1); selected = 1; } - else if (node_find_indicated_socket(snode, &node, &sock, SOCK_OUT)) { + else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { if (sock->flag & SELECT) { node_socket_deselect(node, sock, 1); } @@ -341,7 +338,7 @@ static int node_mouse_select(Main *bmain, SpaceNode *snode, ARegion *ar, const i } else { /* find the closest visible node */ - node = node_under_mouse_select(snode->edittree, mx, my); + node = node_under_mouse_select(snode->edittree, cursor[0], cursor[1]); if (node) { if ((node->flag & SELECT) && (node->flag & NODE_ACTIVE) == 0) { @@ -362,7 +359,7 @@ static int node_mouse_select(Main *bmain, SpaceNode *snode, ARegion *ar, const i else { /* extend == 0 */ /* find the closest visible node */ - node = node_under_mouse_select(snode->edittree, mx, my); + node = node_under_mouse_select(snode->edittree, cursor[0], cursor[1]); if (node) { for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) { @@ -834,7 +831,8 @@ static int node_select_same_type_step_exec(bContext *C, wmOperator *op) if (active->totr.xmax < ar->v2d.cur.xmin || active->totr.xmin > ar->v2d.cur.xmax || active->totr.ymax < ar->v2d.cur.ymin || active->totr.ymin > ar->v2d.cur.ymax) { - space_node_view_flag(C, snode, CTX_wm_region(C), NODE_SELECT); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + space_node_view_flag(C, snode, ar, NODE_SELECT, smooth_viewtx); } } @@ -898,7 +896,7 @@ static void node_find_call_cb(struct bContext *C, void *UNUSED(arg1), void *arg2 if (active->totr.xmax < ar->v2d.cur.xmin || active->totr.xmin > ar->v2d.cur.xmax || active->totr.ymax < ar->v2d.cur.ymin || active->totr.ymin > ar->v2d.cur.ymax) { - space_node_view_flag(C, snode, ar, NODE_SELECT); + space_node_view_flag(C, snode, ar, NODE_SELECT, U.smooth_viewtx); } } diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index 9e6e1e628f6..f889a8ec97b 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -66,7 +66,8 @@ /* **************** View All Operator ************** */ -int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, const int node_flag) +int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, + const int node_flag, const int smooth_viewtx) { bNode *node; rctf cur_new; @@ -125,22 +126,23 @@ int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, const int n BLI_rctf_scale(&cur_new, 1.1f); } - UI_view2d_smooth_view(C, ar, &cur_new); + UI_view2d_smooth_view(C, ar, &cur_new, smooth_viewtx); } return (tot != 0); } -static int node_view_all_exec(bContext *C, wmOperator *UNUSED(op)) +static int node_view_all_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); /* is this really needed? */ snode->xof = 0; snode->yof = 0; - if (space_node_view_flag(C, snode, ar, 0)) { + if (space_node_view_flag(C, snode, ar, 0, smooth_viewtx)) { return OPERATOR_FINISHED; } else { @@ -163,12 +165,13 @@ void NODE_OT_view_all(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int node_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) +static int node_view_selected_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - if (space_node_view_flag(C, snode, ar, NODE_SELECT)) { + if (space_node_view_flag(C, snode, ar, NODE_SELECT, smooth_viewtx)) { return OPERATOR_FINISHED; } else { @@ -327,6 +330,60 @@ void NODE_OT_backimage_zoom(wmOperatorType *ot) RNA_def_float(ot->srna, "factor", 1.2f, 0.0f, 10.0f, "Factor", "", 0.0f, 10.0f); } +static int backimage_fit_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceNode *snode = CTX_wm_space_node(C); + ARegion *ar = CTX_wm_region(C); + + Image *ima; + ImBuf *ibuf; + + const float pad = 32.0f; + + void *lock; + + float facx, facy; + + ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); + ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + + if (ibuf == NULL) { + BKE_image_release_ibuf(ima, ibuf, lock); + return OPERATOR_CANCELLED; + } + + facx = 1.0f * (ar->sizex - pad) / (ibuf->x * snode->zoom); + facy = 1.0f * (ar->sizey - pad) / (ibuf->y * snode->zoom); + + BKE_image_release_ibuf(ima, ibuf, lock); + + snode->zoom *= min_ff(facx, facy); + + snode->xof = 0; + snode->yof = 0; + + ED_region_tag_redraw(ar); + + return OPERATOR_FINISHED; +} + +void NODE_OT_backimage_fit(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name = "Background Image Fit"; + ot->idname = "NODE_OT_backimage_fit"; + ot->description = "Fit the background image to the view"; + + /* api callbacks */ + ot->exec = backimage_fit_exec; + ot->poll = composite_node_active; + + /* flags */ + ot->flag = OPTYPE_BLOCKING; + +} + /******************** sample backdrop operator ********************/ typedef struct ImageSampleInfo { diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 922912fa540..6ae8a1f94b1 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -307,10 +307,12 @@ static SpaceLink *node_new(const bContext *UNUSED(C)) snode->zoom = 1.0f; /* select the first tree type for valid type */ - NODE_TREE_TYPES_BEGIN(treetype) + NODE_TREE_TYPES_BEGIN (treetype) + { strcpy(snode->tree_idname, treetype->idname); break; - NODE_TREE_TYPES_END + } + NODE_TREE_TYPES_END; /* header */ ar = MEM_callocN(sizeof(ARegion), "header for node"); @@ -602,8 +604,14 @@ static void node_cursor(wmWindow *win, ScrArea *sa, ARegion *ar) /* convert mouse coordinates to v2d space */ UI_view2d_region_to_view(&ar->v2d, win->eventstate->x - ar->winrct.xmin, win->eventstate->y - ar->winrct.ymin, &snode->cursor[0], &snode->cursor[1]); + + /* here snode->cursor is used to detect the node edge for sizing */ + node_set_cursor(win, snode, snode->cursor); - node_set_cursor(win, snode); + /* XXX snode->cursor is in placing new nodes space */ + snode->cursor[0] /= UI_DPI_FAC; + snode->cursor[1] /= UI_DPI_FAC; + } /* Initialize main area, setting handlers. */ diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 44d5672e7da..fe706ce2365 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -363,6 +363,9 @@ void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag) if (group_restrict_flag(gr, flag)) { for (gob = gr->gobject.first; gob; gob = gob->next) { + if (gob->ob->id.lib) + continue; + gob->ob->restrictflag &= ~flag; if (flag == OB_RESTRICT_VIEW) @@ -372,6 +375,9 @@ void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag) } else { for (gob = gr->gobject.first; gob; gob = gob->next) { + if (gob->ob->id.lib) + continue; + /* not in editmode */ if (scene->obedit != gob->ob) { gob->ob->restrictflag |= flag; @@ -565,7 +571,11 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar } if (tselem->type == 0 && te->idcode == ID_GR) { int restrict_bool; + int but_flag = UI_BUT_DRAG_LOCK; gr = (Group *)tselem->id; + + if (gr->id.lib) + but_flag |= UI_BUT_DISABLED; uiBlockSetEmboss(block, UI_EMBOSSN); @@ -574,21 +584,21 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Restrict/Allow visibility in the 3D View")); uiButSetFunc(bt, restrictbutton_gr_restrict_view, scene, gr); - uiButSetFlag(bt, UI_BUT_DRAG_LOCK); + uiButSetFlag(bt, but_flag); restrict_bool = group_restrict_flag(gr, OB_RESTRICT_SELECT); bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Restrict/Allow selection in the 3D View")); uiButSetFunc(bt, restrictbutton_gr_restrict_select, scene, gr); - uiButSetFlag(bt, UI_BUT_DRAG_LOCK); + uiButSetFlag(bt, but_flag); restrict_bool = group_restrict_flag(gr, OB_RESTRICT_RENDER); bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Restrict/Allow renderability")); uiButSetFunc(bt, restrictbutton_gr_restrict_render, scene, gr); - uiButSetFlag(bt, UI_BUT_DRAG_LOCK); + uiButSetFlag(bt, but_flag); uiBlockSetEmboss(block, UI_EMBOSS); } @@ -1035,48 +1045,37 @@ static void outliner_draw_keymapbuts(uiBlock *block, ARegion *ar, SpaceOops *soo } -static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, SpaceOops *soops, ListBase *lb) +static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, TreeElement *te) { uiBut *bt; - TreeElement *te; TreeStoreElem *tselem; int spx, dx, len; - - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) { - - if (tselem->flag & TSE_TEXTBUT) { - - /* If we add support to rename Sequence. - * need change this. - */ - // prevent crash when trying to rename 'pose' entry of armature - if (tselem->type == TSE_POSE_BASE) continue; - - if (tselem->type == TSE_EBONE) len = sizeof(((EditBone *) 0)->name); - else if (tselem->type == TSE_MODIFIER) len = sizeof(((ModifierData *) 0)->name); - else if (tselem->id && GS(tselem->id->name) == ID_LI) len = sizeof(((Library *) 0)->name); - else len = MAX_ID_NAME - 2; - - dx = (int)UI_GetStringWidth(te->name); - if (dx < 5 * UI_UNIT_X) dx = 5 * UI_UNIT_X; - spx = te->xs + 1.8f * UI_UNIT_X; - if (spx + dx + 0.5f * UI_UNIT_X > ar->v2d.cur.xmax) dx = ar->v2d.cur.xmax - spx - 0.5f * UI_UNIT_X; + tselem = TREESTORE(te); - bt = uiDefBut(block, TEX, OL_NAMEBUTTON, "", spx, te->ys, dx + UI_UNIT_X, UI_UNIT_Y - 1, (void *)te->name, - 1.0, (float)len, 0, 0, ""); - uiButSetRenameFunc(bt, namebutton_cb, tselem); - - /* returns false if button got removed */ - if (false == uiButActiveOnly(C, ar, block, bt)) { - tselem->flag &= ~TSE_TEXTBUT; - } - } - } - - if (TSELEM_OPEN(tselem, soops)) outliner_buttons(C, block, ar, soops, &te->subtree); + BLI_assert(tselem->flag & TSE_TEXTBUT); + /* If we add support to rename Sequence. + * need change this. + */ + + if (tselem->type == TSE_EBONE) len = sizeof(((EditBone *) 0)->name); + else if (tselem->type == TSE_MODIFIER) len = sizeof(((ModifierData *) 0)->name); + else if (tselem->id && GS(tselem->id->name) == ID_LI) len = sizeof(((Library *) 0)->name); + else len = MAX_ID_NAME - 2; + + spx = te->xs + 1.8f * UI_UNIT_X; + dx = ar->v2d.cur.xmax - (spx + 3.2f * UI_UNIT_X); + + bt = uiDefBut(block, TEX, OL_NAMEBUTTON, "", spx, te->ys, dx, UI_UNIT_Y - 1, (void *)te->name, + 1.0, (float)len, 0, 0, ""); + uiButSetRenameFunc(bt, namebutton_cb, tselem); + + /* returns false if button got removed */ + if (false == uiButActiveOnly(C, ar, block, bt)) { + tselem->flag &= ~TSE_TEXTBUT; + + /* bad! (notifier within draw) without this, we don't get a refesh */ + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); } } @@ -1389,6 +1388,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto tselem_draw_icon_uibut(&arg, ICON_GROUP); break; case ID_LI: tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); break; + case ID_LS: + tselem_draw_icon_uibut(&arg, ICON_BRUSH_DATA); break; /* FIXME proper icon */ } } } @@ -1472,7 +1473,7 @@ static void outliner_set_coord_tree_element(SpaceOops *soops, TreeElement *te, i static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops, - TreeElement *te, int startx, int *starty) + TreeElement *te, int startx, int *starty, TreeElement **te_edit) { TreeElement *ten; TreeStoreElem *tselem; @@ -1485,6 +1486,10 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene int xmax = ar->v2d.cur.xmax; unsigned char alpha = 128; + if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) { + *te_edit = te; + } + /* icons can be ui buts, we don't want it to overlap with restrict */ if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) xmax -= OL_TOGW + UI_UNIT_X; @@ -1665,7 +1670,7 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene *starty -= UI_UNIT_Y; for (ten = te->subtree.first; ten; ten = ten->next) - outliner_draw_tree_element(C, block, scene, ar, soops, ten, startx + UI_UNIT_X, starty); + outliner_draw_tree_element(C, block, scene, ar, soops, ten, startx + UI_UNIT_X, starty, te_edit); } else { for (ten = te->subtree.first; ten; ten = ten->next) @@ -1749,7 +1754,8 @@ static void outliner_draw_selection(ARegion *ar, SpaceOops *soops, ListBase *lb, } -static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops) +static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, + SpaceOops *soops, TreeElement **te_edit) { TreeElement *te; int starty, startx; @@ -1781,7 +1787,7 @@ static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegio starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; startx = 0; for (te = soops->tree.first; te; te = te->next) { - outliner_draw_tree_element(C, block, scene, ar, soops, te, startx, &starty); + outliner_draw_tree_element(C, block, scene, ar, soops, te, startx, &starty, te_edit); } } @@ -1851,6 +1857,7 @@ void draw_outliner(const bContext *C) SpaceOops *soops = CTX_wm_space_outliner(C); uiBlock *block; int sizey = 0, sizex = 0, sizex_rna = 0; + TreeElement *te_edit = NULL; outliner_build_tree(mainvar, scene, soops); // always @@ -1904,7 +1911,7 @@ void draw_outliner(const bContext *C) /* draw outliner stuff (background, hierachy lines and names) */ outliner_back(ar); block = uiBeginBlock(C, ar, __func__, UI_EMBOSS); - outliner_draw_tree((bContext *)C, block, scene, ar, soops); + outliner_draw_tree((bContext *)C, block, scene, ar, soops, &te_edit); if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) { /* draw rna buttons */ @@ -1921,7 +1928,9 @@ void draw_outliner(const bContext *C) } /* draw edit buttons if nessecery */ - outliner_buttons(C, block, ar, soops, &soops->tree); + if (te_edit) { + outliner_buttons(C, block, ar, te_edit); + } uiEndBlock(C, block); uiDrawBlock(C, block); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 1e9b681197c..559fb6f932e 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -227,7 +227,7 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, BKE_report(reports, RPT_WARNING, "Cannot edit sequence name"); } else if (tselem->id->lib) { - // XXX error_libdata(); + BKE_report(reports, RPT_WARNING, "Cannot edit external libdata"); } else if (te->idcode == ID_LI && te->parent) { BKE_report(reports, RPT_WARNING, "Cannot edit the path of an indirectly linked library"); @@ -1102,7 +1102,7 @@ static void tree_element_to_path(TreeElement *te, TreeStoreElem *tselem, /* item is part of an array, so must set the array_index */ *array_index = te->index; } - else if (RNA_property_array_length(ptr, prop)) { + else if (RNA_property_array_check(prop)) { /* entire array was selected, so keyframe all */ *flag |= KSP_FLAG_WHOLE_ARRAY; } @@ -1469,7 +1469,7 @@ static int parent_drop_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "child", childname); ob = (Object *)BKE_libblock_find_name(ID_OB, childname); - ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, FALSE, FALSE); + ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, false, false, NULL); DAG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); @@ -1525,7 +1525,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) } if ((par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) { - if (ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, FALSE, FALSE)) { + if (ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, false, false, NULL)) { DAG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index c1950e62817..a0af9340fe2 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -57,6 +57,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_sequencer.h" +#include "BKE_treehash.h" #include "ED_armature.h" #include "ED_object.h" @@ -113,7 +114,7 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb, case ID_LA: case ID_AR: case ID_CA: case ID_SPK: case ID_MA: case ID_TE: case ID_IP: case ID_IM: case ID_SO: case ID_KE: case ID_WO: case ID_AC: - case ID_NLA: case ID_TXT: case ID_GR: + case ID_NLA: case ID_TXT: case ID_GR: case ID_LS: if (*idlevel == 0) *idlevel = idcode; else if (*idlevel != idcode) *idlevel = -1; break; @@ -299,17 +300,13 @@ static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te, if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id); if (base) { - SpaceOops *soops = CTX_wm_space_outliner(C); - // check also library later if (scene->obedit == base->object) ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); ED_base_object_free_and_unlink(CTX_data_main(C), scene, base); te->directdata = NULL; - BLI_ghash_remove(soops->treehash, tselem, NULL, NULL); tselem->id = NULL; - BLI_ghash_insert(soops->treehash, tselem, tselem); } } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 514bfc43ac7..10890a305fb 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -32,15 +32,6 @@ #include <math.h> #include <string.h> -#if defined WIN32 && !defined _LIBC || defined __sun -# include "BLI_fnmatch.h" /* use fnmatch included in blenlib */ -#else -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# endif -# include <fnmatch.h> -#endif - #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" @@ -59,12 +50,14 @@ #include "DNA_sequence_types.h" #include "DNA_speaker_types.h" #include "DNA_object_types.h" +#include "DNA_linestyle_types.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math.h" #include "BLI_ghash.h" #include "BLI_mempool.h" +#include "BLI_fnmatch.h" #include "BLF_translation.h" @@ -74,6 +67,7 @@ #include "BKE_modifier.h" #include "BKE_sequencer.h" #include "BKE_idcode.h" +#include "BKE_treehash.h" #include "ED_armature.h" #include "ED_screen.h" @@ -116,9 +110,8 @@ static void outliner_storage_cleanup(SpaceOops *soops) if (BLI_mempool_count(ts) == unused) { BLI_mempool_destroy(ts); soops->treestore = NULL; - if (soops->treehash) { - BLI_ghash_free(soops->treehash, NULL, NULL); + BKE_treehash_free(soops->treehash); soops->treehash = NULL; } } @@ -135,14 +128,9 @@ static void outliner_storage_cleanup(SpaceOops *soops) } BLI_mempool_destroy(ts); soops->treestore = new_ts; - if (soops->treehash) { /* update hash table to fix broken pointers */ - BLI_ghash_clear(soops->treehash, NULL, NULL); - BLI_mempool_iternew(soops->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - BLI_ghash_insert(soops->treehash, tselem, tselem); - } + BKE_treehash_rebuild_from_treestore(soops->treehash, soops->treestore); } } } @@ -150,53 +138,23 @@ static void outliner_storage_cleanup(SpaceOops *soops) } } -static unsigned int tse_hash(const void *ptr) -{ - const TreeStoreElem *tse = (const TreeStoreElem *)ptr; - unsigned int hash; - BLI_assert(tse->type || !tse->nr); - hash = BLI_ghashutil_inthash(SET_INT_IN_POINTER((tse->nr << 16) + tse->type)); - hash ^= BLI_ghashutil_inthash(tse->id); - return hash; -} - -static int tse_cmp(const void *a, const void *b) -{ - const TreeStoreElem *tse_a = (const TreeStoreElem *)a; - const TreeStoreElem *tse_b = (const TreeStoreElem *)b; - return tse_a->type != tse_b->type || tse_a->nr != tse_b->nr || tse_a->id != tse_b->id; -} - static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short type, short nr) { - /* When treestore comes directly from readfile.c, treehash is empty; - * In this case we don't want to get TSE_CLOSED while adding elements one by one, - * that is why this function restores treehash */ - bool restore_treehash = (soops->treestore && !soops->treehash); - TreeStoreElem *tselem, elem_template; + TreeStoreElem *tselem; if (soops->treestore == NULL) { /* if treestore was not created in readfile.c, create it here */ soops->treestore = BLI_mempool_create(sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER); + } if (soops->treehash == NULL) { - soops->treehash = BLI_ghash_new(tse_hash, tse_cmp, "treehash"); - } - - if (restore_treehash) { - BLI_mempool_iter iter; - BLI_mempool_iternew(soops->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - BLI_ghash_insert(soops->treehash, tselem, tselem); - } + soops->treehash = BKE_treehash_create_from_treestore(soops->treestore); } - /* check if 'te' is in treestore */ - elem_template.type = type; - elem_template.nr = type ? nr : 0; // we're picky! :) - elem_template.id = id; - tselem = BLI_ghash_lookup(soops->treehash, &elem_template); - if (tselem && !tselem->used) { + /* find any unused tree element in treestore and mark it as used + * (note that there may be multiple unused elements in case of linked objects) */ + tselem = BKE_treehash_lookup_unused(soops->treehash, type, nr, id); + if (tselem) { te->store_elem = tselem; tselem->used = 1; return; @@ -210,7 +168,7 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty tselem->used = 0; tselem->flag = TSE_CLOSED; te->store_elem = tselem; - BLI_ghash_insert(soops->treehash, tselem, tselem); + BKE_treehash_add_element(soops->treehash, tselem); } /* ********************************************************* */ @@ -250,16 +208,12 @@ static TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *stor /* tse is not in the treestore, we use its contents to find a match */ TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse) { - GHash *th = soops->treehash; - TreeStoreElem *tselem, tselem_template; + TreeStoreElem *tselem; if (tse->id == NULL) return NULL; /* check if 'tse' is in treestore */ - tselem_template.id = tse->id; - tselem_template.type = tse->type; - tselem_template.nr = tse->type ? tse->nr : 0; - tselem = BLI_ghash_lookup(th, &tselem_template); + tselem = BKE_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id); if (tselem) return outliner_find_tree_element(&soops->tree, tselem); @@ -423,6 +377,32 @@ static bool outliner_animdata_test(AnimData *adt) return false; } +static void outliner_add_line_styles(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te) +{ + SceneRenderLayer *srl; + FreestyleLineSet *lineset; + + for (srl = sce->r.layers.first; srl; srl = srl->next) { + for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { + FreestyleLineStyle *linestyle = lineset->linestyle; + if (linestyle) { + linestyle->id.flag |= LIB_DOIT; + } + } + } + for (srl = sce->r.layers.first; srl; srl = srl->next) { + for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { + FreestyleLineStyle *linestyle = lineset->linestyle; + if (linestyle) { + if (!(linestyle->id.flag & LIB_DOIT)) + continue; + linestyle->id.flag &= ~LIB_DOIT; + outliner_add_element(soops, lb, linestyle, te, 0, 0); + } + } + } +} + static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te) { SceneRenderLayer *srl; @@ -448,6 +428,8 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0); outliner_add_element(soops, lb, sce->world, te, 0, 0); + + outliner_add_line_styles(soops, lb, sce, te); } // can be inlined if necessary @@ -806,6 +788,14 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor } break; } + case ID_LS: + { + FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id; + + if (outliner_animdata_test(linestyle->adt)) + outliner_add_element(soops, &te->subtree, linestyle, te, TSE_ANIM_DATA, 0); + break; + } } } diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 874852ee320..d695ffa46d5 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -43,6 +43,7 @@ #include "BKE_context.h" #include "BKE_screen.h" #include "BKE_scene.h" +#include "BKE_treehash.h" #include "ED_space_api.h" #include "ED_screen.h" @@ -435,7 +436,7 @@ static void outliner_free(SpaceLink *sl) BLI_mempool_destroy(soutliner->treestore); } if (soutliner->treehash) { - BLI_ghash_free(soutliner->treehash, NULL, NULL); + BKE_treehash_free(soutliner->treehash); } } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 68fd09f5fb7..dca1b481334 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -926,13 +926,13 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq /* stop all running jobs, except screen one. currently previews frustrate Render * needed to make so sequencer's rendering doesn't conflict with compositor */ - WM_jobs_kill_type(CTX_wm_manager(C), WM_JOB_TYPE_COMPOSITE); + WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_COMPOSITE); if ((scene->r.seq_flag & R_SEQ_GL_PREV) == 0) { /* in case of final rendering used for preview, kill all previews, * otherwise threading conflict will happen in rendering module */ - WM_jobs_kill_type(CTX_wm_manager(C), WM_JOB_TYPE_RENDER_PREVIEW); + WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_RENDER_PREVIEW); } } @@ -1086,10 +1086,10 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq type = GL_FLOAT; if (ibuf->float_colorspace) { - glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, ibuf->float_colorspace, TRUE); + glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, ibuf->float_colorspace, true); } else { - glsl_used = IMB_colormanagement_setup_glsl_draw_ctx(C, TRUE); + glsl_used = IMB_colormanagement_setup_glsl_draw_ctx(C, true); } } else if (ibuf->rect) { @@ -1097,7 +1097,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq format = GL_RGBA; type = GL_UNSIGNED_BYTE; - glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, ibuf->rect_colorspace, FALSE); + glsl_used = IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, ibuf->rect_colorspace, false); } else { format = GL_RGBA; diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 955a9c78c56..8b2e7067eb9 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -2155,12 +2155,13 @@ void SEQUENCER_OT_meta_separate(wmOperatorType *ot) } /* view_all operator */ -static int sequencer_view_all_exec(bContext *C, wmOperator *UNUSED(op)) +static int sequencer_view_all_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); View2D *v2d = UI_view2d_fromcontext(C); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); - UI_view2d_smooth_view(C, ar, &v2d->tot); + UI_view2d_smooth_view(C, ar, &v2d->tot, smooth_viewtx); return OPERATOR_FINISHED; } @@ -2322,7 +2323,7 @@ void SEQUENCER_OT_view_toggle(wmOperatorType *ot) /* view_selected operator */ -static int sequencer_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) +static int sequencer_view_selected_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); View2D *v2d = UI_view2d_fromcontext(C); @@ -2355,6 +2356,7 @@ static int sequencer_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) } if (ymax != 0) { + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); xmax += xmargin; xmin -= xmargin; @@ -2377,7 +2379,7 @@ static int sequencer_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) cur_new.ymax = ymid + (orig_height / 2); } - UI_view2d_smooth_view(C, ar, &cur_new); + UI_view2d_smooth_view(C, ar, &cur_new, smooth_viewtx); return OPERATOR_FINISHED; } @@ -2958,7 +2960,7 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot) /* identifiers */ ot->name = "Border Offset View"; ot->idname = "SEQUENCER_OT_view_ghost_border"; - ot->description = "Enable border select mode"; + ot->description = "Set the boundaries of the border used for offset-view"; /* api callbacks */ ot->invoke = WM_border_select_invoke; diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c index 51df21e509a..c8fd6e4b6ea 100644 --- a/source/blender/editors/space_sequencer/sequencer_modifier.c +++ b/source/blender/editors/space_sequencer/sequencer_modifier.c @@ -99,7 +99,7 @@ void SEQUENCER_OT_strip_modifier_add(wmOperatorType *ot) /* identifiers */ ot->name = "Add Strip Modifier"; ot->idname = "SEQUENCER_OT_strip_modifier_add"; - ot->description = "Add a modifier to strip"; + ot->description = "Add a modifier to the strip"; /* api callbacks */ ot->exec = strip_modifier_add_exec; @@ -142,7 +142,7 @@ void SEQUENCER_OT_strip_modifier_remove(wmOperatorType *ot) /* identifiers */ ot->name = "Remove Strip Modifier"; ot->idname = "SEQUENCER_OT_strip_modifier_remove"; - ot->description = "Add a modifier to strip"; + ot->description = "Remove a modifier from the strip"; /* api callbacks */ ot->exec = strip_modifier_remove_exec; diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index 254d15341cd..45f05d56076 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -892,7 +892,7 @@ void SEQUENCER_OT_select_border(wmOperatorType *ot) /* identifiers */ ot->name = "Border Select"; ot->idname = "SEQUENCER_OT_select_border"; - ot->description = "Enable border select mode"; + ot->description = "Select strips using border selection"; /* api callbacks */ ot->invoke = WM_border_select_invoke; diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c index 68428cd890f..deb37f8d943 100644 --- a/source/blender/editors/space_sequencer/sequencer_view.c +++ b/source/blender/editors/space_sequencer/sequencer_view.c @@ -152,7 +152,8 @@ static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event) info->colfp = info->colf; /* sequencer's image buffers are in non-linear space, need to make them linear */ - BKE_sequencer_pixel_from_sequencer_space_v4(scene, info->colf); + copy_v4_v4(info->linearcol, info->colf); + BKE_sequencer_pixel_from_sequencer_space_v4(scene, info->linearcol); info->color_manage = TRUE; } @@ -219,7 +220,8 @@ static int sample_cancel(bContext *C, wmOperator *op) static int sample_poll(bContext *C) { - return BKE_sequencer_editing_get(CTX_data_scene(C), FALSE) != NULL; + SpaceSeq *sseq = CTX_wm_space_seq(C); + return sseq && BKE_sequencer_editing_get(CTX_data_scene(C), FALSE) != NULL; } void SEQUENCER_OT_sample(wmOperatorType *ot) diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 04b2a21bf79..84c6329db53 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -491,6 +491,7 @@ static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa case ND_MARKERS: case ND_RENDER_OPTIONS: /* for FPS and FPS Base */ case ND_SEQUENCER: + case ND_RENDER_RESULT: ED_region_tag_redraw(ar); break; } diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index b04d2b16e8d..c668c8063a8 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -309,6 +309,8 @@ static void text_keymap(struct wmKeyConfig *keyconf) RNA_boolean_set(kmi->ptr, "selection", TRUE); } + WM_keymap_add_item(keymap, "TEXT_OT_properties", TKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "TEXT_OT_jump", JKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "TEXT_OT_find", GKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 95fd7fce878..e92cab72042 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -1133,23 +1133,23 @@ static void draw_cursor(SpaceText *st, ARegion *ar) wrap_offset_in_line(st, ar, text->sell, text->selc, &offl, &offc); - y1 = ar->winy - 2 - (vsell - offl) * lheight; - y2 = y1 - (lheight * visible_lines + TXT_LINE_SPACING); + y1 = ar->winy - (vsell - offl) * lheight; + y2 = y1 - (lheight * visible_lines); } else { - y1 = ar->winy - 2 - vsell * lheight; - y2 = y1 - (lheight + TXT_LINE_SPACING); + y1 = ar->winy - vsell * lheight; + y2 = y1 - (lheight); } if (!(y1 < 0 || y2 > ar->winy)) { /* check we need to draw */ - x1 = st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET; + x1 = 0; // st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET; x2 = x1 + ar->winx; glColor4ub(255, 255, 255, 32); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - glRecti(x1 - 4, y1, x2, y2 + TXT_LINE_SPACING); + glRecti(x1 - 4, y1, x2, y2); glDisable(GL_BLEND); } } @@ -1317,15 +1317,13 @@ void draw_text_main(SpaceText *st, ARegion *ar) int wraplinecount = 0, wrap_skip = 0; int margin_column_x; - /* dpi controlled line height and font size */ - st->lheight_dpi = (U.widget_unit * st->lheight) / 20; - - if (st->lheight_dpi) st->viewlines = (int)ar->winy / (st->lheight_dpi + TXT_LINE_SPACING); - else st->viewlines = 0; - /* if no text, nothing to do */ if (!text) return; + + /* 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; text_update_drawcache(st, ar); diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h index 371ccfd9bd9..5d0c7181e77 100644 --- a/source/blender/editors/space_text/text_intern.h +++ b/source/blender/editors/space_text/text_intern.h @@ -53,11 +53,10 @@ void text_update_character_width(struct SpaceText *st); void text_scroll_to_cursor(struct SpaceText *st, struct ScrArea *sa); void text_update_cursor_moved(struct bContext *C); - /* TXT_OFFSET used to be 35 when the scrollbar was on the left... */ -#define TXT_OFFSET ((int)(0.75f * U.widget_unit)) +#define TXT_OFFSET ((int)(0.5f * U.widget_unit)) #define TXT_SCROLL_WIDTH U.widget_unit #define TXT_SCROLL_SPACE ((int)(0.1f * U.widget_unit)) -#define TXT_LINE_SPACING ((int)(0.2f * U.widget_unit)) /* space between lines */ +#define TXT_LINE_SPACING ((int)(0.3f * st->lheight_dpi)) /* space between lines */ #define TEXTXLOC (st->cwidth * st->linenrs_tot) #define SUGG_LIST_SIZE 7 diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index dec61a0e1ca..c078e612d68 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -949,7 +949,7 @@ static int text_indent_exec(bContext *C, wmOperator *UNUSED(op)) text_drawcache_tag_update(CTX_wm_space_text(C), 0); if (txt_has_sel(text)) { - txt_order_cursors(text); + txt_order_cursors(text, false); txt_indent(text); } else @@ -983,7 +983,7 @@ static int text_unindent_exec(bContext *C, wmOperator *UNUSED(op)) text_drawcache_tag_update(CTX_wm_space_text(C), 0); - txt_order_cursors(text); + txt_order_cursors(text, false); txt_unindent(text); text_update_edited(text); @@ -1063,7 +1063,7 @@ static int text_comment_exec(bContext *C, wmOperator *UNUSED(op)) if (txt_has_sel(text)) { text_drawcache_tag_update(CTX_wm_space_text(C), 0); - txt_order_cursors(text); + txt_order_cursors(text, false); txt_comment(text); text_update_edited(text); @@ -1096,7 +1096,7 @@ static int text_uncomment_exec(bContext *C, wmOperator *UNUSED(op)) if (txt_has_sel(text)) { text_drawcache_tag_update(CTX_wm_space_text(C), 0); - txt_order_cursors(text); + txt_order_cursors(text, false); txt_uncomment(text); text_update_edited(text); @@ -1861,11 +1861,23 @@ static int text_move_cursor(bContext *C, int type, int select) break; case PREV_CHAR: - txt_move_left(text, select); + if (txt_has_sel(text) && !select) { + txt_order_cursors(text, false); + txt_pop_sel(text); + } + else { + txt_move_left(text, select); + } break; case NEXT_CHAR: - txt_move_right(text, select); + if (txt_has_sel(text) && !select) { + txt_order_cursors(text, true); + txt_pop_sel(text); + } + else { + txt_move_right(text, select); + } break; case PREV_LINE: @@ -1931,7 +1943,7 @@ void TEXT_OT_move_select(wmOperatorType *ot) /* identifiers */ ot->name = "Move Select"; ot->idname = "TEXT_OT_move_select"; - ot->description = "Make selection from current cursor position to new cursor position type"; + ot->description = "Move the cursor while selecting"; /* api callbacks */ ot->exec = text_move_select_exec; @@ -2086,10 +2098,17 @@ void TEXT_OT_overwrite_toggle(wmOperatorType *ot) static void txt_screen_clamp(SpaceText *st, ARegion *ar) { - int last; - last = text_get_total_lines(st, ar); - last = last - (st->viewlines / 2); - CLAMP(st->top, 0, last); + if (st->top <= 0) { + st->top = 0; + } + else { + int last; + last = text_get_total_lines(st, ar); + last = last - (st->viewlines / 2); + if (last > 0 && st->top > last) { + st->top = last; + } + } } /* Moves the view vertically by the specified number of lines */ @@ -2272,7 +2291,7 @@ void TEXT_OT_scroll(wmOperatorType *ot) * scroll_bar. Both do basically the same thing (aside * from keymaps).*/ ot->idname = "TEXT_OT_scroll"; - ot->description = "Scroll text screen"; + ot->description = ""; /* api callbacks */ ot->exec = text_scroll_exec; @@ -2282,7 +2301,7 @@ void TEXT_OT_scroll(wmOperatorType *ot) ot->poll = text_scroll_poll; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER | OPTYPE_INTERNAL; /* properties */ RNA_def_int(ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100); @@ -2366,7 +2385,7 @@ void TEXT_OT_scroll_bar(wmOperatorType *ot) * scroll. Both do basically the same thing (aside * from keymaps).*/ ot->idname = "TEXT_OT_scroll_bar"; - ot->description = "Scroll text screen"; + ot->description = ""; /* api callbacks */ ot->invoke = text_scroll_bar_invoke; @@ -2375,7 +2394,7 @@ void TEXT_OT_scroll_bar(wmOperatorType *ot) ot->poll = text_region_scroll_poll; /* flags */ - ot->flag = OPTYPE_BLOCKING; + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; /* properties */ RNA_def_int(ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100); diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index d3d8868520d..2634dd3ec08 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -34,7 +34,6 @@ #include <string.h> #include <math.h> - #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" @@ -1099,12 +1098,14 @@ static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, float xwidth, if ((segments > 1) && (pchan)) { float dlen = length / (float)segments; - Mat4 *bbone = b_bone_spline_setup(pchan, 0); + Mat4 bbone[MAX_BBONE_SUBDIV]; int a; - - for (a = 0; a < segments; a++, bbone++) { + + b_bone_spline_setup(pchan, 0, bbone); + + for (a = 0; a < segments; a++) { glPushMatrix(); - glMultMatrixf(bbone->mat); + glMultMatrixf(bbone[a].mat); if (dt == OB_SOLID) drawsolidcube_size(xwidth, dlen, zwidth); else drawcube_size(xwidth, dlen, zwidth); glPopMatrix(); @@ -1235,6 +1236,7 @@ static void draw_wire_bone_segments(bPoseChannel *pchan, Mat4 *bbones, float len static void draw_wire_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id, bPoseChannel *pchan, EditBone *ebone) { + Mat4 bbones_array[MAX_BBONE_SUBDIV]; Mat4 *bbones = NULL; int segments = 0; float length; @@ -1243,8 +1245,10 @@ static void draw_wire_bone(const short dt, int armflag, int boneflag, short cons segments = pchan->bone->segments; length = pchan->bone->length; - if (segments > 1) - bbones = b_bone_spline_setup(pchan, 0); + if (segments > 1) { + b_bone_spline_setup(pchan, 0, bbones_array); + bbones = bbones_array; + } } else length = ebone->length; @@ -1534,7 +1538,7 @@ static void draw_pose_dofs(Object *ob) if (bone->flag & BONE_SELECTED) { if (bone->layer & arm->layer) { if (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_ZLIMIT)) { - if (ED_pose_channel_in_IK_chain(ob, pchan)) { + if (BKE_pose_channel_in_IK_chain(ob, pchan)) { float corner[4][3], posetrans[3], mat[4][4]; float phi = 0.0f, theta = 0.0f, scale; int a, i; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 62e3f8471a3..23b80fc5bea 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -1672,7 +1672,7 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base int i; float drawsize; const bool is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera); - MovieClip *clip = BKE_object_movieclip_get(scene, base->object, 0); + MovieClip *clip = BKE_object_movieclip_get(scene, base->object, false); /* draw data for movie clip set as active for scene */ if (clip) { @@ -1900,9 +1900,9 @@ static void drawlattice(Scene *scene, View3D *v3d, Object *ob) const bool is_edit = (lt->editlatt != NULL); /* now we default make displist, this will modifiers work for non animated case */ - if (ob->disp.first == NULL) + if (ELEM(NULL, ob->curve_cache, ob->curve_cache->disp.first)) BKE_lattice_modifiers_calc(scene, ob); - dl = BKE_displist_find(&ob->disp, DL_VERTS); + dl = BKE_displist_find(&ob->curve_cache->disp, DL_VERTS); if (is_edit) { lt = lt->editlatt->latt; @@ -2552,6 +2552,11 @@ static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm) } } +static int draw_dm_override_material_color(int UNUSED(nr), void *UNUSED(attribs)) +{ + return 1; +} + /* Second section of routines: Combine first sets to form fancy * drawing routines (for example rendering twice to get overlays). * @@ -3094,9 +3099,6 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, BMVert *eve_act = NULL; bool use_occlude_wire = (v3d->flag2 & V3D_OCCLUDE_WIRE) && (dt > OB_WIRE); - // BLI_assert(!cageDM || !(cageDM->dirty & DM_DIRTY_NORMALS)); - BLI_assert(!finalDM || !(finalDM->dirty & DM_DIRTY_NORMALS)); - if (em->bm->selected.last) { BMEditSelection *ese = em->bm->selected.last; /* face is handeled above */ @@ -3369,8 +3371,6 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D if (!dm) return; - if (dm) BLI_assert(!(dm->dirty & DM_DIRTY_NORMALS)); - /* Check to draw dynamic paint colors (or weights from WeightVG modifiers). * Note: Last "preview-active" modifier in stack will win! */ if (DM_get_tessface_data_layer(dm, CD_PREVIEW_MCOL) && modifiers_isPreview(ob)) @@ -3473,7 +3473,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); - dm->drawMappedFaces(dm, NULL, GPU_enable_material, NULL, NULL, DM_DRAW_USE_COLORS); + dm->drawMappedFaces(dm, NULL, draw_dm_override_material_color, NULL, NULL, DM_DRAW_USE_COLORS); glDisable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); @@ -3803,12 +3803,16 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag, glEnable(GL_LIGHTING); glEnableClientState(GL_VERTEX_ARRAY); - if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW); - else glFrontFace(GL_CCW); if (ob->type == OB_MBALL) { /* mball always smooth shaded */ + if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW); + else glFrontFace(GL_CCW); glShadeModel(GL_SMOOTH); } + else { + if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CCW); + else glFrontFace(GL_CW); + } dl = lb->first; while (dl) { @@ -3971,7 +3975,7 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3 case OB_CURVE: cu = ob->data; - lb = &ob->disp; + lb = &ob->curve_cache->disp; if (solid) { dl = lb->first; @@ -4021,7 +4025,7 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3 break; case OB_SURF: - lb = &ob->disp; + lb = &ob->curve_cache->disp; if (solid) { dl = lb->first; @@ -4049,8 +4053,11 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3 case OB_MBALL: if (BKE_mball_is_basis(ob)) { - lb = &ob->disp; - if (lb->first == NULL) BKE_displist_make_mball(scene, ob); + lb = ob->curve_cache ? &ob->curve_cache->disp : NULL; + if (ELEM(lb, lb->first, NULL)) { + BKE_displist_make_mball(scene, ob); + lb = &ob->curve_cache->disp; + } if (lb->first == NULL) { return true; } @@ -4087,7 +4094,7 @@ static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *ba if (v3d->flag2 & V3D_BACKFACE_CULLING) { /* not all displists use same in/out normal direction convention */ glEnable(GL_CULL_FACE); - glCullFace((base->object->type == OB_MBALL || base->object->derivedFinal) ? GL_BACK : GL_FRONT); + glCullFace(GL_BACK); } retval = drawDispList_nobackface(scene, v3d, rv3d, base, dt, dflag, ob_wire_col); @@ -4566,7 +4573,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv pdd->ma_col = ma_col; } - psys->lattice = psys_get_lattice(&sim); + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); /* circles don't use drawdata, so have to add a special case here */ if ((pdd || draw_as == PART_DRAW_CIRC) && draw_as != PART_DRAW_PATH) { @@ -4892,9 +4899,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED; } - if (psys->lattice) { - end_latt_deform(psys->lattice); - psys->lattice = NULL; + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; } if (pdd) { @@ -5642,7 +5649,7 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, if ((cu->flag & CU_3D) && (ts->normalsize > 0.0015f) && (cu->drawflag & CU_HIDE_NORMALS) == 0) { UI_ThemeColor(TH_WIRE_EDIT); - for (bl = cu->bev.first, nu = nurb; nu && bl; bl = bl->next, nu = nu->next) { + for (bl = ob->curve_cache->bev.first, nu = nurb; nu && bl; bl = bl->next, nu = nu->next) { BevPoint *bevp = (BevPoint *)(bl + 1); int nr = bl->nr; int skip = nu->resolu / 16; @@ -6065,7 +6072,7 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d, } else if (pd->forcefield == PFIELD_GUIDE && ob->type == OB_CURVE) { Curve *cu = ob->data; - if ((cu->flag & CU_PATH) && cu->path && cu->path->data) { + if ((cu->flag & CU_PATH) && ob->curve_cache->path && ob->curve_cache->path->data) { float mindist, guidevec1[4], guidevec2[3]; //if (has_ipo_code(ob->ipo, OB_PD_FSTR)) @@ -6248,7 +6255,7 @@ static void draw_bounding_volume(Scene *scene, Object *ob, char type) bb = BKE_mesh_boundbox_get(ob); } else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - bb = ob->bb ? ob->bb : ( (Curve *)ob->data)->bb; + bb = BKE_curve_boundbox_get(ob); } else if (ob->type == OB_MBALL) { if (BKE_mball_is_basis(ob)) { @@ -6283,9 +6290,7 @@ static void drawtexspace(Object *ob) BKE_mesh_texspace_get(ob->data, loc, NULL, size); } else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - Curve *cu = ob->data; - copy_v3_v3(size, cu->size); - copy_v3_v3(loc, cu->loc); + BKE_curve_texspace_get(ob->data, loc, NULL, size); } else if (ob->type == OB_MBALL) { MetaBall *mb = ob->data; @@ -6323,7 +6328,6 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, glDepthMask(0); if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { - Curve *cu = ob->data; DerivedMesh *dm = ob->derivedFinal; bool has_faces = false; @@ -6331,16 +6335,16 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, has_faces = dm->getNumTessFaces(dm); } else { - has_faces = BKE_displist_has_faces(&ob->disp); + has_faces = BKE_displist_has_faces(&ob->curve_cache->disp); } - if (has_faces && ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb ? ob->bb : cu->bb)) { + if (has_faces && ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb)) { draw_index_wire = false; if (dm) { draw_mesh_object_outline(v3d, ob, dm); } else { - drawDispListwire(&ob->disp); + drawDispListwire(&ob->curve_cache->disp); } draw_index_wire = true; } @@ -6348,7 +6352,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, else if (ob->type == OB_MBALL) { if (BKE_mball_is_basis(ob)) { if ((base->flag & OB_FROMDUPLI) == 0) - drawDispListwire(&ob->disp); + drawDispListwire(&ob->curve_cache->disp); } } else if (ob->type == OB_ARMATURE) { @@ -6375,8 +6379,7 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, unsign glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { - Curve *cu = ob->data; - if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb ? ob->bb : cu->bb)) { + if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb)) { if (ob->type == OB_CURVE) draw_index_wire = false; @@ -6384,7 +6387,7 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, unsign drawCurveDMWired(ob); } else { - drawDispListwire(&ob->disp); + drawDispListwire(&ob->curve_cache->disp); } if (ob->type == OB_CURVE) @@ -6393,7 +6396,7 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, unsign } else if (ob->type == OB_MBALL) { if (BKE_mball_is_basis(ob)) { - drawDispListwire(&ob->disp); + drawDispListwire(&ob->curve_cache->disp); } } @@ -6662,23 +6665,17 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short /* faceselect exception: also draw solid when (dt == wire), except in editmode */ if (is_obact && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) { - if (ob->type == OB_MESH) { - - if (ob->mode & OB_MODE_EDIT) { - /* pass */ + if (ob->type == OB_MESH) { + if (dt < OB_SOLID) { + zbufoff = 1; + dt = OB_SOLID; } - else { - if (dt < OB_SOLID) { - zbufoff = 1; - dt = OB_SOLID; - } - if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { - dt = OB_PAINT; - } - - glEnable(GL_DEPTH_TEST); + if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { + dt = OB_PAINT; } + + glEnable(GL_DEPTH_TEST); } else { if (dt < OB_SOLID) { @@ -6703,7 +6700,9 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short /* bad exception, solve this! otherwise outline shows too late */ if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { /* still needed for curves hidden in other layers. depgraph doesnt handle that yet */ - if (ob->disp.first == NULL) BKE_displist_make_curveTypes(scene, ob, 0); + if (ELEM(NULL, ob->curve_cache, ob->curve_cache->disp.first)) { + BKE_displist_make_curveTypes(scene, ob, 0); + } } /* draw outline for selected objects, mesh does itself */ @@ -6807,7 +6806,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short draw_bounding_volume(scene, ob, ob->boundtype); } } - else if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb ? ob->bb : cu->bb)) { + else if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb)) { empty_object = drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col); } @@ -6825,7 +6824,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short draw_bounding_volume(scene, ob, ob->boundtype); } } - else if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb ? ob->bb : cu->bb)) { + else if (ED_view3d_boundbox_clip(rv3d, ob->obmat, ob->bb)) { empty_object = drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col); //XXX old animsys if (cu->path) @@ -7050,6 +7049,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short // get view vector copy_v3_v3(viewnormal, rv3d->viewinv[2]); + invert_m4_m4(ob->imat, ob->obmat); mul_mat3_m4_v3(ob->imat, viewnormal); normalize_v3(viewnormal); diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index 542ed7af0e6..a7940faa47d 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -83,6 +83,7 @@ struct GPUTexture; #ifdef DEBUG_DRAW_TIME # include "PIL_time.h" +# include "PIL_time_utildefines.h" #endif static int intersect_edges(float *points, float a, float b, float c, float d, float edges[12][2][3]) diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 6c61c2af816..58c0df6b6bd 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -44,6 +44,7 @@ #include "BKE_context.h" #include "BKE_icons.h" +#include "BKE_main.h" #include "BKE_object.h" #include "BKE_screen.h" @@ -258,6 +259,25 @@ void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d) } #endif +void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa) +{ + wmWindowManager *wm = bmain->wm.first; + + if (v3d->drawtype != OB_RENDER) { + ARegion *ar; + + for (ar = sa->regionbase.first; ar; ar = ar->next) { + RegionView3D *rv3d = ar->regiondata; + + if (rv3d && rv3d->render_engine) { + WM_jobs_kill_type(wm, ar, WM_JOB_TYPE_RENDER_PREVIEW); + RE_engine_free(rv3d->render_engine); + rv3d->render_engine = NULL; + } + } + } +} + /* ******************** default callbacks for view3d space ***************** */ static SpaceLink *view3d_new(const bContext *C) diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 75e7605df6b..eea084b4750 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -682,7 +682,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float } } BKE_nurb_test2D(nu); - BKE_nurb_handles_test(nu); /* test for bezier too */ + BKE_nurb_handles_test(nu, true); /* test for bezier too */ nu = nu->next; } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index fa8d43b1756..b737dba1a3b 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -220,10 +220,10 @@ void ED_view3d_clipping_enable(void) static bool view3d_clipping_test(const float co[3], float clip[6][4]) { - if (0.0f < clip[0][3] + dot_v3v3(co, clip[0])) - if (0.0f < clip[1][3] + dot_v3v3(co, clip[1])) - if (0.0f < clip[2][3] + dot_v3v3(co, clip[2])) - if (0.0f < clip[3][3] + dot_v3v3(co, clip[3])) + if (plane_point_side_v3(clip[0], co) > 0.0f) + if (plane_point_side_v3(clip[1], co) > 0.0f) + if (plane_point_side_v3(clip[2], co) > 0.0f) + if (plane_point_side_v3(clip[3], co) > 0.0f) return false; return true; @@ -1662,7 +1662,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, if (bgpic->flag & V3D_BGPIC_CAMERACLIP) { if (scene->camera) - clip = BKE_object_movieclip_get(scene, scene->camera, 1); + clip = BKE_object_movieclip_get(scene, scene->camera, true); } else { clip = bgpic->clip; @@ -2073,7 +2073,7 @@ static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Bas bb = *bb_tmp; /* must make a copy */ /* disable boundbox check for list creation */ - BKE_object_boundbox_flag(dob->ob, OB_BB_DISABLED, 1); + BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 1); /* need this for next part of code */ unit_m4(dob->ob->obmat); /* obmat gets restored */ @@ -2083,7 +2083,7 @@ static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Bas glEndList(); use_displist = true; - BKE_object_boundbox_flag(dob->ob, OB_BB_DISABLED, 0); + BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 0); } } if (use_displist) { diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 7b8c197f3e6..67c9ea4599c 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -85,26 +85,23 @@ /* for ndof prints */ // #define DEBUG_NDOF_MOTION -static void view3d_offset_lock_report(ReportList *reports) -{ - BKE_report(reports, RPT_WARNING, "View offset is locked"); -} - bool ED_view3d_offset_lock_check(struct View3D *v3d, struct RegionView3D *rv3d) { return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre); } -#define VIEW3D_OP_OFS_LOCK_TEST(C, op) \ - { \ - View3D *v3d_tmp = CTX_wm_view3d(C); \ - RegionView3D *rv3d_tmp = CTX_wm_region_view3d(C); \ - if (ED_view3d_offset_lock_check(v3d_tmp, rv3d_tmp)) { \ - view3d_offset_lock_report((op)->reports); \ - return OPERATOR_CANCELLED; \ - } \ - } (void)0 - +static bool view3d_operator_offset_lock_check(bContext *C, wmOperator *op) +{ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (ED_view3d_offset_lock_check(v3d, rv3d)) { + BKE_report(op->reports, RPT_WARNING, "View offset is locked"); + return true; + } + else { + return false; + } +} /* ********************** view3d_edit: view manipulations ********************* */ @@ -182,6 +179,27 @@ bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d) } } +/** + * For viewport operators that exit camera persp. + * + * \note This differs from simply setting ``rv3d->persp = persp`` because it + * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera, + * otherwise switching out of camera view may jump to a different part of the scene. + */ +static void view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const char persp) +{ + BLI_assert(rv3d->persp == RV3D_CAMOB); + BLI_assert(persp != RV3D_CAMOB); + + if (v3d->camera) { + rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); + ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); + } + + if (!ED_view3d_camera_lock_check(v3d, rv3d)) { + rv3d->persp = persp; + } +} /* ********************* box view support ***************** */ @@ -378,6 +396,7 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip) /* ************************** init for view ops **********************************/ typedef struct ViewOpsData { + /* context pointers (assigned by viewops_data_alloc) */ ScrArea *sa; ARegion *ar; View3D *v3d; @@ -435,10 +454,17 @@ static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3]) } -static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event) +/* -------------------------------------------------------------------- */ +/* ViewOpsData */ + +/** \name Generic View Operator Custom-Data. + * \{ */ + +/** + * Allocate and fill in context pointers for #ViewOpsData + */ +static void viewops_data_alloc(bContext *C, wmOperator *op) { - static float lastofs[3] = {0, 0, 0}; - RegionView3D *rv3d; ViewOpsData *vod = MEM_callocN(sizeof(ViewOpsData), "viewops data"); /* store data */ @@ -446,7 +472,17 @@ static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *even vod->sa = CTX_wm_area(C); vod->ar = CTX_wm_region(C); vod->v3d = vod->sa->spacedata.first; - vod->rv3d = rv3d = vod->ar->regiondata; + vod->rv3d = vod->ar->regiondata; +} + +/** + * Calculate the values for #ViewOpsData + */ +static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod = op->customdata; + static float lastofs[3] = {0, 0, 0}; + RegionView3D *rv3d = vod->rv3d; /* set the view from the camera, if view locking is enabled. * we may want to make this optional but for now its needed always */ @@ -489,10 +525,15 @@ static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *even } else if (U.uiflag & USER_ZBUF_ORBIT) { Scene *scene = CTX_data_scene(C); + float fallback_depth_pt[3]; view3d_operator_needs_opengl(C); /* needed for zbuf drawing */ - if ((vod->use_dyn_ofs = ED_view3d_autodist(scene, vod->ar, vod->v3d, event->mval, vod->dyn_ofs, true))) { + negate_v3_v3(fallback_depth_pt, rv3d->ofs); + + if ((vod->use_dyn_ofs = ED_view3d_autodist(scene, vod->ar, vod->v3d, + event->mval, vod->dyn_ofs, true, fallback_depth_pt))) + { if (rv3d->is_persp) { float my_origin[3]; /* original G.vd->ofs */ float my_pivot[3]; /* view */ @@ -522,6 +563,14 @@ static void viewops_data_create(bContext *C, wmOperator *op, const wmEvent *even negate_v3_v3(rv3d->ofs, dvec); } + else { + float mval_ar_mid[2] = { + (float)vod->ar->winx / 2.0f, + (float)vod->ar->winy / 2.0f}; + + ED_view3d_win_to_3d(vod->ar, vod->dyn_ofs, mval_ar_mid, rv3d->ofs); + negate_v3(rv3d->ofs); + } negate_v3(vod->dyn_ofs); copy_v3_v3(vod->ofs, rv3d->ofs); } @@ -576,6 +625,8 @@ static void viewops_data_free(bContext *C, wmOperator *op) if (p && (p->flags & PAINT_FAST_NAVIGATE)) ED_region_tag_redraw(ar); } +/** \} */ + /* ************************** viewrotate **********************************/ @@ -928,37 +979,27 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event) static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; - RegionView3D *rv3d; /* makes op->customdata */ + viewops_data_alloc(C, op); viewops_data_create(C, op, event); vod = op->customdata; - rv3d = vod->rv3d; - if (rv3d->viewlock) { /* poll should check but in some cases fails, see poll func for details */ + if (vod->rv3d->viewlock) { /* poll should check but in some cases fails, see poll func for details */ viewops_data_free(C, op); return OPERATOR_PASS_THROUGH; } /* switch from camera view when: */ - if (rv3d->persp != RV3D_PERSP) { + if (vod->rv3d->persp != RV3D_PERSP) { if (U.uiflag & USER_AUTOPERSP) { if (!ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) { - rv3d->persp = RV3D_PERSP; + vod->rv3d->persp = RV3D_PERSP; } } - else if (rv3d->persp == RV3D_CAMOB) { - - /* changed since 2.4x, use the camera view */ - if (vod->v3d->camera) { - rv3d->dist = ED_view3d_offset_distance(vod->v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); - ED_view3d_from_object(vod->v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); - } - - if (!ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) { - rv3d->persp = rv3d->lpersp; - } + else if (vod->rv3d->persp == RV3D_CAMOB) { + view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, vod->rv3d->lpersp); } ED_region_tag_redraw(vod->ar); } @@ -970,7 +1011,7 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) else viewrotate_apply(vod, event->prevx, event->prevy); - ED_view3d_depth_tag_update(rv3d); + ED_view3d_depth_tag_update(vod->rv3d); viewops_data_free(C, op); @@ -979,7 +1020,7 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) else if (event->type == MOUSEROTATE) { /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */ viewrotate_apply(vod, event->prevx, event->y); - ED_view3d_depth_tag_update(rv3d); + ED_view3d_depth_tag_update(vod->rv3d); viewops_data_free(C, op); @@ -1012,9 +1053,13 @@ static int view3d_camera_user_poll(bContext *C) static int view3d_lock_poll(bContext *C) { View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - - return ED_view3d_offset_lock_check(v3d, rv3d); + if (v3d) { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (rv3d) { + return ED_view3d_offset_lock_check(v3d, rv3d); + } + } + return false; } static int viewrotate_cancel(bContext *C, wmOperator *op) @@ -1143,8 +1188,9 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, RegionView3D static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (event->type != NDOF_MOTION) + if (event->type != NDOF_MOTION) { return OPERATOR_CANCELLED; + } else { View3D *v3d = CTX_wm_view3d(C); ViewOpsData *vod; @@ -1153,6 +1199,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_view3d_camera_lock_init(v3d, rv3d); + viewops_data_alloc(C, op); viewops_data_create(C, op, event); vod = op->customdata; @@ -1210,7 +1257,7 @@ void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot) { /* identifiers */ ot->name = "NDOF Orbit View"; - ot->description = "Explore every angle of an object using the 3D mouse"; + ot->description = "Orbit the view using the 3D mouse"; ot->idname = "VIEW3D_OT_ndof_orbit"; /* api callbacks */ @@ -1225,8 +1272,9 @@ void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot) static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (event->type != NDOF_MOTION) + if (event->type != NDOF_MOTION) { return OPERATOR_CANCELLED; + } else { ViewOpsData *vod; View3D *v3d = CTX_wm_view3d(C); @@ -1237,6 +1285,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev rv3d->rot_angle = 0.f; /* off by default, until changed later this function */ + viewops_data_alloc(C, op); viewops_data_create(C, op, event); vod = op->customdata; @@ -1306,7 +1355,7 @@ void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot) { /* identifiers */ ot->name = "NDOF Orbit View with Zoom"; - ot->description = "Explore every angle of an object using the 3D mouse"; + ot->description = "Orbit and zoom the view using the 3D mouse"; ot->idname = "VIEW3D_OT_ndof_orbit_zoom"; /* api callbacks */ @@ -1322,14 +1371,16 @@ void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot) */ static int ndof_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (event->type != NDOF_MOTION) + if (event->type != NDOF_MOTION) { return OPERATOR_CANCELLED; + } else { View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); wmNDOFMotionData *ndof = (wmNDOFMotionData *) event->customdata; - VIEW3D_OP_OFS_LOCK_TEST(C, op); + if (view3d_operator_offset_lock_check(C, op)) + return OPERATOR_CANCELLED; ED_view3d_camera_lock_init(v3d, rv3d); @@ -1401,7 +1452,7 @@ void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot) { /* identifiers */ ot->name = "NDOF Pan View"; - ot->description = "Position your viewpoint with the 3D mouse"; + ot->description = "Pan the view with the 3D mouse"; ot->idname = "VIEW3D_OT_ndof_pan"; /* api callbacks */ @@ -1422,13 +1473,13 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } else { - ViewOpsData *vod; RegionView3D *rv3d; View3D *v3d = CTX_wm_view3d(C); wmNDOFMotionData *ndof = (wmNDOFMotionData *) event->customdata; + viewops_data_alloc(C, op); viewops_data_create(C, op, event); vod = op->customdata; rv3d = vod->rv3d; @@ -1492,7 +1543,7 @@ void VIEW3D_OT_ndof_all(struct wmOperatorType *ot) { /* identifiers */ ot->name = "NDOF Move View"; - ot->description = "Position your viewpoint with the 3D mouse"; + ot->description = "Pan and rotate the view with the 3D mouse"; ot->idname = "VIEW3D_OT_ndof_all"; /* api callbacks */ @@ -1627,6 +1678,7 @@ static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event) ViewOpsData *vod; /* makes op->customdata */ + viewops_data_alloc(C, op); viewops_data_create(C, op, event); vod = op->customdata; @@ -1993,6 +2045,7 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) ViewOpsData *vod; /* makes op->customdata */ + viewops_data_alloc(C, op); viewops_data_create(C, op, event); vod = op->customdata; @@ -2207,12 +2260,34 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewOpsData *vod; - VIEW3D_OP_OFS_LOCK_TEST(C, op); + if (view3d_operator_offset_lock_check(C, op)) + return OPERATOR_CANCELLED; /* makes op->customdata */ - viewops_data_create(C, op, event); + viewops_data_alloc(C, op); vod = op->customdata; + if (vod->rv3d->viewlock) { /* poll should check but in some cases fails, see poll func for details */ + viewops_data_free(C, op); + return OPERATOR_PASS_THROUGH; + } + + /* needs to run before 'viewops_data_create' so the backup 'rv3d->ofs' is correct */ + /* switch from camera view when: */ + if (vod->rv3d->persp != RV3D_PERSP) { + if (vod->rv3d->persp == RV3D_CAMOB) { + /* ignore rv3d->lpersp because dolly only makes sense in perspective mode */ + view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, RV3D_PERSP); + } + else { + vod->rv3d->persp = RV3D_PERSP; + } + ED_region_tag_redraw(vod->ar); + } + + viewops_data_create(C, op, event); + + /* if one or the other zoom position aren't set, set from event */ if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) { RNA_int_set(op->ptr, "mx", event->x); @@ -2257,25 +2332,6 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_FINISHED; } -/* like ED_operator_region_view3d_active but check its not in ortho view */ -static int viewdolly_poll(bContext *C) -{ - RegionView3D *rv3d = CTX_wm_region_view3d(C); - - if (rv3d) { - if (rv3d->persp == RV3D_PERSP) { - return 1; - } - else { - View3D *v3d = CTX_wm_view3d(C); - if (ED_view3d_camera_lock_check(v3d, rv3d)) { - return 1; - } - } - } - return 0; -} - static int viewdolly_cancel(bContext *C, wmOperator *op) { viewops_data_free(C, op); @@ -2294,7 +2350,7 @@ void VIEW3D_OT_dolly(wmOperatorType *ot) ot->invoke = viewdolly_invoke; ot->exec = viewdolly_exec; ot->modal = viewdolly_modal; - ot->poll = viewdolly_poll; + ot->poll = ED_operator_region_view3d_active; ot->cancel = viewdolly_cancel; /* flags */ @@ -2306,8 +2362,8 @@ void VIEW3D_OT_dolly(wmOperatorType *ot) } static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar, - const float min[3], const float max[3], - bool ok_dist) + const float min[3], const float max[3], + bool ok_dist, const int smooth_viewtx) { RegionView3D *rv3d = ar->regiondata; float afm[3]; @@ -2369,10 +2425,14 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar, if (rv3d->persp == RV3D_CAMOB && !ED_view3d_camera_lock_check(v3d, rv3d)) { rv3d->persp = RV3D_PERSP; - view3d_smooth_view(C, v3d, ar, v3d->camera, NULL, new_ofs, NULL, ok_dist ? &new_dist : NULL, NULL); + ED_view3d_smooth_view(C, v3d, ar, v3d->camera, NULL, + new_ofs, NULL, ok_dist ? &new_dist : NULL, NULL, + smooth_viewtx); } else { - view3d_smooth_view(C, v3d, ar, NULL, NULL, new_ofs, NULL, ok_dist ? &new_dist : NULL, NULL); + ED_view3d_smooth_view(C, v3d, ar, NULL, NULL, + new_ofs, NULL, ok_dist ? &new_dist : NULL, NULL, + smooth_viewtx); } /* smooth view does viewlock RV3D_BOXVIEW copy */ @@ -2381,7 +2441,7 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar, /* same as view3d_from_minmax but for all regions (except cameras) */ static void view3d_from_minmax_multi(bContext *C, View3D *v3d, const float min[3], const float max[3], - const bool ok_dist) + const bool ok_dist, const int smooth_viewtx) { ScrArea *sa = CTX_wm_area(C); ARegion *ar; @@ -2391,7 +2451,7 @@ static void view3d_from_minmax_multi(bContext *C, View3D *v3d, /* when using all regions, don't jump out of camera view, * but _do_ allow locked cameras to be moved */ if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) { - view3d_from_minmax(C, v3d, ar, min, max, ok_dist); + view3d_from_minmax(C, v3d, ar, min, max, ok_dist, smooth_viewtx); } } } @@ -2409,6 +2469,7 @@ static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in /* any one of the regions may be locked */ (use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA)); const bool center = RNA_boolean_get(op->ptr, "center"); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); float min[3], max[3]; bool change = false; @@ -2448,10 +2509,10 @@ static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in } if (use_all_regions) { - view3d_from_minmax_multi(C, v3d, min, max, true); + view3d_from_minmax_multi(C, v3d, min, max, true, smooth_viewtx); } else { - view3d_from_minmax(C, v3d, ar, min, max, true); + view3d_from_minmax(C, v3d, ar, min, max, true, smooth_viewtx); } return OPERATOR_FINISHED; @@ -2493,6 +2554,7 @@ static int viewselected_exec(bContext *C, wmOperator *op) const bool skip_camera = (ED_view3d_camera_lock_check(v3d, ar->regiondata) || /* any one of the regions may be locked */ (use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA)); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); INIT_MINMAX(min, max); @@ -2568,10 +2630,10 @@ static int viewselected_exec(bContext *C, wmOperator *op) } if (use_all_regions) { - view3d_from_minmax_multi(C, v3d, min, max, ok_dist); + view3d_from_minmax_multi(C, v3d, min, max, ok_dist, smooth_viewtx); } else { - view3d_from_minmax(C, v3d, ar, min, max, ok_dist); + view3d_from_minmax(C, v3d, ar, min, max, ok_dist, smooth_viewtx); } // XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT); @@ -2683,7 +2745,7 @@ void VIEW3D_OT_view_lock_to_active(wmOperatorType *ot) ot->flag = 0; } -static int viewcenter_cursor_exec(bContext *C, wmOperator *UNUSED(op)) +static int viewcenter_cursor_exec(bContext *C, wmOperator *op) { View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -2691,11 +2753,14 @@ static int viewcenter_cursor_exec(bContext *C, wmOperator *UNUSED(op)) if (rv3d) { ARegion *ar = CTX_wm_region(C); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); /* non camera center */ float new_ofs[3]; negate_v3_v3(new_ofs, give_cursor(scene, v3d)); - view3d_smooth_view(C, v3d, ar, NULL, NULL, new_ofs, NULL, NULL, NULL); + ED_view3d_smooth_view(C, v3d, ar, NULL, NULL, + new_ofs, NULL, NULL, NULL, + smooth_viewtx); /* smooth view does viewlock RV3D_BOXVIEW copy */ } @@ -2718,7 +2783,7 @@ void VIEW3D_OT_view_center_cursor(wmOperatorType *ot) ot->flag = 0; } -static int viewcenter_pick_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -2727,10 +2792,11 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *UNUSED(op), const wmE if (rv3d) { float new_ofs[3]; + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); view3d_operator_needs_opengl(C); - if (ED_view3d_autodist(scene, ar, v3d, event->mval, new_ofs, false)) { + if (ED_view3d_autodist(scene, ar, v3d, event->mval, new_ofs, false, NULL)) { /* pass */ } else { @@ -2739,7 +2805,9 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *UNUSED(op), const wmE ED_view3d_win_to_3d_int(ar, new_ofs, event->mval, new_ofs); } negate_v3(new_ofs); - view3d_smooth_view(C, v3d, ar, NULL, NULL, new_ofs, NULL, NULL, NULL); + ED_view3d_smooth_view(C, v3d, ar, NULL, NULL, + new_ofs, NULL, NULL, NULL, + smooth_viewtx); } return OPERATOR_FINISHED; @@ -2988,6 +3056,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) RegionView3D *rv3d = CTX_wm_region_view3d(C); Scene *scene = CTX_data_scene(C); int gesture_mode; + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); /* Zooms in on a border drawn by the user */ rcti rect; @@ -3119,7 +3188,9 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) new_dist = dist_range_min; } - view3d_smooth_view(C, v3d, ar, NULL, NULL, new_ofs, NULL, &new_dist, NULL); + ED_view3d_smooth_view(C, v3d, ar, NULL, NULL, + new_ofs, NULL, &new_dist, NULL, + smooth_viewtx); if (rv3d->viewlock & RV3D_BOXVIEW) view3d_boxview_sync(CTX_wm_area(C), ar); @@ -3224,7 +3295,8 @@ static EnumPropertyItem prop_view_items[] = { static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar, float q1, float q2, float q3, float q4, - short view, int perspo, bool align_active) + short view, int perspo, bool align_active, + const int smooth_viewtx) { RegionView3D *rv3d = ar->regiondata; /* no NULL check is needed, poll checks */ float new_quat[4]; @@ -3285,14 +3357,18 @@ static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar, if (U.uiflag & USER_AUTOPERSP) rv3d->persp = view ? RV3D_ORTHO : RV3D_PERSP; else if (rv3d->persp == RV3D_CAMOB) rv3d->persp = perspo; - view3d_smooth_view(C, v3d, ar, v3d->camera, NULL, rv3d->ofs, new_quat, NULL, NULL); + ED_view3d_smooth_view(C, v3d, ar, v3d->camera, NULL, + rv3d->ofs, new_quat, NULL, NULL, + smooth_viewtx); } else { if (U.uiflag & USER_AUTOPERSP) rv3d->persp = view ? RV3D_ORTHO : RV3D_PERSP; else if (rv3d->persp == RV3D_CAMOB) rv3d->persp = perspo; - view3d_smooth_view(C, v3d, ar, NULL, NULL, NULL, new_quat, NULL, NULL); + ED_view3d_smooth_view(C, v3d, ar, NULL, NULL, + NULL, new_quat, NULL, NULL, + smooth_viewtx); } } @@ -3306,6 +3382,7 @@ static int viewnumpad_exec(bContext *C, wmOperator *op) static int perspo = RV3D_PERSP; int viewnum, nextperspo; bool align_active; + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); /* no NULL check is needed, poll checks */ ED_view3d_context_user_region(C, &v3d, &ar); @@ -3330,32 +3407,32 @@ static int viewnumpad_exec(bContext *C, wmOperator *op) switch (viewnum) { case RV3D_VIEW_BOTTOM: axis_set_view(C, v3d, ar, 0.0, -1.0, 0.0, 0.0, - viewnum, nextperspo, align_active); + viewnum, nextperspo, align_active, smooth_viewtx); break; case RV3D_VIEW_BACK: axis_set_view(C, v3d, ar, 0.0, 0.0, -M_SQRT1_2, -M_SQRT1_2, - viewnum, nextperspo, align_active); + viewnum, nextperspo, align_active, smooth_viewtx); break; case RV3D_VIEW_LEFT: axis_set_view(C, v3d, ar, 0.5, -0.5, 0.5, 0.5, - viewnum, nextperspo, align_active); + viewnum, nextperspo, align_active, smooth_viewtx); break; case RV3D_VIEW_TOP: axis_set_view(C, v3d, ar, 1.0, 0.0, 0.0, 0.0, - viewnum, nextperspo, align_active); + viewnum, nextperspo, align_active, smooth_viewtx); break; case RV3D_VIEW_FRONT: axis_set_view(C, v3d, ar, M_SQRT1_2, -M_SQRT1_2, 0.0, 0.0, - viewnum, nextperspo, align_active); + viewnum, nextperspo, align_active, smooth_viewtx); break; case RV3D_VIEW_RIGHT: axis_set_view(C, v3d, ar, 0.5, -0.5, -0.5, -0.5, - viewnum, nextperspo, align_active); + viewnum, nextperspo, align_active, smooth_viewtx); break; case RV3D_VIEW_CAMERA: @@ -3411,7 +3488,9 @@ static int viewnumpad_exec(bContext *C, wmOperator *op) /* finally do snazzy view zooming */ rv3d->persp = RV3D_CAMOB; - view3d_smooth_view(C, v3d, ar, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens); + ED_view3d_smooth_view(C, v3d, ar, NULL, v3d->camera, + rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens, + smooth_viewtx); } else { @@ -3419,7 +3498,8 @@ static int viewnumpad_exec(bContext *C, wmOperator *op) /* does view3d_smooth_view too */ axis_set_view(C, v3d, ar, rv3d->lviewquat[0], rv3d->lviewquat[1], rv3d->lviewquat[2], rv3d->lviewquat[3], - rv3d->lview, rv3d->lpersp, 0); + rv3d->lview, rv3d->lpersp, 0, + smooth_viewtx); } } break; @@ -3479,6 +3559,7 @@ static int vieworbit_exec(bContext *C, wmOperator *op) if (rv3d->viewlock == 0) { if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) { + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); float angle = DEG2RADF((float)U.pad_rot_angle); float quat_mul[4]; float quat_new[4]; @@ -3506,7 +3587,9 @@ static int vieworbit_exec(bContext *C, wmOperator *op) mul_qt_qtqt(quat_new, rv3d->viewquat, quat_mul); rv3d->view = RV3D_VIEW_USER; - view3d_smooth_view(C, CTX_wm_view3d(C), ar, NULL, NULL, NULL, quat_new, NULL, NULL); + ED_view3d_smooth_view(C, CTX_wm_view3d(C), ar, NULL, NULL, + NULL, quat_new, NULL, NULL, + smooth_viewtx); return OPERATOR_FINISHED; } @@ -3533,6 +3616,190 @@ void VIEW3D_OT_view_orbit(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit"); } + +/* ************************ viewroll ******************************** */ + +static void view_roll_angle(ARegion *ar, float quat[4], const float orig_quat[4], const float dvec[3], float angle) +{ + RegionView3D *rv3d = ar->regiondata; + float quat_mul[4]; + + /* camera axis */ + axis_angle_to_quat(quat_mul, dvec, angle); + + mul_qt_qtqt(quat, orig_quat, quat_mul); + rv3d->view = RV3D_VIEW_USER; +} + +static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y)) +{ + float angle = 0.0; + + { + float len1, len2, tot; + + tot = vod->ar->winrct.xmax - vod->ar->winrct.xmin; + len1 = (vod->ar->winrct.xmax - x) / tot; + len2 = (vod->ar->winrct.xmax - vod->origx) / tot; + angle = (len1 - len2) * (float)M_PI * 4.0f; + } + + if (angle != 0.0f) + view_roll_angle(vod->ar, vod->rv3d->viewquat, vod->oldquat, vod->mousevec, angle); + + if (vod->rv3d->viewlock & RV3D_BOXVIEW) + view3d_boxview_sync(vod->sa, vod->ar); + + ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); + + ED_region_tag_redraw(vod->ar); +} + +static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod = op->customdata; + short event_code = VIEW_PASS; + + /* execute the events */ + if (event->type == MOUSEMOVE) { + event_code = VIEW_APPLY; + } + else if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case VIEW_MODAL_CONFIRM: + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_MOVE: + WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + case VIEWROT_MODAL_SWITCH_ROTATE: + WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL); + event_code = VIEW_CONFIRM; + break; + } + } + else if (event->type == vod->origkey && event->val == KM_RELEASE) { + event_code = VIEW_CONFIRM; + } + + if (event_code == VIEW_APPLY) { + viewroll_apply(vod, event->x, event->y); + } + else if (event_code == VIEW_CONFIRM) { + ED_view3d_depth_tag_update(vod->rv3d); + viewops_data_free(C, op); + + return OPERATOR_FINISHED; + } + + return OPERATOR_RUNNING_MODAL; +} + +static int viewroll_exec(bContext *C, wmOperator *op) +{ + View3D *v3d; + RegionView3D *rv3d; + ARegion *ar; + + if (op->customdata) { + ViewOpsData *vod = op->customdata; + ar = vod->ar; + v3d = vod->v3d; + } + else { + ar = CTX_wm_region(C); + v3d = CTX_wm_view3d(C); + } + + rv3d = ar->regiondata; + if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) { + const float angle = RNA_float_get(op->ptr, "angle"); + float mousevec[3]; + float quat_new[4]; + + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + + normalize_v3_v3(mousevec, rv3d->viewinv[2]); + negate_v3(mousevec); + view_roll_angle(ar, quat_new, rv3d->viewquat, mousevec, angle); + + ED_view3d_smooth_view(C, v3d, ar, NULL, NULL, + NULL, quat_new, NULL, NULL, + smooth_viewtx); + + viewops_data_free(C, op); + return OPERATOR_FINISHED; + } + else { + viewops_data_free(C, op); + return OPERATOR_CANCELLED; + } +} + +static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ViewOpsData *vod; + + /* makes op->customdata */ + viewops_data_alloc(C, op); + viewops_data_create(C, op, event); + vod = op->customdata; + + if (RNA_struct_property_is_set(op->ptr, "angle")) { + viewroll_exec(C, op); + } + else { + /* overwrite the mouse vector with the view direction */ + normalize_v3_v3(vod->mousevec, vod->rv3d->viewinv[2]); + negate_v3(vod->mousevec); + + if (event->type == MOUSEROTATE) { + vod->origx = vod->oldx = event->x; + viewroll_apply(vod, event->prevx, event->prevy); + ED_view3d_depth_tag_update(vod->rv3d); + + viewops_data_free(C, op); + return OPERATOR_FINISHED; + } + else { + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + } + return OPERATOR_FINISHED; +} + +static int viewroll_cancel(bContext *C, wmOperator *op) +{ + viewops_data_free(C, op); + + return OPERATOR_CANCELLED; +} + +void VIEW3D_OT_view_roll(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "View Roll"; + ot->description = "Roll the view"; + ot->idname = "VIEW3D_OT_view_roll"; + + /* api callbacks */ + ot->invoke = viewroll_invoke; + ot->exec = viewroll_exec; + ot->modal = viewroll_modal; + ot->poll = ED_operator_rv3d_user_region_poll; + ot->cancel = viewroll_cancel; + + /* flags */ + ot->flag = 0; + + /* properties */ + ot->prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX); +} + static EnumPropertyItem prop_view_pan_items[] = { {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the Left"}, {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the Right"}, @@ -3553,7 +3820,8 @@ static int viewpan_exec(bContext *C, wmOperator *op) float zfac; int pandir; - VIEW3D_OP_OFS_LOCK_TEST(C, op); + if (view3d_operator_offset_lock_check(C, op)) + return OPERATOR_CANCELLED; pandir = RNA_enum_get(op->ptr, "type"); @@ -3855,6 +4123,11 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) float zfac; bool flip; + /* normally the caller should ensure this, + * but this is called from areas that aren't already dealing with the viewport */ + if (rv3d == NULL) + return; + zfac = ED_view3d_calc_zfac(rv3d, fp, &flip); /* reset the depth based on the view offset (we _know_ the offset is infront of us) */ @@ -3869,7 +4142,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) if (U.uiflag & USER_ZBUF_CURSOR) { /* maybe this should be accessed some other way */ view3d_operator_needs_opengl(C); - if (ED_view3d_autodist(scene, ar, v3d, mval, fp, true)) + if (ED_view3d_autodist(scene, ar, v3d, mval, fp, true, NULL)) depth_used = true; } @@ -4041,7 +4314,9 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg } /* XXX todo Zooms in on a border drawn by the user */ -bool ED_view3d_autodist(Scene *scene, ARegion *ar, View3D *v3d, const int mval[2], float mouse_worldloc[3], bool alphaoverride) +bool ED_view3d_autodist(Scene *scene, ARegion *ar, View3D *v3d, + const int mval[2], float mouse_worldloc[3], + const bool alphaoverride, const float fallback_depth_pt[3]) { bglMats mats; /* ZBuffer depth vars */ float depth_close; @@ -4053,22 +4328,27 @@ bool ED_view3d_autodist(Scene *scene, ARegion *ar, View3D *v3d, const int mval[2 depth_close = view_autodist_depth_margin(ar, mval, 4); - if (depth_close == FLT_MAX) - return false; + if (depth_close != FLT_MAX) { + cent[0] = (double)mval[0]; + cent[1] = (double)mval[1]; - cent[0] = (double)mval[0]; - cent[1] = (double)mval[1]; + if (gluUnProject(cent[0], cent[1], depth_close, + mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) + { + mouse_worldloc[0] = (float)p[0]; + mouse_worldloc[1] = (float)p[1]; + mouse_worldloc[2] = (float)p[2]; + return true; + } + } - if (!gluUnProject(cent[0], cent[1], depth_close, - mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) - { + if (fallback_depth_pt) { + ED_view3d_win_to_3d_int(ar, fallback_depth_pt, mval, mouse_worldloc); + return true; + } + else { return false; } - - mouse_worldloc[0] = (float)p[0]; - mouse_worldloc[1] = (float)p[1]; - mouse_worldloc[2] = (float)p[2]; - return true; } void ED_view3d_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode) diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index a1a13130b27..9341ea9d3e6 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -159,6 +159,11 @@ void fly_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_UP); WM_modalkeymap_add_item(keymap, FKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_DOWN); + WM_modalkeymap_add_item(keymap, UPARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_FORWARD); + WM_modalkeymap_add_item(keymap, DOWNARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_BACKWARD); + WM_modalkeymap_add_item(keymap, LEFTARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_LEFT); + WM_modalkeymap_add_item(keymap, RIGHTARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_RIGHT); + WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_X); WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_Z); @@ -580,6 +585,12 @@ static void flyEvent(FlyInfo *fly, const wmEvent *event) double time_currwheel; float time_wheel; + /* not quite correct but avoids confusion WASD/arrow keys 'locking up' */ + if (fly->axis == -1) { + fly->axis = 2; + fly->speed = fabsf(fly->speed); + } + time_currwheel = PIL_check_seconds_timer(); time_wheel = (float)(time_currwheel - fly->time_lastwheel); fly->time_lastwheel = time_currwheel; @@ -599,6 +610,12 @@ static void flyEvent(FlyInfo *fly, const wmEvent *event) double time_currwheel; float time_wheel; + /* not quite correct but avoids confusion WASD/arrow keys 'locking up' */ + if (fly->axis == -1) { + fly->axis = 2; + fly->speed = -fabsf(fly->speed); + } + time_currwheel = PIL_check_seconds_timer(); time_wheel = (float)(time_currwheel - fly->time_lastwheel); fly->time_lastwheel = time_currwheel; @@ -806,9 +823,10 @@ static void flyMoveCamera(bContext *C, RegionView3D *rv3d, FlyInfo *fly, static int flyApply(bContext *C, FlyInfo *fly) { -#define FLY_ROTATE_FAC 2.5f /* more is faster */ +#define FLY_ROTATE_FAC 10.0f /* more is faster */ #define FLY_ZUP_CORRECT_FAC 0.1f /* amount to correct per step */ #define FLY_ZUP_CORRECT_ACCEL 0.05f /* increase upright momentum each step */ +#define FLY_SMOOTH_FAC 20.0f /* higher value less lag */ /* fly mode - Shift+F * a fly loop where the user can move move the view as if they are flying @@ -1052,7 +1070,7 @@ static int flyApply(bContext *C, FlyInfo *fly) } /* impose a directional lag */ - interp_v3_v3v3(dvec, dvec_tmp, fly->dvec_prev, (1.0f / (1.0f + (time_redraw * 5.0f)))); + interp_v3_v3v3(dvec, dvec_tmp, fly->dvec_prev, (1.0f / (1.0f + (time_redraw * FLY_SMOOTH_FAC)))); if (rv3d->persp == RV3D_CAMOB) { Object *lock_ob = fly->root_parent ? fly->root_parent : fly->v3d->camera; diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 085af4e5c18..a496bbba72f 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -95,6 +95,7 @@ void VIEW3D_OT_view_persportho(struct wmOperatorType *ot); void VIEW3D_OT_background_image_add(struct wmOperatorType *ot); void VIEW3D_OT_background_image_remove(struct wmOperatorType *ot); void VIEW3D_OT_view_orbit(struct wmOperatorType *ot); +void VIEW3D_OT_view_roll(struct wmOperatorType *ot); void VIEW3D_OT_clip_border(struct wmOperatorType *ot); void VIEW3D_OT_cursor3d(struct wmOperatorType *ot); void VIEW3D_OT_manipulator(struct wmOperatorType *ot); @@ -186,8 +187,9 @@ void VIEW3D_OT_game_start(struct wmOperatorType *ot); bool ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[4][4], const struct BoundBox *bb); -void view3d_smooth_view(struct bContext *C, struct View3D *v3d, struct ARegion *ar, struct Object *, struct Object *, - float *ofs, float *quat, float *dist, float *lens); +void ED_view3d_smooth_view(struct bContext *C, struct View3D *v3d, struct ARegion *ar, struct Object *, struct Object *, + float *ofs, float *quat, float *dist, float *lens, + const int smooth_viewtx); void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect); void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d); diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index d13ab15d837..2023513ad92 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -368,7 +368,7 @@ void lattice_foreachScreenVert( Object *obedit = vc->obedit; Lattice *lt = obedit->data; BPoint *bp = lt->editlatt->latt->def; - DispList *dl = BKE_displist_find(&obedit->disp, DL_VERTS); + DispList *dl = obedit->curve_cache ? BKE_displist_find(&obedit->curve_cache->disp, DL_VERTS) : NULL; float *co = dl ? dl->verts : NULL; int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw; diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 6780b71c906..dec9085baeb 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -138,6 +138,7 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_view_all); WM_operatortype_append(VIEW3D_OT_viewnumpad); WM_operatortype_append(VIEW3D_OT_view_orbit); + WM_operatortype_append(VIEW3D_OT_view_roll); WM_operatortype_append(VIEW3D_OT_view_pan); WM_operatortype_append(VIEW3D_OT_view_persportho); WM_operatortype_append(VIEW3D_OT_background_image_add); @@ -283,7 +284,9 @@ void view3d_keymap(wmKeyConfig *keyconf) RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD4, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANLEFT); RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD6, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANRIGHT); RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANUP); - + RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD4, KM_PRESS, KM_SHIFT, 0)->ptr, "angle", M_PI / -12); + RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD6, KM_PRESS, KM_SHIFT, 0)->ptr, "angle", M_PI / 12); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANRIGHT); RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANLEFT); RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_PANUP); @@ -294,6 +297,9 @@ void view3d_keymap(wmKeyConfig *keyconf) RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELUPMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPUP); RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPDOWN); + RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELUPMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "angle", M_PI / -12); + RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "angle", M_PI / 12); + /* active aligned, replaces '*' key in 2.4x */ kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, KM_SHIFT, 0); RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT); @@ -371,6 +377,11 @@ void view3d_keymap(wmKeyConfig *keyconf) RNA_string_set(kmi->ptr, "value_1", "SOLID"); RNA_string_set(kmi->ptr, "value_2", "TEXTURED"); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", ZKEY, KM_PRESS, KM_SHIFT, 0); + RNA_string_set(kmi->ptr, "data_path", "space_data.viewport_shade"); + RNA_string_set(kmi->ptr, "value_1", "SOLID"); + RNA_string_set(kmi->ptr, "value_2", "RENDERED"); + /* selection*/ kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); RNA_boolean_set(kmi->ptr, "extend", FALSE); diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index 5e71913ea4a..28ffdea0e6c 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -405,15 +405,15 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float float line_end[3]; if (rv3d->is_persp) { - float mousevec[3]; + float mousevec[3], lambda; copy_v3_v3(line_sta, rv3d->viewinv[3]); ED_view3d_win_to_vector(ar, mval, mousevec); add_v3_v3v3(line_end, line_sta, mousevec); - if (isect_line_plane_v3(out, line_sta, line_end, depth_pt, rv3d->viewinv[2], true) == 0) { - /* highly unlikely to ever happen, mouse vector parallel with view plane */ - zero_v3(out); - } + /* note, we could use isect_line_plane_v3() however we want the intersection to be infront of the + * view no matter what, so apply the unsigned factor instead */ + lambda = line_plane_factor_v3(depth_pt, rv3d->viewinv[2], line_sta, line_end); + interp_v3_v3v3(out, line_sta, line_end, fabsf(lambda)); } else { float dx = (2.0f * mval[0] / (float)ar->winx) - 1.0f; diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index b2f2d5849a4..bca162d156b 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -803,7 +803,7 @@ static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE view3d_ruler_header_update(sa); - WM_cursor_modal(win, BC_CROSSCURSOR); + WM_cursor_modal_set(win, BC_CROSSCURSOR); WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; @@ -1029,7 +1029,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) exit: if (ELEM(exit_code, OPERATOR_FINISHED, OPERATOR_CANCELLED)) { - WM_cursor_restore(ruler_info->win); + WM_cursor_modal_restore(ruler_info->win); view3d_ruler_end(C, ruler_info); view3d_ruler_free(ruler_info); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 19426ab2dfa..8553791e229 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1462,7 +1462,7 @@ static bool mouse_select(bContext *C, const int mval[2], bool extend, bool desel /* index of bundle is 1<<16-based. if there's no "bone" index * in height word, this buffer value belongs to camera. not to bundle */ if (buffer[4 * i + 3] & 0xFFFF0000) { - MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, 0); + MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false); MovieTracking *tracking = &clip->tracking; ListBase *tracksbase; MovieTrackingTrack *track; @@ -2406,12 +2406,12 @@ static void paint_facesel_circle_select(ViewContext *vc, const bool select, cons { Object *ob = vc->obact; Mesh *me = ob ? ob->data : NULL; - /* int bbsel; */ /* UNUSED */ + bool bbsel; - if (me) { - bm_vertoffs = me->totpoly + 1; /* max index array */ + bm_vertoffs = me->totpoly + 1; /* max index array */ - /* bbsel = */ /* UNUSED */ EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); + bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); + if (bbsel) { edbm_backbuf_check_and_select_tfaces(me, select); EDBM_backbuf_free(); paintface_flush_flags(ob); @@ -2431,15 +2431,17 @@ static void paint_vertsel_circle_select(ViewContext *vc, const bool select, cons const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT); Object *ob = vc->obact; Mesh *me = ob->data; - /* int bbsel; */ /* UNUSED */ + bool bbsel; /* CircleSelectUserData data = {NULL}; */ /* UNUSED */ if (use_zbuf) { bm_vertoffs = me->totvert + 1; /* max index array */ - /* bbsel = */ /* UNUSED */ EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); - edbm_backbuf_check_and_select_verts_obmode(me, select); - EDBM_backbuf_free(); + bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); + if (bbsel) { + edbm_backbuf_check_and_select_verts_obmode(me, select); + EDBM_backbuf_free(); + } } else { CircleSelectUserData data; diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index 0f2f07a1053..7c29ab01c24 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -143,7 +143,7 @@ static void special_transvert_update(Object *obedit) } BKE_nurb_test2D(nu); - BKE_nurb_handles_test(nu); /* test for bezier too */ + BKE_nurb_handles_test(nu, true); /* test for bezier too */ nu = nu->next; } } @@ -882,7 +882,7 @@ void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot) static void bundle_midpoint(Scene *scene, Object *ob, float vec[3]) { - MovieClip *clip = BKE_object_movieclip_get(scene, ob, 0); + MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); MovieTracking *tracking; MovieTrackingObject *object; int ok = 0; diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 44c338d22b9..74d72061995 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -40,6 +40,7 @@ #include "BLI_rect.h" #include "BLI_listbase.h" #include "BLI_utildefines.h" +#include "BLI_callbacks.h" #include "BKE_anim.h" #include "BKE_action.h" @@ -152,8 +153,9 @@ static void view3d_smooth_view_state_restore(const struct SmoothView3DState *sms /* will start timer if appropriate */ /* the arguments are the desired situation */ -void view3d_smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera, Object *camera, - float *ofs, float *quat, float *dist, float *lens) +void ED_view3d_smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera, Object *camera, + float *ofs, float *quat, float *dist, float *lens, + const int smooth_viewtx) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); @@ -202,7 +204,7 @@ void view3d_smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera } /* skip smooth viewing for render engine draw */ - if (U.smooth_viewtx && v3d->drawtype != OB_RENDER) { + if (smooth_viewtx && v3d->drawtype != OB_RENDER) { bool changed = false; /* zero means no difference */ if (oldcamera != camera) @@ -231,7 +233,7 @@ void view3d_smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera rv3d->view = RV3D_VIEW_USER; } - sms.time_allowed = (double)U.smooth_viewtx / 1000.0; + sms.time_allowed = (double)smooth_viewtx / 1000.0; /* if this is view rotation only * we can decrease the time allowed by @@ -376,12 +378,15 @@ void VIEW3D_OT_smoothview(wmOperatorType *ot) /* identifiers */ ot->name = "Smooth View"; + ot->description = ""; ot->idname = "VIEW3D_OT_smoothview"; - ot->description = "The time to animate the change of view (in milliseconds)"; /* api callbacks */ ot->invoke = view3d_smoothview_invoke; + /* flags */ + ot->flag = OPTYPE_INTERNAL; + ot->poll = ED_operator_view3d_active; } @@ -505,7 +510,7 @@ void VIEW3D_OT_camera_to_view_selected(wmOperatorType *ot) } -static int view3d_setobjectascamera_exec(bContext *C, wmOperator *UNUSED(op)) +static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op) { View3D *v3d; ARegion *ar; @@ -514,6 +519,8 @@ static int view3d_setobjectascamera_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + /* no NULL check is needed, poll checks */ ED_view3d_context_user_region(C, &v3d, &ar); rv3d = ar->regiondata; @@ -525,8 +532,11 @@ static int view3d_setobjectascamera_exec(bContext *C, wmOperator *UNUSED(op)) if (v3d->scenelock) scene->camera = ob; - if (camera_old != ob) /* unlikely but looks like a glitch when set to the same */ - view3d_smooth_view(C, v3d, ar, camera_old, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens); + if (camera_old != ob) { /* unlikely but looks like a glitch when set to the same */ + ED_view3d_smooth_view(C, v3d, ar, camera_old, v3d->camera, + rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens, + smooth_viewtx); + } WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS | NC_OBJECT | ND_DRAW, CTX_data_scene(C)); } @@ -617,7 +627,7 @@ bool ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[4][4], const BoundB int a, flag = -1, fl; if (bb == NULL) return true; - if (bb->flag & OB_BB_DISABLED) return true; + if (bb->flag & BOUNDBOX_DISABLED) return true; mul_m4_m4m4(mat, rv3d->persmat, obmat); @@ -1170,7 +1180,7 @@ static bool view3d_localview_init(Main *bmain, Scene *scene, ScrArea *sa, Report return ok; } -static void restore_localviewdata(ScrArea *sa, int free) +static void restore_localviewdata(Main *bmain, ScrArea *sa, int free) { ARegion *ar; View3D *v3d = sa->spacedata.first; @@ -1207,12 +1217,7 @@ static void restore_localviewdata(ScrArea *sa, int free) } } - if (v3d->drawtype != OB_RENDER) { - if (rv3d->render_engine) { - RE_engine_free(rv3d->render_engine); - rv3d->render_engine = NULL; - } - } + ED_view3d_shade_update(bmain, v3d, sa); } } } @@ -1227,7 +1232,7 @@ static bool view3d_localview_exit(Main *bmain, Scene *scene, ScrArea *sa) locallay = v3d->lay & 0xFF000000; - restore_localviewdata(sa, 1); /* 1 = free */ + restore_localviewdata(bmain, sa, 1); /* 1 = free */ /* for when in other window the layers have changed */ if (v3d->scenelock) v3d->lay = scene->lay; @@ -1433,6 +1438,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) { #ifdef WITH_GAMEENGINE Scene *startscene = CTX_data_scene(C); + Main *bmain = CTX_data_main(C); ScrArea /* *sa, */ /* UNUSED */ *prevsa = CTX_wm_area(C); ARegion *ar, *prevar = CTX_wm_region(C); wmWindow *prevwin = CTX_wm_window(C); @@ -1449,6 +1455,8 @@ static int game_engine_exec(bContext *C, wmOperator *op) * the window manager until after this operator exits */ WM_redraw_windows(C); + BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_PRE); + rv3d = CTX_wm_region_view3d(C); /* sa = CTX_wm_area(C); */ /* UNUSED */ ar = CTX_wm_region(C); @@ -1504,6 +1512,8 @@ static int game_engine_exec(bContext *C, wmOperator *op) BKE_scene_set_background(CTX_data_main(C), startscene); //XXX BKE_scene_update_for_newframe(bmain, scene, scene->lay); + BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_POST); + return OPERATOR_FINISHED; #else (void)C; /* unused */ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index d5a9d0f9f93..ce2f07f1813 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1749,29 +1749,32 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) // If modal, save settings back in scene if not set as operator argument if (t->flag & T_MODAL) { - /* save settings if not set in operator */ - if ((prop = RNA_struct_find_property(op->ptr, "proportional")) && - !RNA_property_is_set(op->ptr, prop)) - { - if (t->obedit) - ts->proportional = proportional; - else if (t->options & CTX_MASK) - ts->proportional_mask = (proportional != PROP_EDIT_OFF); - else - ts->proportional_objects = (proportional != PROP_EDIT_OFF); - } - if ((prop = RNA_struct_find_property(op->ptr, "proportional_size")) && - !RNA_property_is_set(op->ptr, prop)) - { - ts->proportional_size = t->prop_size; - } + /* skip saving proportional edit if it was not actually used */ + if (!(t->options & CTX_NO_PET)) { + if ((prop = RNA_struct_find_property(op->ptr, "proportional")) && + !RNA_property_is_set(op->ptr, prop)) + { + if (t->obedit) + ts->proportional = proportional; + else if (t->options & CTX_MASK) + ts->proportional_mask = (proportional != PROP_EDIT_OFF); + else + ts->proportional_objects = (proportional != PROP_EDIT_OFF); + } - if ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) && - !RNA_property_is_set(op->ptr, prop)) - { - ts->prop_mode = t->prop_mode; + if ((prop = RNA_struct_find_property(op->ptr, "proportional_size")) && + !RNA_property_is_set(op->ptr, prop)) + { + ts->proportional_size = t->prop_size; + } + + if ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) && + !RNA_property_is_set(op->ptr, prop)) + { + ts->prop_mode = t->prop_mode; + } } /* do we check for parameter? */ @@ -1851,7 +1854,7 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even options |= CTX_TEXTURE; } } - + t->options = options; t->mode = mode; @@ -1893,6 +1896,7 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even else if (t->spacetype == SPACE_CLIP) { unit_m3(t->spacemtx); t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); + t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t); } else if (t->spacetype == SPACE_NODE) { unit_m3(t->spacemtx); @@ -3005,7 +3009,12 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) copy_v3_v3(center, td->center); } else if (t->options & CTX_MOVIECLIP) { - copy_v3_v3(center, td->center); + if (td->flag & TD_INDIVIDUAL_SCALE) { + copy_v3_v3(center, td->center); + } + else { + copy_v3_v3(center, t->center); + } } else { copy_v3_v3(center, t->center); @@ -4795,6 +4804,26 @@ static BMEdge *get_other_edge(BMVert *v, BMEdge *e) return NULL; } +/* interpoaltes along a line made up of 2 segments (used for edge slide) */ +static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float t) +{ + float t_mid, t_delta; + + /* could be pre-calculated */ + t_mid = line_point_factor_v3(v2, v1, v3); + + t_delta = t - t_mid; + if (fabsf(t_delta) < FLT_EPSILON) { + copy_v3_v3(p, v2); + } + else if (t_delta < 0.0f) { + interp_v3_v3v3(p, v1, v2, t / t_mid); + } + else { + interp_v3_v3v3(p, v2, v3, (t - t_mid) / (1.0f - t_mid)); + } +} + static void len_v3_ensure(float v[3], const float length) { normalize_v3(v); @@ -4820,7 +4849,7 @@ static bool bm_loop_calc_opposite_co(BMLoop *l_tmp, float tvec[3]; if (isect_line_plane_v3(tvec, l_iter->v->co, l_iter->next->v->co, - l_tmp->v->co, plane_no, false)) + l_tmp->v->co, plane_no)) { const float fac = line_point_factor_v3(tvec, l_iter->v->co, l_iter->next->v->co); /* allow some overlap to avoid missing the intersection because of float precision */ @@ -5707,20 +5736,16 @@ static void drawEdgeSlide(const struct bContext *C, TransInfo *t) /* Non-Prop mode */ if (sld && sld->is_proportional == FALSE) { View3D *v3d = CTX_wm_view3d(C); - float marker[3]; - float v1[3], v2[3]; - float interp_v; + float co_a[3], co_b[3], co_mark[3]; TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; + const float fac = (sld->perc + 1.0f) / 2.0f; const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f; const float guide_size = ctrl_size - 0.5f; const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; const int alpha_shade = -30; - add_v3_v3v3(v1, curr_sv->v_co_orig, curr_sv->dir_a); - add_v3_v3v3(v2, curr_sv->v_co_orig, curr_sv->dir_b); - - interp_v = (sld->perc + 1.0f) / 2.0f; - interp_v3_v3v3(marker, v2, v1, interp_v); + add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_a); + add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_b); if (v3d && v3d->zbuf) glDisable(GL_DEPTH_TEST); @@ -5761,7 +5786,12 @@ static void drawEdgeSlide(const struct bContext *C, TransInfo *t) UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade); glPointSize(guide_size); bglBegin(GL_POINTS); - bglVertex3fv(marker); +#if 0 + interp_v3_v3v3(co_mark, co_b, co_a, fac); + bglVertex3fv(co_mark); +#endif + interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac); + bglVertex3fv(co_mark); bglEnd(); @@ -5823,10 +5853,10 @@ static int doEdgeSlide(TransInfo *t, float perc) add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_b); if (sld->flipped_vtx) { - interp_v3_v3v3(sv->v->co, co_b, co_a, fac); + interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac); } else { - interp_v3_v3v3(sv->v->co, co_a, co_b, fac); + interp_line_v3_v3v3v3(sv->v->co, co_a, sv->v_co_orig, co_b, fac); } } } diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 4a1c4203a43..a4828317604 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -341,7 +341,9 @@ typedef struct TransInfo { float auto_values[4]; float axis[3]; float axis_orig[3]; /* TransCon can change 'axis', store the original value here */ - + + short remove_on_cancel; /* remove elements if operator is cancelled */ + void *view; struct bContext *context; /* Only valid (non null) during an operator called function. */ struct ScrArea *sa; @@ -350,6 +352,7 @@ typedef struct TransInfo { struct ToolSettings *settings; struct wmTimer *animtimer; struct wmKeyMap *keymap; /* so we can do lookups for header text */ + struct ReportList *reports; /* assign from the operator, or can be NULL */ int mval[2]; /* current mouse position */ float zfac; /* use for 3d view */ struct Object *obedit; @@ -455,7 +458,7 @@ typedef struct TransInfo { #define TD_USEQUAT (1 << 3) #define TD_NOTCONNECTED (1 << 4) #define TD_SINGLESIZE (1 << 5) /* used for scaling of MetaElem->rad */ -/*#define TD_TIMEONLY (1 << 8) */ /*UNUSED*/ +#define TD_INDIVIDUAL_SCALE (1 << 8) /* Scale relative to individual element center */ #define TD_NOCENTER (1 << 9) #define TD_NO_EXT (1 << 10) /* ext abused for particle key timing */ #define TD_SKIP (1 << 11) /* don't transform this data */ diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index fd8fba91fc9..a73bf86feb1 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -727,6 +727,7 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) RegionView3D *rv3d = CTX_wm_region_view3d(C); float tmat[4][4], imat[4][4]; float center[3]; + int depth_test_enabled; UI_ThemeColor(TH_GRID); @@ -759,10 +760,17 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) glScalef(1.0f / aspx, 1.0f / aspy, 1.0); } + depth_test_enabled = glIsEnabled(GL_DEPTH_TEST); + if (depth_test_enabled) + glDisable(GL_DEPTH_TEST); + set_inverted_drawing(1); drawcircball(GL_LINE_LOOP, center, t->prop_size, imat); set_inverted_drawing(0); + if (depth_test_enabled) + glEnable(GL_DEPTH_TEST); + glPopMatrix(); } } diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 95ec20a0c2b..f5a12fed076 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -58,9 +58,12 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" -#include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_smallhash.h" +#include "BLI_listbase.h" +#include "BLI_linklist_stack.h" +#include "BLI_string.h" +#include "BLI_rect.h" #include "BKE_DerivedMesh.h" #include "BKE_action.h" @@ -120,7 +123,19 @@ #include "transform.h" #include "bmesh.h" -#include "BLI_sys_types.h" // for intptr_t support +/** + * Transforming around ourselves is no use, fallback to individual origins, + * useful for curve/armatures. + */ +static void transform_around_single_fallback(TransInfo *t) +{ + if ((t->total == 1) && + (ELEM3(t->around, V3D_CENTER, V3D_CENTROID, V3D_ACTIVE)) && + (ELEM3(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) + { + t->around = V3D_LOCAL; + } +} /* when transforming islands */ struct TransIslandData { @@ -274,6 +289,13 @@ static void createTransTexspace(TransInfo *t) id = ob->data; if (id == NULL || !ELEM3(GS(id->name), ID_ME, ID_CU, ID_MB)) { + BKE_report(t->reports, RPT_ERROR, "Unsupported object type for text-space transform"); + t->total = 0; + return; + } + + if (BKE_object_obdata_is_libdata(ob)) { + BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform"); t->total = 0; return; } @@ -989,8 +1011,7 @@ static void createTransPose(TransInfo *t, Object *ob) if (arm->flag & ARM_RESTPOS) { if (ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE) == 0) { - // XXX use transform operator reports - // BKE_report(op->reports, RPT_ERROR, "Cannot select linked when sync selection is enabled"); + BKE_report(t->reports, RPT_ERROR, "Cannot select linked when sync selection is enabled"); return; } } @@ -1030,8 +1051,7 @@ static void createTransPose(TransInfo *t, Object *ob) } if (td != (t->data + t->total)) { - // XXX use transform operator reports - // BKE_report(op->reports, RPT_DEBUG, "Bone selection count error"); + BKE_report(t->reports, RPT_DEBUG, "Bone selection count error"); } /* initialize initial auto=ik chainlen's? */ @@ -1078,6 +1098,8 @@ static void createTransArmatureVerts(TransInfo *t) if (!t->total) return; + transform_around_single_fallback(t); + copy_m3_m4(mtx, t->obedit->obmat); pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); @@ -1402,6 +1424,8 @@ static void createTransCurveVerts(TransInfo *t) else t->total = countsel; t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Curve EditMode)"); + transform_around_single_fallback(t); + copy_m3_m4(mtx, t->obedit->obmat); pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); @@ -1437,7 +1461,9 @@ static void createTransCurveVerts(TransInfo *t) { copy_v3_v3(td->iloc, bezt->vec[0]); td->loc = bezt->vec[0]; - copy_v3_v3(td->center, bezt->vec[(hide_handles || bezt->f2 & SELECT) ? 1 : 0]); + copy_v3_v3(td->center, bezt->vec[(hide_handles || + (t->around == V3D_LOCAL) || + (bezt->f2 & SELECT)) ? 1 : 0]); if (hide_handles) { if (bezt->f2 & SELECT) td->flag = TD_SELECTED; else td->flag = 0; @@ -1505,7 +1531,9 @@ static void createTransCurveVerts(TransInfo *t) { copy_v3_v3(td->iloc, bezt->vec[2]); td->loc = bezt->vec[2]; - copy_v3_v3(td->center, bezt->vec[(hide_handles || bezt->f2 & SELECT) ? 1 : 2]); + copy_v3_v3(td->center, bezt->vec[(hide_handles || + (t->around == V3D_LOCAL) || + (bezt->f2 & SELECT)) ? 1 : 2]); if (hide_handles) { if (bezt->f2 & SELECT) td->flag = TD_SELECTED; else td->flag = 0; @@ -1546,7 +1574,7 @@ static void createTransCurveVerts(TransInfo *t) * but for now just don't change handle types */ if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT) == 0) { /* sets the handles based on their selection, do this after the data is copied to the TransData */ - BKE_nurb_handles_test(nu); + BKE_nurb_handles_test(nu, !hide_handles); } } else { @@ -1848,15 +1876,13 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float /* need to be very careful of feedback loops here, store previous dist's to avoid feedback */ float *dists_prev = MEM_mallocN(bm->totvert * sizeof(float), __func__); - BMVert **queue = MEM_mallocN(bm->totvert * sizeof(BMVert *), __func__); - STACK_DECLARE(queue); + BLI_LINKSTACK_DECLARE(queue, BMVert *); /* any BM_ELEM_TAG'd vertex is in 'queue_next', so we don't add in twice */ - BMVert **queue_next = MEM_mallocN(bm->totvert * sizeof(BMVert *), __func__); - STACK_DECLARE(queue_next); + BLI_LINKSTACK_DECLARE(queue_next, BMVert *); - STACK_INIT(queue); - STACK_INIT(queue_next); + BLI_LINKSTACK_INIT(queue); + BLI_LINKSTACK_INIT(queue_next); { BMIter viter; @@ -1871,7 +1897,7 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float dists[i] = FLT_MAX; } else { - STACK_PUSH(queue, v); + BLI_LINKSTACK_PUSH(queue, v); dists[i] = 0.0f; } @@ -1880,11 +1906,11 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float do { BMVert *v; - unsigned int i; + LinkNode *lnk; memcpy(dists_prev, dists, sizeof(float) * bm->totvert); - while ((v = STACK_POP(queue))) { + while ((v = BLI_LINKSTACK_POP(queue))) { BMIter iter; BMEdge *e; BMLoop *l; @@ -1896,7 +1922,7 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) { if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) { BM_elem_flag_enable(v_other, BM_ELEM_TAG); - STACK_PUSH(queue_next, v_other); + BLI_LINKSTACK_PUSH(queue_next, v_other); } } } @@ -1912,7 +1938,7 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) { if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) { BM_elem_flag_enable(v_other, BM_ELEM_TAG); - STACK_PUSH(queue_next, v_other); + BLI_LINKSTACK_PUSH(queue_next, v_other); } } } while ((l = l->next) != l_end); @@ -1921,22 +1947,20 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float } /* clear for the next loop */ - for (i = 0; i < STACK_SIZE(queue_next); i++) { - BM_elem_flag_disable(queue_next[i], BM_ELEM_TAG); + for (lnk = queue_next; lnk; lnk = lnk->next) { + BM_elem_flag_disable((BMVert *)lnk->link, BM_ELEM_TAG); } - STACK_SWAP(queue, queue_next); + BLI_LINKSTACK_SWAP(queue, queue_next); /* none should be tagged now since 'queue_next' is empty */ BLI_assert(BM_iter_mesh_count_flag(BM_VERTS_OF_MESH, bm, BM_ELEM_TAG, true) == 0); - } while (STACK_SIZE(queue)); + } while (BLI_LINKSTACK_SIZE(queue)); - STACK_FREE(queue); - STACK_FREE(queue_next); + BLI_LINKSTACK_FREE(queue); + BLI_LINKSTACK_FREE(queue_next); - MEM_freeN(queue); - MEM_freeN(queue_next); MEM_freeN(dists_prev); } @@ -2125,7 +2149,7 @@ static void createTransEditVerts(TransInfo *t) BMVert *eve; BMIter iter; BMVert *eve_act = NULL; - float *mappedcos = NULL, *quats = NULL; + float (*mappedcos)[3] = NULL, (*quats)[4] = NULL; float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL; float *dists = NULL; int a; @@ -2214,30 +2238,34 @@ static void createTransEditVerts(TransInfo *t) island_info = editmesh_islands_info_calc(em, &island_info_tot, &island_vert_map); } - /* BMESH_TODO, crazy-space writing into the index values is BAD!, means we cant - * use the values for vertex mirror - campbell */ - /* detect CrazySpace [tm] */ if (modifiers_getCageIndex(t->scene, t->obedit, NULL, 1) >= 0) { - if (modifiers_isCorrectableDeformed(t->obedit)) { - int totleft; + int totleft = -1; + if (modifiers_isCorrectableDeformed(t->scene, t->obedit)) { /* check if we can use deform matrices for modifier from the * start up to stack, they are more accurate than quats */ totleft = editbmesh_get_first_deform_matrices(t->scene, t->obedit, em, &defmats, &defcos); + } - /* if we still have more modifiers, also do crazyspace - * correction with quats, relative to the coordinates after - * the modifiers that support deform matrices (defcos) */ - if (totleft > 0) { - mappedcos = crazyspace_get_mapped_editverts(t->scene, t->obedit); - quats = MEM_mallocN((t->total) * sizeof(float) * 4, "crazy quats"); - crazyspace_set_quats_editmesh(em, (float *)defcos, mappedcos, quats); /* BMESH_TODO, abuses vertex index, should use an int array */ - if (mappedcos) - MEM_freeN(mappedcos); - } + /* if we still have more modifiers, also do crazyspace + * correction with quats, relative to the coordinates after + * the modifiers that support deform matrices (defcos) */ + +#if 0 /* TODO, fix crazyspace+extrude so it can be enabled for general use - campbell */ + if ((totleft > 0) || (totleft == -1)) +#else + if (totleft > 0) +#endif + { + mappedcos = crazyspace_get_mapped_editverts(t->scene, t->obedit); + quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats"); + crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats); + if (mappedcos) + MEM_freeN(mappedcos); + } - if (defcos) - MEM_freeN(defcos); + if (defcos) { + MEM_freeN(defcos); } } @@ -2283,12 +2311,12 @@ static void createTransEditVerts(TransInfo *t) } /* CrazySpace */ - if (defmats || (quats && BM_elem_index_get(eve) != -1)) { + if (defmats || (quats && BM_elem_flag_test(eve, BM_ELEM_TAG))) { float mat[3][3], qmat[3][3], imat[3][3]; /* use both or either quat and defmat correction */ - if (quats && BM_elem_index_get(eve) != -1) { - quat_to_mat3(qmat, quats + 4 * BM_elem_index_get(eve)); + if (quats && BM_elem_flag_test(eve, BM_ELEM_TAG)) { + quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]); if (defmats) mul_serie_m3(mat, mtx, qmat, defmats[a], @@ -3866,7 +3894,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) } /* if handles were not selected, store their selection status */ - if (!(sel1) && !(sel3)) { + if (!(sel1) || !(sel3)) { if (hdata == NULL) hdata = initTransDataCurveHandles(td, bezt); } @@ -5248,6 +5276,48 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o } } +static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t) +{ + SpaceClip *sc = t->sa->spacedata.first; + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTrackingPlaneTrack *plane_track; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); + int framenr = ED_space_clip_get_clip_frame_number(sc); + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + bool do_update = false; + + do_update |= (plane_track->flag & SELECT) != 0; + if (do_update == false) { + if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) { + int i; + for (i = 0; i < plane_track->point_tracksnr; i++) { + MovieTrackingTrack *track = plane_track->point_tracks[i]; + + if (TRACK_VIEW_SELECTED(sc, track)) { + do_update = true; + break; + } + } + } + } + + if (do_update) { + BKE_tracking_track_plane_from_existing_motion(plane_track, framenr); + } + } + + if (t->scene->nodetree) { + /* tracks can be used for stabilization nodes, + * flush update for such nodes */ + nodeUpdateID(t->scene->nodetree, &clip->id); + WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL); + } +} + static void special_aftertrans_update__mask(bContext *C, TransInfo *t) { Mask *mask = NULL; @@ -5281,6 +5351,25 @@ static void special_aftertrans_update__mask(bContext *C, TransInfo *t) } } +static void special_aftertrans_update__node(bContext *UNUSED(C), TransInfo *t) +{ + int canceled = (t->state == TRANS_CANCEL); + + if (canceled && t->remove_on_cancel) { + /* remove selected nodes on cancel */ + SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first; + bNodeTree *ntree = snode->edittree; + if (ntree) { + bNode *node, *node_next; + for (node = ntree->nodes.first; node; node = node_next) { + node_next = node->next; + if (node->flag & NODE_SELECT) + nodeFreeNode(ntree, node); + } + } + } +} + static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) { /* so automerge supports mirror */ @@ -5392,6 +5481,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) } else if (t->spacetype == SPACE_NODE) { SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first; + special_aftertrans_update__node(C, t); if (canceled == 0) { ED_node_post_apply_transform(C, snode->edittree); @@ -5403,15 +5493,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) } else if (t->spacetype == SPACE_CLIP) { if (t->options & CTX_MOVIECLIP) { - SpaceClip *sc = t->sa->spacedata.first; - MovieClip *clip = ED_space_clip_get_clip(sc); - - if (t->scene->nodetree) { - /* tracks can be used for stabilization nodes, - * flush update for such nodes */ - nodeUpdateID(t->scene->nodetree, &clip->id); - WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL); - } + special_aftertrans_update__movieclip(C, t); } else if (t->options & CTX_MASK) { special_aftertrans_update__mask(C, t); @@ -5959,7 +6041,8 @@ static void createTransNodeData(bContext *UNUSED(C), TransInfo *t) enum transDataTracking_Mode { transDataTracking_ModeTracks = 0, - transDataTracking_ModeCurves = 1 + transDataTracking_ModeCurves = 1, + transDataTracking_ModePlaneTracks = 2, }; typedef struct TransDataTracking { @@ -5978,6 +6061,9 @@ typedef struct TransDataTracking { /* marker transformation from curves editor */ float *prev_pos, scale; short coord; + + MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; } TransDataTracking; static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt, @@ -6008,6 +6094,7 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra tdt->markersnr = track->markersnr; tdt->markers = track->markers; + tdt->track = track; if (rel) { if (!anchor) { @@ -6026,6 +6113,7 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra copy_v3_v3(td->iloc, td->loc); //copy_v3_v3(td->center, td->loc); + td->flag |= TD_INDIVIDUAL_SCALE; td->center[0] = marker->pos[0] * aspx; td->center[1] = marker->pos[1] * aspy; @@ -6076,6 +6164,52 @@ static void trackToTransData(const int framenr, TransData *td, TransData2D *td2d } } +static void planeMarkerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt, + MovieTrackingPlaneTrack *plane_track, float corner[2], + float aspx, float aspy) +{ + tdt->mode = transDataTracking_ModePlaneTracks; + tdt->plane_track = plane_track; + + td2d->loc[0] = corner[0] * aspx; /* hold original location */ + td2d->loc[1] = corner[1] * aspy; + + td2d->loc2d = corner; /* current location */ + td2d->loc[2] = 0.0f; + + td->flag = 0; + td->loc = td2d->loc; + copy_v3_v3(td->iloc, td->loc); + copy_v3_v3(td->center, td->loc); + + memset(td->axismtx, 0, sizeof(td->axismtx)); + td->axismtx[2][2] = 1.0f; + + td->ext = NULL; + td->val = NULL; + + td->flag |= TD_SELECTED; + td->dist = 0.0; + + unit_m3(td->mtx); + unit_m3(td->smtx); +} + +static void planeTrackToTransData(const int framenr, TransData *td, TransData2D *td2d, + TransDataTracking *tdt, MovieTrackingPlaneTrack *plane_track, + float aspx, float aspy) +{ + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr); + int i; + + tdt->flag = plane_marker->flag; + plane_marker->flag &= ~PLANE_MARKER_TRACKED; + + for (i = 0; i < 4; i++) { + planeMarkerToTransDataInit(td++, td2d++, tdt++, plane_track, plane_marker->corners[i], aspx, aspy); + } +} + static void transDataTrackingFree(TransInfo *t) { TransDataTracking *tdt = t->customData; @@ -6096,7 +6230,9 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t) SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; TransDataTracking *tdt; int framenr = ED_space_clip_get_clip_frame_number(sc); float aspx, aspy; @@ -6122,6 +6258,15 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t) track = track->next; } + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (plane_track->flag & SELECT) { + t->total += 4; + } + } + if (t->total == 0) return; @@ -6165,11 +6310,23 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t) track = track->next; } + + for (plane_track = plane_tracks_base->first; + plane_track; + plane_track = plane_track->next) + { + if (plane_track->flag & SELECT) { + planeTrackToTransData(framenr, td, td2d, tdt, plane_track, aspx, aspy); + td += 4; + td2d += 4; + tdt += 4; + } + } } static void markerToTransCurveDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt, - MovieTrackingMarker *marker, MovieTrackingMarker *prev_marker, - short coord, float size) + MovieTrackingTrack *track, MovieTrackingMarker *marker, + MovieTrackingMarker *prev_marker, short coord, float size) { float frames_delta = (marker->framenr - prev_marker->framenr); @@ -6180,6 +6337,7 @@ static void markerToTransCurveDataInit(TransData *td, TransData2D *td2d, TransDa tdt->coord = coord; tdt->scale = 1.0f / size * frames_delta; tdt->prev_pos = prev_marker->pos; + tdt->track = track; /* calculate values depending on marker's speed */ td2d->loc[0] = marker->framenr; @@ -6265,14 +6423,14 @@ static void createTransTrackingCurvesData(bContext *C, TransInfo *t) continue; if (marker->flag & MARKER_GRAPH_SEL_X) { - markerToTransCurveDataInit(td, td2d, tdt, marker, &track->markers[i - 1], 0, width); + markerToTransCurveDataInit(td, td2d, tdt, track, marker, &track->markers[i - 1], 0, width); td += 1; td2d += 1; tdt += 1; } if (marker->flag & MARKER_GRAPH_SEL_Y) { - markerToTransCurveDataInit(td, td2d, tdt, marker, &track->markers[i - 1], 1, height); + markerToTransCurveDataInit(td, td2d, tdt, track, marker, &track->markers[i - 1], 1, height); td += 1; td2d += 1; @@ -6313,57 +6471,54 @@ static void createTransTrackingData(bContext *C, TransInfo *t) static void cancelTransTracking(TransInfo *t) { - TransDataTracking *tdt = t->customData; SpaceClip *sc = t->sa->spacedata.first; - MovieClip *clip = ED_space_clip_get_clip(sc); - ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); - MovieTrackingTrack *track; - MovieTrackingMarker *marker; - int a, framenr = ED_space_clip_get_clip_frame_number(sc); + int i, framenr = ED_space_clip_get_clip_frame_number(sc); - if (tdt->mode == transDataTracking_ModeTracks) { - track = tracksbase->first; - while (track) { - if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) { - marker = BKE_tracking_marker_get(track, framenr); - marker->flag = tdt->flag; + i = 0; + while (i < t->total) { + TransDataTracking *tdt = (TransDataTracking *) t->customData + i; - tdt++; + if (tdt->mode == transDataTracking_ModeTracks) { + MovieTrackingTrack *track = tdt->track; + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); - if (track->flag & SELECT) - tdt++; + marker->flag = tdt->flag; - if (track->pat_flag & SELECT) - tdt += 2; + if (track->flag & SELECT) + i++; - if (track->search_flag & SELECT) - tdt += 2; - } + if (track->pat_flag & SELECT) + i += 4; - track = track->next; + if (track->search_flag & SELECT) + i += 2; } - } - else if (tdt->mode == transDataTracking_ModeCurves) { - MovieTrackingMarker *prev_marker; + else if (tdt->mode == transDataTracking_ModeCurves) { + MovieTrackingTrack *track = tdt->track; + MovieTrackingMarker *marker, *prev_marker; + int a; - track = tracksbase->first; - while (track) { - if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) { - for (a = 1; a < track->markersnr; a++) { - marker = &track->markers[a]; - prev_marker = &track->markers[a - 1]; + for (a = 1; a < track->markersnr; a++) { + marker = &track->markers[a]; + prev_marker = &track->markers[a - 1]; - if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) - continue; + if ((marker->flag & MARKER_DISABLED) || (prev_marker->flag & MARKER_DISABLED)) + continue; - if (marker->flag & (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y)) { - marker->flag = tdt->flag; - } + if (marker->flag & (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y)) { + marker->flag = tdt->flag; } } + } + else if (tdt->mode == transDataTracking_ModePlaneTracks) { + MovieTrackingPlaneTrack *plane_track = tdt->plane_track; + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr); - track = track->next; + plane_marker->flag = tdt->flag; + i += 3; } + + i++; } } @@ -6432,6 +6587,10 @@ void flushTransTracking(TransInfo *t) else if (tdt->mode == transDataTracking_ModeCurves) { td2d->loc2d[tdt->coord] = tdt->prev_pos[tdt->coord] + td2d->loc[1] * tdt->scale; } + else if (tdt->mode == transDataTracking_ModePlaneTracks) { + td2d->loc2d[0] = td2d->loc[0] / aspx; + td2d->loc2d[1] = td2d->loc[1] / aspy; + } } } @@ -6443,29 +6602,40 @@ typedef struct TransDataMasking { float handle[2], orig_handle[2]; float vec[3][3]; MaskSplinePoint *point; + float parent_matrix[3][3]; + float parent_inverse_matrix[3][3]; } TransDataMasking; -static void MaskPointToTransData(MaskSplinePoint *point, +static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point, TransData *td, TransData2D *td2d, TransDataMasking *tdm, const int propmode, const float asp[2]) { BezTriple *bezt = &point->bezt; short is_sel_point = MASKPOINT_ISSEL_KNOT(point); short is_sel_any = MASKPOINT_ISSEL_ANY(point); + float parent_matrix[3][3], parent_inverse_matrix[3][3]; tdm->point = point; copy_m3_m3(tdm->vec, bezt->vec); + BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix); + invert_m3_m3(parent_inverse_matrix, parent_matrix); + if (propmode || is_sel_point) { int i; for (i = 0; i < 3; i++) { + copy_m3_m3(tdm->parent_matrix, parent_matrix); + copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix); + /* CV coords are scaled by aspects. this is needed for rotations and * proportional editing to be consistent with the stretched CV coords * that are displayed. this also means that for display and numinput, * and when the the CV coords are flushed, these are converted each time */ - td2d->loc[0] = bezt->vec[i][0] * asp[0]; - td2d->loc[1] = bezt->vec[i][1] * asp[1]; + mul_v2_m3v2(td2d->loc, parent_matrix, bezt->vec[i]); + td2d->loc[0] *= asp[0]; + td2d->loc[1] *= asp[1]; td2d->loc[2] = 0.0f; + td2d->loc2d = bezt->vec[i]; td->flag = 0; @@ -6497,18 +6667,23 @@ static void MaskPointToTransData(MaskSplinePoint *point, td++; td2d++; + tdm++; } } else { tdm->is_handle = TRUE; + copy_m3_m3(tdm->parent_matrix, parent_matrix); + copy_m3_m3(tdm->parent_inverse_matrix, parent_inverse_matrix); BKE_mask_point_handle(point, tdm->handle); copy_v2_v2(tdm->orig_handle, tdm->handle); - td2d->loc[0] = tdm->handle[0] * asp[0]; - td2d->loc[1] = tdm->handle[1] * asp[1]; + mul_v2_m3v2(td2d->loc, parent_matrix, tdm->handle); + td2d->loc[0] *= asp[0]; + td2d->loc[1] *= asp[1]; td2d->loc[2] = 0.0f; + td2d->loc2d = tdm->handle; td->flag = 0; @@ -6538,6 +6713,7 @@ static void MaskPointToTransData(MaskSplinePoint *point, static void createTransMaskingData(bContext *C, TransInfo *t) { + Scene *scene = CTX_data_scene(C); Mask *mask = CTX_data_edit_mask(C); MaskLayer *masklay; TransData *td = NULL; @@ -6610,7 +6786,7 @@ static void createTransMaskingData(bContext *C, TransInfo *t) MaskSplinePoint *point = &spline->points[i]; if (propmode || MASKPOINT_ISSEL_ANY(point)) { - MaskPointToTransData(point, td, td2d, tdm, propmode, asp); + MaskPointToTransData(scene, point, td, td2d, tdm, propmode, asp); if (propmode || MASKPOINT_ISSEL_KNOT(point)) { td += 3; @@ -6643,6 +6819,7 @@ void flushTransMasking(TransInfo *t) for (a = 0, td = t->data2d, tdm = t->customData; a < t->total; a++, td++, tdm++) { td->loc2d[0] = td->loc[0] * inv[0]; td->loc2d[1] = td->loc[1] * inv[1]; + mul_m3_v2(tdm->parent_inverse_matrix, td->loc2d); if (tdm->is_handle) BKE_mask_point_set_handle(tdm->point, td->loc2d, t->flag & T_ALT_TRANSFORM, tdm->orig_handle, tdm->vec); diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index cb0a0530036..233ef1d18a5 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1052,6 +1052,7 @@ int initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even t->ar = ar; t->obedit = obedit; t->settings = ts; + t->reports = op ? op->reports : NULL; if (obedit) { copy_m3_m4(t->obedit_mat, obedit->obmat); @@ -1104,6 +1105,13 @@ int initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *even t->options |= CTX_EDGE; } + t->remove_on_cancel = false; + + if (op && (prop = RNA_struct_find_property(op->ptr, "remove_on_cancel")) && RNA_property_is_set(op->ptr, prop)) { + if (RNA_property_boolean_get(op->ptr, prop)) { + t->remove_on_cancel = true; + } + } /* Assign the space type, some exceptions for running in different mode */ if (sa == NULL) { @@ -1511,7 +1519,6 @@ void calculateCenterCursor2D(TransInfo *t) if (t->spacetype == SPACE_IMAGE) { SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first; - /* only space supported right now but may change */ if (t->options & CTX_MASK) { ED_space_image_get_aspect(sima, &aspx, &aspy); } @@ -1520,17 +1527,37 @@ void calculateCenterCursor2D(TransInfo *t) } cursor = sima->cursor; } + else if (t->spacetype == SPACE_CLIP) { + SpaceClip *space_clip = (SpaceClip *) t->sa->spacedata.first; + if (t->options & CTX_MOVIECLIP) { + ED_space_clip_get_aspect_dimension_aware(space_clip, &aspx, &aspy); + } + else { + ED_space_clip_get_aspect(space_clip, &aspx, &aspy); + } + cursor = space_clip->cursor; + } if (cursor) { if (t->options & CTX_MASK) { float co[2]; float frame_size[2]; - SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first; - ED_space_image_get_size_fl(sima, frame_size); - - BKE_mask_coord_from_frame(co, cursor, frame_size); - ED_space_image_get_aspect(sima, &aspx, &aspy); + if (t->spacetype == SPACE_IMAGE) { + SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first; + ED_space_image_get_size_fl(sima, frame_size); + BKE_mask_coord_from_frame(co, cursor, frame_size); + ED_space_image_get_aspect(sima, &aspx, &aspy); + } + else if (t->spacetype == SPACE_CLIP) { + SpaceClip *space_clip = (SpaceClip *) t->sa->spacedata.first; + ED_space_clip_get_size_fl(space_clip, frame_size); + BKE_mask_coord_from_frame(co, cursor, frame_size); + ED_space_clip_get_aspect(space_clip, &aspx, &aspy); + } + else { + BLI_assert(!"Shall not happen"); + } t->center[0] = co[0] * aspx; t->center[1] = co[1] * aspy; @@ -1609,7 +1636,7 @@ void calculateCenter(TransInfo *t) calculateCenterMedian(t); break; case V3D_CURSOR: - if (t->spacetype == SPACE_IMAGE) + if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) calculateCenterCursor2D(t); else if (t->spacetype == SPACE_IPO) calculateCenterCursorGraph2D(t); diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 6fecf0d6642..f667a98812b 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -428,12 +428,12 @@ int calc_manipulator_stats(const bContext *C) totsel++; } else { - if (bezt->f1) { - calc_tw_center(scene, bezt->vec[0]); + if (bezt->f1 & SELECT) { + calc_tw_center(scene, bezt->vec[(v3d->around == V3D_LOCAL) ? 1 : 0]); totsel++; } - if (bezt->f3) { - calc_tw_center(scene, bezt->vec[2]); + if (bezt->f3 & SELECT) { + calc_tw_center(scene, bezt->vec[(v3d->around == V3D_LOCAL) ? 1 : 2]); totsel++; } } @@ -1858,11 +1858,12 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op) * See [#34621], it's a miracle it did not cause more problems!!! */ /* However, we need to copy the "release_confirm" property... */ PointerRNA props_ptr; - WM_operator_properties_create(&props_ptr, "TRANSFORM_OT_trackball"); + wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_trackball", true); + WM_operator_properties_create_ptr(&props_ptr, ot); RNA_boolean_set(&props_ptr, "release_confirm", RNA_boolean_get(op->ptr, "release_confirm")); - - WM_operator_name_call(C, "TRANSFORM_OT_trackball", WM_OP_INVOKE_DEFAULT, &props_ptr); - //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_trackball", 0), event, NULL, NULL, FALSE); + WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, &props_ptr); + //wm_operator_invoke(C, WM_operatortype_find(ot->idname, 0), event, NULL, NULL, FALSE); + WM_operator_properties_free(&props_ptr); } else if (drawflags & MAN_ROT_C) { switch (drawflags) { diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index eb204be3220..e7c22fc0899 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -537,6 +537,8 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) if (flags & P_OPTIONS) { 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"); + RNA_def_property_flag(prop, PROP_HIDDEN); } if (flags & P_CORRECT_UV) { diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 55d80d63234..cd6a2e6712e 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -728,31 +728,46 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], } } else { + const bool use_handle = (cu->drawflag & CU_HIDE_HANDLES) == 0; + for (nu = nurbs->first; nu; nu = nu->next) { /* only bezier has a normal */ if (nu->type == CU_BEZIER) { bezt = nu->bezt; a = nu->pntsu; while (a--) { + short flag = 0; + +#define SEL_F1 (1 << 0) +#define SEL_F2 (1 << 1) +#define SEL_F3 (1 << 2) + + if (use_handle) { + if (bezt->f1 & SELECT) flag |= SEL_F1; + if (bezt->f2 & SELECT) flag |= SEL_F2; + if (bezt->f3 & SELECT) flag |= SEL_F3; + } + else { + flag = (bezt->f2 & SELECT) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0; + } + /* exception */ - if ((bezt->f1 | bezt->f2 | bezt->f3) & SELECT) { + if (flag) { float tvec[3]; - if ((bezt->f1 & SELECT) + (bezt->f2 & SELECT) + (bezt->f3 & SELECT) > SELECT) { + if ((v3d->around == V3D_LOCAL) || + ELEM3(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3)) + { BKE_nurb_bezt_calc_normal(nu, bezt, tvec); add_v3_v3(normal, tvec); } else { - if (bezt->f1 & SELECT) { + /* ignore bezt->f2 in this case */ + if (flag & SEL_F1) { sub_v3_v3v3(tvec, bezt->vec[0], bezt->vec[1]); normalize_v3(tvec); add_v3_v3(normal, tvec); } - if (bezt->f2 & SELECT) { - sub_v3_v3v3(tvec, bezt->vec[0], bezt->vec[2]); - normalize_v3(tvec); - add_v3_v3(normal, tvec); - } - if (bezt->f3 & SELECT) { + if (flag & SEL_F3) { sub_v3_v3v3(tvec, bezt->vec[1], bezt->vec[2]); normalize_v3(tvec); add_v3_v3(normal, tvec); @@ -762,6 +777,11 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], BKE_nurb_bezt_calc_plane(nu, bezt, tvec); add_v3_v3(plane, tvec); } + +#undef SEL_F1 +#undef SEL_F2 +#undef SEL_F3 + bezt++; } } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 909ca68cc20..04bccac2a15 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -59,6 +59,7 @@ #include "BKE_context.h" #include "BKE_editmesh.h" #include "BKE_mesh.h" +#include "BKE_tracking.h" #include "RNA_access.h" @@ -133,7 +134,8 @@ bool validSnap(TransInfo *t) bool activeSnap(TransInfo *t) { - return (t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP || (t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP_INVERT; + return ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP) || + ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP_INVERT); } void drawSnapping(const struct bContext *C, TransInfo *t) @@ -1147,7 +1149,7 @@ static void TargetSnapClosest(TransInfo *t) } } -static bool snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], short v2no[3], float obmat[4][4], float timat[3][3], +static bool snapEdge(ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3], float obmat[4][4], float timat[3][3], const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval_fl[2], float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth) { @@ -1234,7 +1236,7 @@ static bool snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], s return retval; } -static bool snapVertex(ARegion *ar, float vco[3], short vno[3], float obmat[4][4], float timat[3][3], +static bool snapVertex(ARegion *ar, const float vco[3], const short vno[3], float obmat[4][4], float timat[3][3], const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval_fl[2], float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth) { @@ -1518,6 +1520,129 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes return retval; } +/* may extend later (for now just snaps to empty center) */ +static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4], + const float ray_start[3], const float ray_normal[3], const float mval[2], + float r_loc[3], float *UNUSED(r_no), float *r_dist_px, float *r_depth) +{ + float imat[4][4]; + float ray_start_local[3], ray_normal_local[3]; + bool retval = false; + + if (ob->transflag & OB_DUPLI) { + return retval; + } + /* for now only vertex supported */ + if (snap_mode != SCE_SNAP_MODE_VERTEX) { + return retval; + } + + invert_m4_m4(imat, obmat); + + copy_v3_v3(ray_start_local, ray_start); + copy_v3_v3(ray_normal_local, ray_normal); + + mul_m4_v3(imat, ray_start_local); + mul_mat3_m4_v3(imat, ray_normal_local); + + switch (snap_mode) { + case SCE_SNAP_MODE_VERTEX: + { + const float zero_co[3] = {0.0f}; + retval |= snapVertex(ar, zero_co, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); + break; + } + default: + break; + } + + return retval; +} + +static bool snapCamera(short snap_mode, ARegion *ar, Scene *scene, Object *object, float obmat[4][4], + const float ray_start[3], const float ray_normal[3], const float mval[2], + float r_loc[3], float *UNUSED(r_no), float *r_dist_px, float *r_depth) +{ + float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4]; + bool retval = false; + MovieClip *clip = BKE_object_movieclip_get(scene, object, false); + MovieTracking *tracking; + float ray_start_local[3], ray_normal_local[3]; + + if (clip == NULL) { + return retval; + } + if (object->transflag & OB_DUPLI) { + return retval; + } + + tracking = &clip->tracking; + + BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat); + + invert_m4_m4(orig_camera_imat, orig_camera_mat); + invert_m4_m4(imat, obmat); + + switch (snap_mode) { + case SCE_SNAP_MODE_VERTEX: + { + MovieTrackingObject *tracking_object; + + for (tracking_object = tracking->objects.first; + tracking_object; + tracking_object = tracking_object->next) + { + ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object); + MovieTrackingTrack *track; + float reconstructed_camera_mat[4][4], + reconstructed_camera_imat[4][4]; + float (*vertex_obmat)[4]; + + copy_v3_v3(ray_start_local, ray_start); + copy_v3_v3(ray_normal_local, ray_normal); + + if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) { + BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, + CFRA, reconstructed_camera_mat); + + invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat); + } + + for (track = tracksbase->first; track; track = track->next) { + float bundle_pos[3]; + + if ((track->flag & TRACK_HAS_BUNDLE) == 0) { + continue; + } + + copy_v3_v3(bundle_pos, track->bundle_pos); + if (tracking_object->flag & TRACKING_OBJECT_CAMERA) { + mul_m4_v3(orig_camera_imat, ray_start_local); + mul_mat3_m4_v3(orig_camera_imat, ray_normal_local); + vertex_obmat = orig_camera_mat; + } + else { + mul_m4_v3(reconstructed_camera_imat, bundle_pos); + mul_m4_v3(imat, ray_start_local); + mul_mat3_m4_v3(imat, ray_normal_local); + vertex_obmat = obmat; + } + + retval |= snapVertex(ar, bundle_pos, NULL, vertex_obmat, NULL, + ray_start, ray_start_local, ray_normal_local, mval, + r_loc, NULL, r_dist_px, r_depth); + } + } + + break; + } + default: + break; + } + + return retval; +} + static bool snapObject(Scene *scene, short snap_mode, ARegion *ar, Object *ob, float obmat[4][4], bool use_obedit, Object **r_ob, float r_obmat[4][4], const float ray_start[3], const float ray_normal[3], const float mval[2], @@ -1545,6 +1670,12 @@ static bool snapObject(Scene *scene, short snap_mode, ARegion *ar, Object *ob, f else if (ob->type == OB_ARMATURE) { retval = snapArmature(snap_mode, ar, ob, ob->data, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist_px, r_depth); } + else if (ob->type == OB_EMPTY) { + retval = snapEmpty(snap_mode, ar, ob, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist_px, r_depth); + } + else if (ob->type == OB_CAMERA) { + retval = snapCamera(snap_mode, ar, scene, ob, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist_px, r_depth); + } if (retval) { if (r_ob) { diff --git a/source/blender/editors/util/crazyspace.c b/source/blender/editors/util/crazyspace.c index bed8aaaddf2..ff65e11f53e 100644 --- a/source/blender/editors/util/crazyspace.c +++ b/source/blender/editors/util/crazyspace.c @@ -51,39 +51,46 @@ #include "ED_util.h" typedef struct { - float *vertexcos; + float (*vertexcos)[3]; BLI_bitmap *vertex_visit; } MappedUserData; -#define TAN_MAKE_VEC(a, b, c) a[0] = b[0] + 0.2f * (b[0] - c[0]); a[1] = b[1] + 0.2f * (b[1] - c[1]); a[2] = b[2] + 0.2f * (b[2] - c[2]) -static void set_crazy_vertex_quat(float *quat, float *v1, float *v2, float *v3, float *def1, float *def2, float *def3) +BLI_INLINE void tan_calc_v3(float a[3], const float b[3], const float c[3]) { - float vecu[3], vecv[3]; + a[0] = b[0] + 0.2f * (b[0] - c[0]); + a[1] = b[1] + 0.2f * (b[1] - c[1]); + a[2] = b[2] + 0.2f * (b[2] - c[2]); +} + +static void set_crazy_vertex_quat( + float r_quat[4], + const float co_1[3], const float co_2[3], const float co_3[3], + const float vd_1[3], const float vd_2[3], const float vd_3[3]) +{ + float vec_u[3], vec_v[3]; float q1[4], q2[4]; - TAN_MAKE_VEC(vecu, v1, v2); - TAN_MAKE_VEC(vecv, v1, v3); - tri_to_quat(q1, v1, vecu, vecv); + tan_calc_v3(vec_u, co_1, co_2); + tan_calc_v3(vec_v, co_1, co_3); + tri_to_quat(q1, co_1, vec_u, vec_v); - TAN_MAKE_VEC(vecu, def1, def2); - TAN_MAKE_VEC(vecv, def1, def3); - tri_to_quat(q2, def1, vecu, vecv); + tan_calc_v3(vec_u, vd_1, vd_2); + tan_calc_v3(vec_v, vd_1, vd_3); + tri_to_quat(q2, vd_1, vec_u, vec_v); - sub_qt_qtqt(quat, q2, q1); + sub_qt_qtqt(r_quat, q2, q1); } -#undef TAN_MAKE_VEC static void make_vertexcos__mapFunc(void *userData, int index, const float co[3], const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) { MappedUserData *mappedData = (MappedUserData *)userData; - float *vec = mappedData->vertexcos; - vec += 3 * index; if (BLI_BITMAP_GET(mappedData->vertex_visit, index) == 0) { - /* we need coord from prototype vertex, not it clones or images, - * suppose they stored in the beginning of vertex array stored in DM */ - copy_v3_v3(vec, co); + /* we need coord from prototype vertex, not from copies, + * assume they stored in the beginning of vertex array stored in DM + * (mirror modifier for eg does this) */ + copy_v3_v3(mappedData->vertexcos[index], co); BLI_BITMAP_SET(mappedData->vertex_visit, index); } } @@ -104,11 +111,11 @@ static int modifiers_disable_subsurf_temporary(Object *ob) } /* disable subsurf temporal, get mapped cos, and enable it */ -float *crazyspace_get_mapped_editverts(Scene *scene, Object *obedit) +float (*crazyspace_get_mapped_editverts(Scene *scene, Object *obedit))[3] { Mesh *me = obedit->data; DerivedMesh *dm; - float *vertexcos; + float (*vertexcos)[3]; int nverts = me->edit_btmesh->bm->totvert; BLI_bitmap *vertex_visit; MappedUserData userData; @@ -122,7 +129,7 @@ float *crazyspace_get_mapped_editverts(Scene *scene, Object *obedit) /* now get the cage */ dm = editbmesh_get_derived_cage(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH); - vertexcos = MEM_callocN(3 * sizeof(float) * nverts, "vertexcos map"); + vertexcos = MEM_callocN(sizeof(*vertexcos) * nverts, "vertexcos map"); vertex_visit = BLI_BITMAP_NEW(nverts, "vertexcos flags"); userData.vertexcos = vertexcos; @@ -139,65 +146,69 @@ float *crazyspace_get_mapped_editverts(Scene *scene, Object *obedit) return vertexcos; } -void crazyspace_set_quats_editmesh(BMEditMesh *em, float *origcos, float *mappedcos, float *quats) +void crazyspace_set_quats_editmesh(BMEditMesh *em, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4]) { - BMVert *v; - BMIter iter, liter; - BMLoop *l; - float *v1, *v2, *v3, *co1, *co2, *co3; - int *vert_table = MEM_callocN(sizeof(int) * em->bm->totvert, "vert_table"); - int index = 0; - - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(v, BM_ELEM_SELECT) || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) - continue; - - BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { - BMLoop *l2 = BM_loop_other_edge_loop(l, v); - - /* retrieve mapped coordinates */ - v1 = mappedcos + 3 * BM_elem_index_get(l->v); - v2 = mappedcos + 3 * BM_elem_index_get(BM_edge_other_vert(l2->e, l->v)); - v3 = mappedcos + 3 * BM_elem_index_get(BM_edge_other_vert(l->e, l->v)); - - co1 = (origcos) ? origcos + 3 * BM_elem_index_get(l->v) : l->v->co; - co2 = (origcos) ? origcos + 3 * BM_elem_index_get(BM_edge_other_vert(l2->e, l->v)) : BM_edge_other_vert(l2->e, l->v)->co; - co3 = (origcos) ? origcos + 3 * BM_elem_index_get(BM_edge_other_vert(l->e, l->v)) : BM_edge_other_vert(l->e, l->v)->co; - - set_crazy_vertex_quat(quats, v1, v2, v3, co1, co2, co3); - quats += 4; - - vert_table[BM_elem_index_get(l->v)] = index + 1; - - index++; - break; /*just do one corner*/ + BMFace *f; + BMIter iter; + int index; + + { + BMVert *v; + BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, index) { + BM_elem_flag_disable(v, BM_ELEM_TAG); + BM_elem_index_set(v, index); /* set_inline */ } + em->bm->elem_index_dirty &= ~BM_VERT; } - index = 0; - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (vert_table[index] != 0) - BM_elem_index_set(v, vert_table[index] - 1); /* set_dirty! */ - else - BM_elem_index_set(v, -1); /* set_dirty! */ - - index++; + BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) { + 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) || BM_elem_flag_test(l_iter->v, BM_ELEM_HIDDEN)) + continue; + + if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) { + const float *co_prev, *co_curr, *co_next; /* orig */ + const float *vd_prev, *vd_curr, *vd_next; /* deform */ + + const int i_prev = BM_elem_index_get(l_iter->prev->v); + const int i_curr = BM_elem_index_get(l_iter->v); + const int i_next = BM_elem_index_get(l_iter->next->v); + + /* retrieve mapped coordinates */ + vd_prev = mappedcos[i_prev]; + vd_curr = mappedcos[i_curr]; + vd_next = mappedcos[i_next]; + + if (origcos) { + co_prev = origcos[i_prev]; + co_curr = origcos[i_curr]; + co_next = origcos[i_next]; + } + else { + co_prev = l_iter->prev->v->co; + co_curr = l_iter->v->co; + co_next = l_iter->next->v->co; + } + + set_crazy_vertex_quat(quats[i_curr], + co_curr, co_next, co_prev, + vd_curr, vd_next, vd_prev); + + BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG); + } + } while ((l_iter = l_iter->next) != l_first); } - em->bm->elem_index_dirty |= BM_VERT; - - MEM_freeN(vert_table); } -/* BMESH_TODO - use MPolys over MFace's */ - -void crazyspace_set_quats_mesh(Mesh *me, float *origcos, float *mappedcos, float *quats) +void crazyspace_set_quats_mesh(Mesh *me, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4]) { int i; MVert *mvert; - MFace *mface; - float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4; + MLoop *mloop; + MPoly *mp; mvert = me->mvert; for (i = 0; i < me->totvert; i++, mvert++) @@ -205,49 +216,48 @@ void crazyspace_set_quats_mesh(Mesh *me, float *origcos, float *mappedcos, float /* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */ mvert = me->mvert; - mface = me->mface; - for (i = 0; i < me->totface; i++, mface++) { - - /* retrieve mapped coordinates */ - v1 = mappedcos + 3 * mface->v1; - v2 = mappedcos + 3 * mface->v2; - v3 = mappedcos + 3 * mface->v3; - - co1 = (origcos) ? origcos + 3 * mface->v1 : mvert[mface->v1].co; - co2 = (origcos) ? origcos + 3 * mface->v2 : mvert[mface->v2].co; - co3 = (origcos) ? origcos + 3 * mface->v3 : mvert[mface->v3].co; - - if ((mvert[mface->v2].flag & ME_VERT_TMP_TAG) == 0) { - set_crazy_vertex_quat(&quats[mface->v2 * 4], co2, co3, co1, v2, v3, v1); - mvert[mface->v2].flag |= ME_VERT_TMP_TAG; - } - - if (mface->v4) { - v4 = mappedcos + 3 * mface->v4; - co4 = (origcos) ? origcos + 3 * mface->v4 : mvert[mface->v4].co; - - if ((mvert[mface->v1].flag & ME_VERT_TMP_TAG) == 0) { - set_crazy_vertex_quat(&quats[mface->v1 * 4], co1, co2, co4, v1, v2, v4); - mvert[mface->v1].flag |= ME_VERT_TMP_TAG; - } - if ((mvert[mface->v3].flag & ME_VERT_TMP_TAG) == 0) { - set_crazy_vertex_quat(&quats[mface->v3 * 4], co3, co4, co2, v3, v4, v2); - mvert[mface->v3].flag |= ME_VERT_TMP_TAG; - } - if ((mvert[mface->v4].flag & ME_VERT_TMP_TAG) == 0) { - set_crazy_vertex_quat(&quats[mface->v4 * 4], co4, co1, co3, v4, v1, v3); - mvert[mface->v4].flag |= ME_VERT_TMP_TAG; - } - } - else { - if ((mvert[mface->v1].flag & ME_VERT_TMP_TAG) == 0) { - set_crazy_vertex_quat(&quats[mface->v1 * 4], co1, co2, co3, v1, v2, v3); - mvert[mface->v1].flag |= ME_VERT_TMP_TAG; - } - if ((mvert[mface->v3].flag & ME_VERT_TMP_TAG) == 0) { - set_crazy_vertex_quat(&quats[mface->v3 * 4], co3, co1, co2, v3, v1, v2); - mvert[mface->v3].flag |= ME_VERT_TMP_TAG; + mp = me->mpoly; + mloop = me->mloop; + + for (i = 0; i < me->totpoly; i++, mp++) { + MLoop *ml_prev, *ml_curr, *ml_next; + int j; + + ml_next = &mloop[mp->loopstart]; + ml_curr = &ml_next[mp->totloop - 1]; + ml_prev = &ml_next[mp->totloop - 2]; + + for (j = 0; j < mp->totloop; j++) { + if ((mvert[ml_curr->v].flag & ME_VERT_TMP_TAG) == 0) { + const float *co_prev, *co_curr, *co_next; /* orig */ + const float *vd_prev, *vd_curr, *vd_next; /* deform */ + + /* retrieve mapped coordinates */ + vd_prev = mappedcos[ml_prev->v]; + vd_curr = mappedcos[ml_curr->v]; + vd_next = mappedcos[ml_next->v]; + + if (origcos) { + co_prev = origcos[ml_prev->v]; + co_curr = origcos[ml_curr->v]; + co_next = origcos[ml_next->v]; + } + else { + co_prev = mvert[ml_prev->v].co; + co_curr = mvert[ml_curr->v].co; + co_next = mvert[ml_next->v].co; + } + + set_crazy_vertex_quat(quats[ml_curr->v], + co_curr, co_next, co_prev, + vd_curr, vd_next, vd_prev); + + mvert[ml_curr->v].flag |= ME_VERT_TMP_TAG; } + + ml_prev = ml_curr; + ml_curr = ml_next; + ml_next++; } } } @@ -260,11 +270,12 @@ int editbmesh_get_first_deform_matrices(Scene *scene, Object *ob, BMEditMesh *em int i, a, numleft = 0, numVerts = 0; int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL; + VirtualModifierData virtualModifierData; modifiers_clearErrors(ob); dm = NULL; - md = modifiers_getVirtualModifierList(ob); + md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* compute the deformation matrices and coordinates for the first * modifiers with on cage editing that are enabled and support computing @@ -314,6 +325,7 @@ int sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**deformma MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); int has_multires = mmd != NULL && mmd->sculptlvl > 0; int numleft = 0; + VirtualModifierData virtualModifierData; if (has_multires) { *deformmats = NULL; @@ -322,7 +334,7 @@ int sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**deformma } dm = NULL; - md = modifiers_getVirtualModifierList(ob); + md = modifiers_getVirtualModifierList(ob, &virtualModifierData); for (; md; md = md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); @@ -373,9 +385,10 @@ void crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[3][3 float (*deformedVerts)[3] = *deformcos; float (*origVerts)[3] = MEM_dupallocN(deformedVerts); - float *quats = NULL; + float (*quats)[4]; int i, deformed = 0; - ModifierData *md = modifiers_getVirtualModifierList(ob); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); Mesh *me = (Mesh *)ob->data; for (; md; md = md->next) { @@ -394,14 +407,14 @@ void crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[3][3 } } - quats = MEM_mallocN(me->totvert * sizeof(float) * 4, "crazy quats"); + quats = MEM_mallocN(me->totvert * sizeof(*quats), "crazy quats"); - crazyspace_set_quats_mesh(me, (float *)origVerts, (float *)deformedVerts, quats); + crazyspace_set_quats_mesh(me, origVerts, deformedVerts, quats); for (i = 0; i < me->totvert; i++) { float qmat[3][3], tmat[3][3]; - quat_to_mat3(qmat, &quats[i * 4]); + quat_to_mat3(qmat, quats[i]); mul_m3_m3m3(tmat, qmat, (*deformmats)[i]); copy_m3_m3((*deformmats)[i], tmat); } diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index a873702b5b8..d20ef0e70e0 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -69,7 +69,7 @@ #define USE_EDBM_LOOPTRIS -void draw_image_cursor(SpaceImage *sima, ARegion *ar) +void draw_image_cursor(ARegion *ar, const float cursor[2]) { float zoom[2], x_fac, y_fac; @@ -80,7 +80,7 @@ void draw_image_cursor(SpaceImage *sima, ARegion *ar) y_fac = zoom[1]; cpack(0xFFFFFF); - glTranslatef(sima->cursor[0], sima->cursor[1], 0.0); + glTranslatef(cursor[0], cursor[1], 0.0); fdrawline(-0.05f * x_fac, 0, 0, 0.05f * y_fac); fdrawline(0, 0.05f * y_fac, 0.05f * x_fac, 0.0f); fdrawline(0.05f * x_fac, 0.0f, 0.0f, -0.05f * y_fac); @@ -108,7 +108,7 @@ void draw_image_cursor(SpaceImage *sima, ARegion *ar) fdrawline(0.0f, -0.020f * y_fac, 0.0f, -0.1f * y_fac); fdrawline(0.0f, 0.1f * y_fac, 0.0f, 0.020f * y_fac); - glTranslatef(-sima->cursor[0], -sima->cursor[1], 0.0); + glTranslatef(-cursor[0], -cursor[1], 0.0); setlinestyle(0); } @@ -158,7 +158,7 @@ static int draw_uvs_dm_shadow(DerivedMesh *dm) /* draw shadow mesh - this is the mesh with the modifier applied */ if (dm && dm->drawUVEdges && CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { - glColor3ub(112, 112, 112); + UI_ThemeColor(TH_UV_SHADOW); dm->drawUVEdges(dm); return 1; } @@ -362,7 +362,7 @@ static void draw_uvs_other(Scene *scene, Object *obedit, Image *curimage) { Base *base; - glColor3ub(96, 96, 96); + UI_ThemeColor(TH_UV_OTHERS); for (base = scene->base.first; base; base = base->next) { Object *ob = base->object; @@ -404,7 +404,7 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob) if (sima->flag & SI_DRAW_OTHER) draw_uvs_other(scene, ob, curimage); - glColor3ub(112, 112, 112); + UI_ThemeColor(TH_UV_SHADOW); if (me->mtpoly) { MPoly *mpoly = me->mpoly; @@ -884,7 +884,7 @@ void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedi draw_uvs_texpaint(sima, scene, obact); if (show_uvedit && !(toolsettings->use_uv_sculpt)) - draw_image_cursor(sima, ar); + draw_image_cursor(ar, sima->cursor); } } diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 0b514e3f6fd..8c299cccbc2 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -3823,6 +3823,12 @@ static void UV_OT_reveal(wmOperatorType *ot) /******************** set 3d cursor operator ********************/ +static int uv_set_2d_cursor_poll(bContext *C) +{ + return ED_operator_uvedit_space_image(C) || + ED_space_image_maskedit_poll(C); +} + static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op) { SpaceImage *sima = CTX_wm_space_image(C); @@ -3858,7 +3864,7 @@ static void UV_OT_cursor_set(wmOperatorType *ot) /* api callbacks */ ot->exec = uv_set_2d_cursor_exec; ot->invoke = uv_set_2d_cursor_invoke; - ot->poll = ED_operator_uvedit_space_image; + ot->poll = uv_set_2d_cursor_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index 7851eebe269..b8a54c56c63 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -33,6 +33,7 @@ #include "BLI_rand.h" #include "BLI_heap.h" #include "BLI_boxpack2d.h" +#include "BLI_convexhull2d.h" #include "ONL_opennl.h" @@ -485,6 +486,36 @@ static void p_chart_uv_translate(PChart *chart, float trans[2]) } } +static void p_chart_uv_transform(PChart *chart, float mat[2][2]) +{ + PVert *v; + + for (v = chart->verts; v; v = v->nextlink) { + mul_v2_m2v2(v->uv, mat, v->uv); + } +} + +static void p_chart_uv_to_array(PChart *chart, float (*points)[2]) +{ + PVert *v; + unsigned int i = 0; + + for (v = chart->verts; v; v = v->nextlink) { + copy_v2_v2(points[i++], v->uv); + } +} + +static void UNUSED_FUNCTION(p_chart_uv_from_array)(PChart *chart, float (*points)[2]) +{ + PVert *v; + unsigned int i = 0; + + for (v = chart->verts; v; v = v->nextlink) { + copy_v2_v2(v->uv, points[i++]); + } +} + + static PBool p_intersect_line_2d_dir(float *v1, float *dir1, float *v2, float *dir2, float *isect) { float lmbda, div; @@ -4441,8 +4472,42 @@ void param_smooth_area(ParamHandle *handle) p_smooth(chart); } } - -void param_pack(ParamHandle *handle, float margin) + +/* don't pack, just rotate (used for better packing) */ +static void param_pack_rotate(ParamHandle *handle) +{ + PChart *chart; + int i; + + PHandle *phandle = (PHandle *)handle; + + for (i = 0; i < phandle->ncharts; i++) { + float (*points)[2]; + float angle; + + chart = phandle->charts[i]; + + if (chart->flag & PCHART_NOPACK) { + continue; + } + + points = MEM_mallocN(sizeof(*points) * chart->nverts, __func__); + + p_chart_uv_to_array(chart, points); + + angle = BLI_convexhull_aabb_fit_points_2d((const float (*)[2])points, chart->nverts); + + MEM_freeN(points); + + if (angle != 0.0f) { + float mat[2][2]; + angle_to_mat2(mat, angle); + p_chart_uv_transform(chart, mat); + } + } +} + +void param_pack(ParamHandle *handle, float margin, bool do_rotate) { /* box packing variables */ BoxPack *boxarray, *box; @@ -4461,6 +4526,11 @@ void param_pack(ParamHandle *handle, float margin) if (phandle->aspx != phandle->aspy) param_scale(handle, 1.0f / phandle->aspx, 1.0f / phandle->aspy); + /* this could be its own function */ + if (do_rotate) { + param_pack_rotate(handle); + } + /* we may not use all these boxes */ boxarray = MEM_mallocN(phandle->ncharts * sizeof(BoxPack), "BoxPack box"); @@ -4513,7 +4583,7 @@ void param_pack(ParamHandle *handle, float margin) } } - BLI_box_pack_2D(boxarray, phandle->ncharts - unpacked, &tot_width, &tot_height); + BLI_box_pack_2d(boxarray, phandle->ncharts - unpacked, &tot_width, &tot_height); if (tot_height > tot_width) scale = 1.0f / tot_height; diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.h b/source/blender/editors/uvedit/uvedit_parametrizer.h index 7127a436570..265577555a6 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.h +++ b/source/blender/editors/uvedit/uvedit_parametrizer.h @@ -99,7 +99,7 @@ void param_smooth_area(ParamHandle *handle); /* Packing */ -void param_pack(ParamHandle *handle, float margin); +void param_pack(ParamHandle *handle, float margin, bool do_rotate); /* Average area for all charts */ diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 3318ae72624..f788c6a772c 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -1718,6 +1718,7 @@ static int stitch_init(bContext *C, wmOperator *op) UvElement *element = ED_uv_element_get(state->element_map, efa, l); int offset1, itmp1 = element - state->element_map->buf; int offset2, itmp2 = ED_uv_element_get(state->element_map, efa, l->next) - state->element_map->buf; + UvEdge *edge; offset1 = map[itmp1]; offset2 = map[itmp2]; @@ -1737,8 +1738,8 @@ static int stitch_init(bContext *C, wmOperator *op) all_edges[counter].uv2 = offset1; } - if (BLI_ghash_haskey(edge_hash, &all_edges[counter])) { - UvEdge *edge = BLI_ghash_lookup(edge_hash, &all_edges[counter]); + edge = BLI_ghash_lookup(edge_hash, &all_edges[counter]); + if (edge) { edge->flag = 0; } else { diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 49505b03a19..87cc42001d6 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -718,6 +718,7 @@ static int pack_islands_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); ParamHandle *handle; bool implicit = true; + bool do_rotate = RNA_boolean_get(op->ptr, "rotate"); if (!uvedit_have_selection(scene, em, implicit)) { return OPERATOR_CANCELLED; @@ -729,7 +730,7 @@ static int pack_islands_exec(bContext *C, wmOperator *op) RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin); handle = construct_param_handle(scene, obedit, em, implicit, 0, 1, 1); - param_pack(handle, scene->toolsettings->uvcalc_margin); + param_pack(handle, scene->toolsettings->uvcalc_margin, do_rotate); param_flush(handle); param_delete(handle); @@ -753,6 +754,7 @@ void UV_OT_pack_islands(wmOperatorType *ot) ot->poll = ED_operator_uvedit; /* properties */ + RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit"); RNA_def_float_factor(ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f); } @@ -1151,7 +1153,7 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel) param_lscm_end(handle); param_average(handle); - param_pack(handle, scene->toolsettings->uvcalc_margin); + param_pack(handle, scene->toolsettings->uvcalc_margin, false); param_flush(handle); diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp index dbf3fa8349e..c61f72295d2 100644 --- a/source/blender/freestyle/intern/application/Controller.cpp +++ b/source/blender/freestyle/intern/application/Controller.cpp @@ -290,6 +290,8 @@ int Controller::LoadMesh(Render *re, SceneRenderLayer *srl) _ListOfModels.push_back("Blender_models"); + _Scene3dBBox = _RootNode->bbox(); + _bboxDiag = (_RootNode->bbox().getMax() - _RootNode->bbox().getMin()).norm(); if (G.debug & G_DEBUG_FREESTYLE) { cout << "Triangles nb : " << _SceneNumFaces << endl; @@ -339,6 +341,7 @@ void Controller::DeleteWingedEdge() // clears the grid _Grid.clear(); + _Scene3dBBox.clear(); _SceneNumFaces = 0; _minEdgeSize = DBL_MAX; } @@ -540,8 +543,8 @@ void Controller::ComputeViewMap() } _Chrono.start(); // Build View Map - _ViewMap = vmBuilder.BuildViewMap(*_winged_edge, _VisibilityAlgo, _EPSILON, _RootNode->bbox(), _SceneNumFaces); - _ViewMap->setScene3dBBox(_RootNode->bbox()); + _ViewMap = vmBuilder.BuildViewMap(*_winged_edge, _VisibilityAlgo, _EPSILON, _Scene3dBBox, _SceneNumFaces); + _ViewMap->setScene3dBBox(_Scene3dBBox); if (G.debug & G_DEBUG_FREESTYLE) { printf("ViewMap edge count : %i\n", _ViewMap->viewedges_size()); diff --git a/source/blender/freestyle/intern/application/Controller.h b/source/blender/freestyle/intern/application/Controller.h index d4537f5f987..f5e50347d0f 100644 --- a/source/blender/freestyle/intern/application/Controller.h +++ b/source/blender/freestyle/intern/application/Controller.h @@ -211,6 +211,7 @@ private: FastGrid _Grid; //HashGrid _Grid; + BBox<Vec3r> _Scene3dBBox; unsigned int _SceneNumFaces; real _minEdgeSize; real _EPSILON; diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp index 8cb44d05b84..7dc218c74df 100644 --- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp +++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp @@ -369,7 +369,7 @@ static void prepare(Main *bmain, Render *re, SceneRenderLayer *srl) if (lineset->flags & FREESTYLE_LINESET_ENABLED) { if (G.debug & G_DEBUG_FREESTYLE) { cout << " " << layer_count+1 << ": " << lineset->name << " - " << - lineset->linestyle->id.name + 2 << endl; + (lineset->linestyle ? (lineset->linestyle->id.name + 2) : "<NULL>") << endl; } Text *text = create_lineset_handler(bmain, srl->name, lineset->name); controller->InsertStyleModule(layer_count, lineset->name, text); @@ -680,9 +680,11 @@ void FRS_paste_active_lineset(FreestyleConfig *config) FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config); if (lineset) { - lineset->linestyle->id.us--; + if (lineset->linestyle) + lineset->linestyle->id.us--; lineset->linestyle = lineset_buffer.linestyle; - lineset->linestyle->id.us++; + if (lineset->linestyle) + lineset->linestyle->id.us++; lineset->flags = lineset_buffer.flags; lineset->selection = lineset_buffer.selection; lineset->qi = lineset_buffer.qi; @@ -711,10 +713,10 @@ void FRS_delete_active_lineset(FreestyleConfig *config) if (lineset) { if (lineset->group) { lineset->group->id.us--; - lineset->group = NULL; } - lineset->linestyle->id.us--; - lineset->linestyle = NULL; + if (lineset->linestyle) { + lineset->linestyle->id.us--; + } BLI_remlink(&config->linesets, lineset); MEM_freeN(lineset); BKE_freestyle_lineset_set_active_index(config, 0); diff --git a/source/blender/freestyle/intern/geometry/BBox.h b/source/blender/freestyle/intern/geometry/BBox.h index 794ceba48e7..c557c2a6368 100644 --- a/source/blender/freestyle/intern/geometry/BBox.h +++ b/source/blender/freestyle/intern/geometry/BBox.h @@ -28,6 +28,10 @@ * \date 22/05/2003 */ +#include <stdlib.h> + +#include "BLI_utildefines.h" + #ifdef WITH_CXX_GUARDEDALLOC #include "MEM_guardedalloc.h" #endif @@ -95,6 +99,7 @@ public: inline BBox<Point>& operator=(const BBox<Point>& b) { + BLI_assert(!b.empty()); _min = b.getMin(); _max = b.getMax(); _empty = false; @@ -103,6 +108,7 @@ public: inline BBox<Point>& operator+=(const BBox<Point>& b) { + BLI_assert(!b.empty()); if (_empty) { _min = b.getMin(); _max = b.getMax(); diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp index 9b915df03d1..869ada0d058 100644 --- a/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp +++ b/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp @@ -44,7 +44,7 @@ PyDoc_STRVAR(ViewEdge_doc, "Class hierarchy: :class:`Interface1D` > :class:`ViewEdge`\n" "\n" "Class defining a ViewEdge. A ViewEdge in an edge of the image graph.\n" -"it connnects two :class:`ViewVertex` objects. It is made by connecting\n" +"it connects two :class:`ViewVertex` objects. It is made by connecting\n" "a set of FEdges.\n" "\n" ".. method:: __init__()\n" diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp index 18815ab6f62..b54ed48edc3 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp @@ -48,7 +48,7 @@ static char MaterialF0D___doc__[] = " evaluation can be ambiguous (in the case of a :class:`TVertex` for\n" " example. This functor tries to remove this ambiguity using the\n" " context offered by the 1D element to which the Interface0DIterator\n" -" belongs to and by arbitrary chosing the material of the face that\n" +" belongs to and by arbitrary choosing the material of the face that\n" " lies on its left when following the 1D element if there are two\n" " different materials on each side of the point. However, there\n" " still can be problematic cases, and the user willing to deal with\n" diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp index 8f7fccb5293..b64f6c06e93 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp @@ -47,7 +47,7 @@ static char ZDiscontinuityF0D___doc__[] = " :class:`Interface0D` pointed by the Interface0DIterator and the\n" " shape that lies behind (occludee). This distance is evaluated in\n" " the camera space and normalized between 0 and 1. Therefore, if no\n" -" oject is occluded by the shape to which the Interface0D belongs to,\n" +" object is occluded by the shape to which the Interface0D belongs to,\n" " 1 is returned.\n" "\n" " :arg it: An Interface0DIterator object.\n" diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp index 5c3dc3eed9f..65fde596e23 100644 --- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp +++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp @@ -52,7 +52,7 @@ static char ZDiscontinuityF1D___doc__[] = " Returns a real value giving the distance between an Interface1D\n" " and the shape that lies behind (occludee). This distance is\n" " evaluated in the camera space and normalized between 0 and 1.\n" -" Therefore, if no oject is occluded by the shape to which the\n" +" Therefore, if no object is occluded by the shape to which the\n" " Interface1D belongs to, 1 is returned.\n" "\n" " :arg inter: An Interface1D object.\n" diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.cpp b/source/blender/freestyle/intern/stroke/StrokeRep.cpp index 2615df0a124..fb6da853e02 100644 --- a/source/blender/freestyle/intern/stroke/StrokeRep.cpp +++ b/source/blender/freestyle/intern/stroke/StrokeRep.cpp @@ -149,7 +149,8 @@ void Strip::createStrip (const vector<StrokeVertex*>& iStrokeVertices) if (dp < 0) userDir = userDir * (-1.0f); stripDir = userDir; - } else { + } + else { ++orientationErrors; } } @@ -207,7 +208,8 @@ void Strip::createStrip (const vector<StrokeVertex*>& iStrokeVertices) if (dp < 0) userDir = userDir * (-1.0f); stripDir = userDir; - } else { + } + else { ++orientationErrors; } } @@ -226,7 +228,8 @@ void Strip::createStrip (const vector<StrokeVertex*>& iStrokeVertices) if (dp < 0) userDir = userDir * (-1.0f); stripDirPrev = userDir; - } else { + } + else { ++orientationErrors; } } @@ -302,7 +305,8 @@ void Strip::createStrip (const vector<StrokeVertex*>& iStrokeVertices) if (dp < 0) userDir = userDir * (-1.0f); stripDirLast = userDir; - } else { + } + else { ++orientationErrors; } } diff --git a/source/blender/freestyle/intern/stroke/StrokeShader.h b/source/blender/freestyle/intern/stroke/StrokeShader.h index 7986a08e303..4657e98be61 100644 --- a/source/blender/freestyle/intern/stroke/StrokeShader.h +++ b/source/blender/freestyle/intern/stroke/StrokeShader.h @@ -63,7 +63,7 @@ class Stroke; * \endcode * Here is a C++ code example of such an iteration: * \code - * for(StrokeInternal::StrokeVertexIterator v = ioStroke.strokeVerticesBegin(), vend = ioStroke.strokeVerticesEnd(); + * for (StrokeInternal::StrokeVertexIterator v = ioStroke.strokeVerticesBegin(), vend = ioStroke.strokeVerticesEnd(); * v != vend; * ++v) * { diff --git a/source/blender/freestyle/intern/stroke/TextStrokeRenderer.cpp b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.cpp index 9d7cb051fdf..ecfb4d4fa25 100644 --- a/source/blender/freestyle/intern/stroke/TextStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.cpp @@ -1,23 +1,22 @@ - -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -/////////////////////////////////////////////////////////////////////////////// +/* + * ***** 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 ***** + */ # include "TextStrokeRenderer.h" # include "Canvas.h" diff --git a/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h index cd56f9d54e3..42402f318ef 100644 --- a/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h +++ b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h @@ -1,3 +1,27 @@ +/* + * ***** 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/stroke/TextStrokeRenderer.h + * \ingroup freestyle + */ + // // Filename : TextStrokeRenderer.h // Author(s) : Stephane Grabli @@ -11,29 +35,8 @@ // /////////////////////////////////////////////////////////////////////////////// - -// -// Copyright (C) : Please refer to the COPYRIGHT file distributed -// with this source distribution. -// -// 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef TEXTSTROKERENDERER_H -# define TEXTSTROKERENDERER_H +#ifndef TEXTSTROKERENDERER_H +#define TEXTSTROKERENDERER_H # include "StrokeRenderer.h" # include "../system/FreestyleConfig.h" diff --git a/source/blender/freestyle/intern/view_map/Functions0D.h b/source/blender/freestyle/intern/view_map/Functions0D.h index 69f6f42e022..e9474191319 100644 --- a/source/blender/freestyle/intern/view_map/Functions0D.h +++ b/source/blender/freestyle/intern/view_map/Functions0D.h @@ -346,7 +346,7 @@ public: // ZDiscontinuity /*! Returns a real giving the distance between and Interface0D and the shape that lies behind (occludee). - * This distance is evaluated in the camera space and normalized between 0 and 1. Therefore, if no oject is occluded + * This distance is evaluated in the camera space and normalized between 0 and 1. Therefore, if no object is occluded * by the shape to which the Interface0D belongs to, 1 is returned. */ class LIB_VIEW_MAP_EXPORT ZDiscontinuityF0D : public UnaryFunction0D<real> @@ -383,7 +383,7 @@ public: /*! Returns the material of the object evaluated at the Interface0D. * This evaluation can be ambiguous (in the case of a TVertex for example. * This functor tries to remove this ambiguity using the context offered by the 1D element to which the - * Interface0DIterator& belongs to and by arbitrary chosing the material of the face that lies on its left when + * Interface0DIterator& belongs to and by arbitrary choosing the material of the face that lies on its left when * following the 1D element if there are two different materials on each side of the point. * However, there still can be problematic cases, and the user willing to deal with this cases in a specific way * should implement its own getMaterial functor. diff --git a/source/blender/freestyle/intern/view_map/Functions1D.h b/source/blender/freestyle/intern/view_map/Functions1D.h index 2d3da151d13..7b10d1b5185 100644 --- a/source/blender/freestyle/intern/view_map/Functions1D.h +++ b/source/blender/freestyle/intern/view_map/Functions1D.h @@ -377,7 +377,7 @@ public: // ZDiscontinuityF1D /*! Returns a real giving the distance between and Interface1D and the shape that lies behind (occludee). - * This distance is evaluated in the camera space and normalized between 0 and 1. Therefore, if no oject is occluded + * This distance is evaluated in the camera space and normalized between 0 and 1. Therefore, if no object is occluded * by the shape to which the Interface1D belongs to, 1 is returned. */ class LIB_VIEW_MAP_EXPORT ZDiscontinuityF1D : public UnaryFunction1D<real> diff --git a/source/blender/freestyle/intern/view_map/SteerableViewMap.h b/source/blender/freestyle/intern/view_map/SteerableViewMap.h index 23681b43c48..581155fa6e8 100644 --- a/source/blender/freestyle/intern/view_map/SteerableViewMap.h +++ b/source/blender/freestyle/intern/view_map/SteerableViewMap.h @@ -89,7 +89,7 @@ public: /*! Returns the number of the SVM to which a FEdge belongs most. * \param id - * The First element of the Id struct of the FEdge we're intersted in. + * The First element of the Id struct of the FEdge we're interested in. */ unsigned getSVMNumber(unsigned id); diff --git a/source/blender/freestyle/intern/view_map/ViewMap.h b/source/blender/freestyle/intern/view_map/ViewMap.h index 987a5bda9b3..0ab089b7d7a 100644 --- a/source/blender/freestyle/intern/view_map/ViewMap.h +++ b/source/blender/freestyle/intern/view_map/ViewMap.h @@ -888,7 +888,7 @@ template<class Traits> class vertex_iterator_base; } // end of namespace ViewEdgeInternal -/*! Class defining a ViewEdge. A ViewEdge in an edge of the image graph. it connnects two ViewVertex. +/*! Class defining a ViewEdge. A ViewEdge in an edge of the image graph. it connects two ViewVertex. * It is made by connecting a set of FEdges. */ class LIB_VIEW_MAP_EXPORT ViewEdge : public Interface1D diff --git a/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h b/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h index 01e93ba77c7..a8c046c4dc1 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h +++ b/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h @@ -232,7 +232,7 @@ public: // operator corresponding to i++, i.e. which returns the value *and then* increments it. // That's why we store the value in a temp. - virtual Self operator++(int) // opérateur correspondant à i++ + virtual Self operator++(int) { Self tmp = *this; increment(); diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp index 81b0f5f8934..702ee9bfea2 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp +++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp @@ -595,7 +595,7 @@ static void computeCumulativeVisibility(ViewMap *ioViewMap, G& grid, real epsilo wFaces.clear(); } - if (iRenderMonitor) { + if (iRenderMonitor && vedges.size()) { stringstream ss; ss << "Freestyle: Visibility computations " << (100 * cnt / vedges.size()) << "%"; iRenderMonitor->setInfo(ss.str()); diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index fca8dcc3392..cc22063a83c 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -46,6 +46,7 @@ struct CustomData; struct DMFlagMat; struct DerivedMesh; struct GHash; +struct GSet; struct GPUVertPointLink; struct PBVH; @@ -175,10 +176,10 @@ GPU_Buffers *GPU_build_grid_buffers(int *grid_indices, int totgrid, GPU_Buffers *GPU_build_bmesh_buffers(int smooth_shading); void GPU_update_bmesh_buffers(GPU_Buffers *buffers, - struct BMesh *bm, - struct GHash *bm_faces, - struct GHash *bm_unique_verts, - struct GHash *bm_other_verts); + struct BMesh *bm, + struct GHash *bm_faces, + struct GSet *bm_unique_verts, + struct GSet *bm_other_verts); void GPU_update_grid_buffers(GPU_Buffers *buffers, struct CCGElem **grids, const struct DMFlagMat *grid_flag_mats, diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 8dd28601d34..1db424b514d 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -61,6 +61,7 @@ int GPU_print_error(const char *str); int GPU_glsl_support(void); int GPU_non_power_of_two_support(void); +int GPU_display_list_support(void); int GPU_color_depth(void); void GPU_code_generate_glsl_lib(void); int GPU_bicubic_bump_support(void); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index c54f937f4a9..384b7cce2ff 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -77,6 +77,8 @@ static int useVBOs = -1; static GPUBufferState GLStates = 0; static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } }; +static ThreadMutex buffer_mutex = BLI_MUTEX_INITIALIZER; + /* stores recently-deleted buffers so that new buffers won't have to * be recreated as often * @@ -203,8 +205,11 @@ void GPU_global_buffer_pool_free_unused(void) } /* get a GPUBuffer of at least `size' bytes; uses one from the buffer - * pool if possible, otherwise creates a new one */ -GPUBuffer *GPU_buffer_alloc(int size) + * pool if possible, otherwise creates a new one + * + * Thread-unsafe version for internal usage only. + */ +static GPUBuffer *gpu_buffer_alloc_intern(int size) { GPUBufferPool *pool; GPUBuffer *buf; @@ -284,10 +289,30 @@ GPUBuffer *GPU_buffer_alloc(int size) return buf; } +/* Same as above, but safe for threading. */ +GPUBuffer *GPU_buffer_alloc(int size) +{ + GPUBuffer *buffer; + + if (size == 0) { + /* Early out, no lock needed in this case. */ + return NULL; + } + + BLI_mutex_lock(&buffer_mutex); + buffer = gpu_buffer_alloc_intern(size); + BLI_mutex_unlock(&buffer_mutex); + + return buffer; +} + /* release a GPUBuffer; does not free the actual buffer or its data, * but rather moves it to the pool of recently-freed buffers for - * possible re-use*/ -void GPU_buffer_free(GPUBuffer *buffer) + * possible re-use + * + * Thread-unsafe version for internal usage only. + */ +static void gpu_buffer_free_intern(GPUBuffer *buffer) { GPUBufferPool *pool; int i; @@ -326,6 +351,19 @@ void GPU_buffer_free(GPUBuffer *buffer) pool->totbuf++; } +/* Same as above, but safe for threading. */ +void GPU_buffer_free(GPUBuffer *buffer) +{ + if (!buffer) { + /* Early output, no need to lock in this case, */ + return; + } + + BLI_mutex_lock(&buffer_mutex); + gpu_buffer_free_intern(buffer); + BLI_mutex_unlock(&buffer_mutex); +} + typedef struct GPUVertPointLink { struct GPUVertPointLink *next; /* -1 means uninitialized */ @@ -510,13 +548,17 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, pool = gpu_get_global_buffer_pool(); + BLI_mutex_lock(&buffer_mutex); + /* alloc a GPUBuffer; fall back to legacy mode on failure */ - if (!(buffer = GPU_buffer_alloc(size))) + if (!(buffer = gpu_buffer_alloc_intern(size))) dm->drawObject->legacy = 1; /* nothing to do for legacy mode */ - if (dm->drawObject->legacy) + if (dm->drawObject->legacy) { + BLI_mutex_unlock(&buffer_mutex); return NULL; + } cur_index_per_mat = MEM_mallocN(sizeof(int) * object->totmaterial, "GPU_buffer_setup.cur_index_per_mat"); @@ -541,7 +583,7 @@ 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(buffer); + gpu_buffer_free_intern(buffer); gpu_buffer_pool_delete_last(pool); buffer = NULL; @@ -549,7 +591,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, * and reallocating the buffer */ if (pool->totbuf > 0) { gpu_buffer_pool_delete_last(pool); - buffer = GPU_buffer_alloc(size); + buffer = gpu_buffer_alloc_intern(size); } /* allocation still failed; fall back @@ -591,6 +633,8 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, MEM_freeN(cur_index_per_mat); + BLI_mutex_unlock(&buffer_mutex); + return buffer; } @@ -1911,6 +1955,7 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, /* Assign index for use in the triangle index buffer */ + /* note: caller must set: bm->elem_index_dirty |= BM_VERT; */ BM_elem_index_set(v, (*v_index)); /* set_dirty! */ (*v_index)++; @@ -1918,19 +1963,19 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, } /* Return the total number of vertices that don't have BM_ELEM_HIDDEN set */ -static int gpu_bmesh_vert_visible_count(GHash *bm_unique_verts, - GHash *bm_other_verts) +static int gpu_bmesh_vert_visible_count(GSet *bm_unique_verts, + GSet *bm_other_verts) { - GHashIterator gh_iter; + GSetIterator gs_iter; int totvert = 0; - GHASH_ITER (gh_iter, bm_unique_verts) { - BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + GSET_ITER (gs_iter, bm_unique_verts) { + BMVert *v = BLI_gsetIterator_getKey(&gs_iter); if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) totvert++; } - GHASH_ITER (gh_iter, bm_other_verts) { - BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + GSET_ITER (gs_iter, bm_other_verts) { + BMVert *v = BLI_gsetIterator_getKey(&gs_iter); if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) totvert++; } @@ -1957,10 +2002,10 @@ static int gpu_bmesh_face_visible_count(GHash *bm_faces) /* Creates a vertex buffer (coordinate, normal, color) and, if smooth * shading, an element index buffer. */ void GPU_update_bmesh_buffers(GPU_Buffers *buffers, - BMesh *bm, - GHash *bm_faces, - GHash *bm_unique_verts, - GHash *bm_other_verts) + BMesh *bm, + GHash *bm_faces, + GSet *bm_unique_verts, + GSet *bm_other_verts) { VertexBufferFormat *vert_data; void *tri_data; @@ -1991,22 +2036,23 @@ void GPU_update_bmesh_buffers(GPU_Buffers *buffers, /* Fill vertex buffer */ vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); if (vert_data) { - GHashIterator gh_iter; int v_index = 0; if (buffers->smooth) { + GSetIterator gs_iter; + /* Vertices get an index assigned for use in the triangle * index buffer */ bm->elem_index_dirty |= BM_VERT; - GHASH_ITER (gh_iter, bm_unique_verts) { - gpu_bmesh_vert_to_buffer_copy(BLI_ghashIterator_getKey(&gh_iter), + GSET_ITER (gs_iter, bm_unique_verts) { + gpu_bmesh_vert_to_buffer_copy(BLI_gsetIterator_getKey(&gs_iter), vert_data, &v_index, NULL, NULL, cd_vert_mask_offset); } - GHASH_ITER (gh_iter, bm_other_verts) { - gpu_bmesh_vert_to_buffer_copy(BLI_ghashIterator_getKey(&gh_iter), + GSET_ITER (gs_iter, bm_other_verts) { + gpu_bmesh_vert_to_buffer_copy(BLI_gsetIterator_getKey(&gs_iter), vert_data, &v_index, NULL, NULL, cd_vert_mask_offset); } @@ -2014,6 +2060,8 @@ void GPU_update_bmesh_buffers(GPU_Buffers *buffers, maxvert = v_index; } else { + GHashIterator gh_iter; + GHASH_ITER (gh_iter, bm_faces) { BMFace *f = BLI_ghashIterator_getKey(&gh_iter); @@ -2045,6 +2093,9 @@ void GPU_update_bmesh_buffers(GPU_Buffers *buffers, } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); + + /* gpu_bmesh_vert_to_buffer_copy sets dirty index values */ + bm->elem_index_dirty |= BM_VERT; } else { /* Memory map failed */ diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index e244c7cf57f..d7919125fee 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -1039,9 +1039,7 @@ static void GPU_nodes_free(ListBase *nodes) { GPUNode *node; - while (nodes->first) { - node = nodes->first; - BLI_remlink(nodes, node); + while ((node = BLI_pophead(nodes))) { GPU_node_free(node); } } diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index e9f9d4a3379..0d25d988df9 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -1216,7 +1216,7 @@ static LinkNode *image_free_queue = NULL; static void gpu_queue_image_for_free(Image *ima) { BLI_lock_thread(LOCK_OPENGL); - BLI_linklist_append(&image_free_queue, ima); + BLI_linklist_prepend(&image_free_queue, ima); BLI_unlock_thread(LOCK_OPENGL); } diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index ea7b169a882..1d08f1f6ea9 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -86,6 +86,7 @@ static struct GPUGlobal { int extdisabled; int colordepth; int npotdisabled; /* ATI 3xx-5xx (and more) chipsets support NPoT partially (== not enough) */ + int dlistsdisabled; /* Legacy ATI driver does not support display lists well */ GPUDeviceType device; GPUOSType os; GPUDriverType driver; @@ -190,6 +191,9 @@ void GPU_extensions_init(void) * Incomplete list http://dri.freedesktop.org/wiki/ATIRadeon * New IDs from MESA's src/gallium/drivers/r300/r300_screen.c */ + /* This list is close enough to those using the legacy driver which + * has a bug with display lists and glVertexAttrib + */ if (strstr(renderer, "R3") || strstr(renderer, "RV3") || strstr(renderer, "R4") || strstr(renderer, "RV4") || strstr(renderer, "RS4") || strstr(renderer, "RC4") || @@ -200,6 +204,7 @@ void GPU_extensions_init(void) strstr(renderer, "RADEON 9")) { GG.npotdisabled = 1; + GG.dlistsdisabled = 1; } } @@ -238,6 +243,11 @@ int GPU_non_power_of_two_support(void) return GLEW_ARB_texture_non_power_of_two; } +int GPU_display_list_support(void) +{ + return !GG.dlistsdisabled; +} + int GPU_color_depth(void) { return GG.colordepth; diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 0ca929da65d..ed7a2f4ede0 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -1127,7 +1127,16 @@ static void do_material_tex(GPUShadeInput *shi) GPU_link(mat, "mtex_nspace_tangent", GPU_attribute(CD_TANGENT, ""), shi->vn, tnor, &newnor); } } + else if (mtex->normapspace == MTEX_NSPACE_OBJECT) { + /* transform normal by object then view matrix */ + GPU_link(mat, "mtex_nspace_object", GPU_builtin(GPU_VIEW_MATRIX), GPU_builtin(GPU_OBJECT_MATRIX), tnor, &newnor); + } + else if (mtex->normapspace == MTEX_NSPACE_WORLD) { + /* transform normal by view matrix */ + GPU_link(mat, "mtex_nspace_world", GPU_builtin(GPU_VIEW_MATRIX), tnor, &newnor); + } else { + /* no transform, normal in camera space */ newnor = tnor; } diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 2aee5b4846a..633112095a7 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1415,6 +1415,16 @@ void mtex_nspace_tangent(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 out outnormal = normalize(outnormal); } +void mtex_nspace_world(mat4 viewmat, vec3 texnormal, out vec3 outnormal) +{ + outnormal = normalize((viewmat*vec4(texnormal, 0.0)).xyz); +} + +void mtex_nspace_object(mat4 viewmat, mat4 obmat, vec3 texnormal, out vec3 outnormal) +{ + outnormal = normalize((viewmat*(obmat*vec4(texnormal, 0.0))).xyz); +} + void mtex_blend_normal(float norfac, vec3 normal, vec3 newnormal, out vec3 outnormal) { outnormal = (1.0 - norfac)*normal + norfac*newnormal; @@ -2087,11 +2097,16 @@ void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out vec4 result) node_bsdf_diffuse(color, 0.0, N, result); } -void node_subsurface_scattering(vec4 color, float roughness, vec3 N, out vec4 result) +void node_subsurface_scattering(vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N, out vec4 result) { node_bsdf_diffuse(color, 0.0, N, result); } +void node_bsdf_hair(vec4 color, float roughnessu, float roughnessv, out vec4 result) +{ + result = color; +} + /* emission */ void node_emission(vec4 color, float strength, vec3 N, out vec4 result) @@ -2119,6 +2134,20 @@ void node_fresnel(float ior, vec3 N, vec3 I, out float result) result = fresnel_dielectric(I, N, (gl_FrontFacing)? eta: 1.0/eta); } +/* gamma */ + +void node_gamma(vec4 col, float gamma, out vec4 outcol) +{ + outcol = col; + + if(col.r > 0.0) + outcol.r = compatible_pow(col.r, gamma); + if(col.g > 0.0) + outcol.g = compatible_pow(col.g, gamma); + if(col.b > 0.0) + outcol.b = compatible_pow(col.b, gamma); +} + /* geometry */ void node_attribute(vec3 attr_uv, out vec4 outcol, out vec3 outvec, out float outf) diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h index 7399b8554aa..64a2bbb72d9 100644 --- a/source/blender/imbuf/IMB_colormanagement.h +++ b/source/blender/imbuf/IMB_colormanagement.h @@ -31,6 +31,12 @@ #ifndef __IMB_COLORMANAGEMENT_H__ #define __IMB_COLORMANAGEMENT_H__ +/** \file blender/imbuf/IMB_colormanagement.h + * \ingroup imbuf + */ + +#include "BLI_sys_types.h" + #define BCM_CONFIG_FILE "config.ocio" struct bContext; @@ -62,19 +68,22 @@ void IMB_colormanagement_check_is_data(struct ImBuf *ibuf, const char *name); void IMB_colormanagement_assign_float_colorspace(struct ImBuf *ibuf, const char *name); void IMB_colormanagement_assign_rect_colorspace(struct ImBuf *ibuf, const char *name); +const char *IMB_colormanagement_get_float_colorspace(struct ImBuf *ibuf); +const char *IMB_colormanagement_get_rect_colorspace(struct ImBuf *ibuf); + /* ** Color space transformation functions ** */ void IMB_colormanagement_transform(float *buffer, int width, int height, int channels, - const char *from_colorspace, const char *to_colorspace, int predivide); + const char *from_colorspace, const char *to_colorspace, bool predivide); void IMB_colormanagement_transform_threaded(float *buffer, int width, int height, int channels, - const char *from_colorspace, const char *to_colorspace, int predivide); + const char *from_colorspace, const char *to_colorspace, bool predivide); void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace); void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], struct ColorSpace *colorspace); -void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4], int predivide, struct ColorSpace *colorspace); +void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4], bool predivide, struct ColorSpace *colorspace); void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], struct ColorSpace *colorspace); -void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, struct ColorSpace *colorspace, int predivide); +void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, struct ColorSpace *colorspace, bool predivide); void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], struct ColorManagedDisplay *display); void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], struct ColorManagedDisplay *display); @@ -88,7 +97,7 @@ void IMB_colormanagement_pixel_to_display_space_v3(float result[3], const float void IMB_colormanagement_imbuf_make_display_space(struct ImBuf *ibuf, const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings); -struct ImBuf *IMB_colormanagement_imbuf_for_write(struct ImBuf *ibuf, int save_as_render, int allocate_result, +struct ImBuf *IMB_colormanagement_imbuf_for_write(struct ImBuf *ibuf, bool save_as_render, bool allocate_result, const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings, struct ImageFormatData *image_format_data); @@ -110,7 +119,7 @@ unsigned char *IMB_display_buffer_acquire_ctx(const struct bContext *C, struct I void IMB_display_buffer_transform_apply(unsigned char *display_buffer, float *linear_buffer, int width, int height, int channels, const struct ColorManagedViewSettings *view_settings, - const struct ColorManagedDisplaySettings *display_settings, int predivide); + const struct ColorManagedDisplaySettings *display_settings, bool predivide); void IMB_display_buffer_release(void *cache_handle); @@ -125,6 +134,10 @@ const char *IMB_colormanagement_display_get_none_name(void); int IMB_colormanagement_view_get_named_index(const char *name); const char *IMB_colormanagement_view_get_indexed_name(int index); +/* ** Look funcrions ** */ +int IMB_colormanagement_look_get_named_index(const char *name); +const char *IMB_colormanagement_look_get_indexed_name(int index); + /* ** Color space functions ** */ int IMB_colormanagement_colorspace_get_named_index(const char *name); const char *IMB_colormanagement_colorspace_get_indexed_name(int index); @@ -135,6 +148,7 @@ void IMB_colormanagment_colorspace_from_ibuf_ftype(struct ColorManagedColorspace /* ** RNA helper functions ** */ void IMB_colormanagement_display_items_add(struct EnumPropertyItem **items, int *totitem); void IMB_colormanagement_view_items_add(struct EnumPropertyItem **items, int *totitem, const char *display_name); +void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items, int *totitem); void IMB_colormanagement_colorspace_items_add(struct EnumPropertyItem **items, int *totitem); /* ** Tile-based buffer management ** */ @@ -142,7 +156,7 @@ void IMB_partial_display_buffer_update(struct ImBuf *ibuf, const float *linear_b int stride, int offset_x, int offset_y, const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings, int xmin, int ymin, int xmax, int ymax, - int update_orig_byte_buffer); + bool update_orig_byte_buffer); void IMB_partial_display_buffer_update_delayed(struct ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax); @@ -154,29 +168,34 @@ void IMB_colormanagement_processor_apply_v4(struct ColormanageProcessor *cm_proc void IMB_colormanagement_processor_apply_v4_predivide(struct ColormanageProcessor *cm_processor, float pixel[4]); void IMB_colormanagement_processor_apply_v3(struct ColormanageProcessor *cm_processor, float pixel[3]); void IMB_colormanagement_processor_apply(struct ColormanageProcessor *cm_processor, float *buffer, int width, int height, - int channels, int predivide); + int channels, bool predivide); void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processor); /* ** OpenGL drawing routines using GLSL for color space transform ** */ +/* Test if GLSL drawing is supported for combination of graphics card and this configuration */ +bool IMB_colormanagement_support_glsl_draw(const struct ColorManagedViewSettings *view_settings, + bool skip_curves); /* Configures GLSL shader for conversion from scene linear to display space */ -int IMB_colormanagement_setup_glsl_draw(const struct ColorManagedViewSettings *view_settings, - const struct ColorManagedDisplaySettings *display_settings, - int predivide); +bool IMB_colormanagement_setup_glsl_draw(const struct ColorManagedViewSettings *view_settings, + const struct ColorManagedDisplaySettings *display_settings, + bool predivide, + bool skip_curves); /* Same as above, but display space conversion happens from a specified space */ -int IMB_colormanagement_setup_glsl_draw_from_space(const struct ColorManagedViewSettings *view_settings, - const struct ColorManagedDisplaySettings *display_settings, - struct ColorSpace *colorspace, - int predivide); +bool IMB_colormanagement_setup_glsl_draw_from_space(const struct ColorManagedViewSettings *view_settings, + const struct ColorManagedDisplaySettings *display_settings, + struct ColorSpace *colorspace, + bool predivide, + bool skip_curves); /* Same as setup_glsl_draw, but color management settings are guessing from a given context */ -int IMB_colormanagement_setup_glsl_draw_ctx(const struct bContext *C, int predivide); +bool IMB_colormanagement_setup_glsl_draw_ctx(const struct bContext *C, bool predivide); /* Same as setup_glsl_draw_from_space, but color management settings are guessing from a given context */ -int IMB_colormanagement_setup_glsl_draw_from_space_ctx(const struct bContext *C, struct ColorSpace *colorspace, int predivide); +bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const struct bContext *C, struct ColorSpace *colorspace, bool predivide); /* Finish GLSL-based display space conversion */ void IMB_colormanagement_finish_glsl_draw(void); /* Configures GLSL shader for conversion from space defined by role to scene linear space */ -int IMB_colormanagement_setup_transform_from_role_glsl(int role, int predivide); +bool IMB_colormanagement_setup_transform_from_role_glsl(int role, bool predivide); /* Finish GLSL-based color space conversion */ void IMB_colormanagement_finish_glsl_transform(void); diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 819026facc6..8c2e79ab7d8 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -51,9 +51,6 @@ * - Endianness issues are dealt with internally. * - File I/O must be done externally. The module uses FILE*'s to * direct input/output. - * - Platform dependency is limited. Some minor patches for - * amiga and Irix are present. A 'posix-compliance-patch' - * provides the interface to windows. * * \section dependencies Dependencies * @@ -72,6 +69,9 @@ #define IM_MAX_SPACE 64 +/* for bool */ +#include "../blenlib/BLI_sys_types.h" + /** * * \attention defined in ??? @@ -146,8 +146,8 @@ struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf1); * * \attention Defined in allocimbuf.c */ -short addzbufImBuf(struct ImBuf *ibuf); -short addzbuffloatImBuf(struct ImBuf *ibuf); +bool addzbufImBuf(struct ImBuf *ibuf); +bool addzbuffloatImBuf(struct ImBuf *ibuf); /** * @@ -500,17 +500,17 @@ void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height, int x1, int y1, int x2, int y2); /* defined in metadata.c */ -int IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *field); +bool IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *field); /* exported for image tools in blender, to quickly allocate 32 bits rect */ -short imb_addrectImBuf(struct ImBuf *ibuf); +bool imb_addrectImBuf(struct ImBuf *ibuf); void imb_freerectImBuf(struct ImBuf *ibuf); -short imb_addrectfloatImBuf(struct ImBuf *ibuf); +bool imb_addrectfloatImBuf(struct ImBuf *ibuf); void imb_freerectfloatImBuf(struct ImBuf *ibuf); void imb_freemipmapImBuf(struct ImBuf *ibuf); -short imb_addtilesImBuf(struct ImBuf *ibuf); +bool imb_addtilesImBuf(struct ImBuf *ibuf); void imb_freetilesImBuf(struct ImBuf *ibuf); /* threaded processors */ diff --git a/source/blender/imbuf/intern/IMB_allocimbuf.h b/source/blender/imbuf/intern/IMB_allocimbuf.h index 047228926ee..02b738cc2cd 100644 --- a/source/blender/imbuf/intern/IMB_allocimbuf.h +++ b/source/blender/imbuf/intern/IMB_allocimbuf.h @@ -35,8 +35,8 @@ struct ImBuf; -short imb_addencodedbufferImBuf(struct ImBuf *ibuf); -short imb_enlargeencodedbufferImBuf(struct ImBuf *ibuf); +bool imb_addencodedbufferImBuf(struct ImBuf *ibuf); +bool imb_enlargeencodedbufferImBuf(struct ImBuf *ibuf); #endif diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h index c372e125a66..17eb4bf6db4 100644 --- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h +++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h @@ -28,10 +28,15 @@ * */ -#ifndef IMB_COLORMANAGEMENT_INTERN_H -#define IMB_COLORMANAGEMENT_INTERN_H +#ifndef __IMB_COLORMANAGEMENT_INTERN_H__ +#define __IMB_COLORMANAGEMENT_INTERN_H__ + +/** \file IMB_colormanagement_intern.h + * \ingroup imbuf + */ #include "DNA_listBase.h" +#include "BLI_sys_types.h" struct OCIO_ConstProcessorRcPtr; struct ImBuf; @@ -48,8 +53,8 @@ typedef struct ColorSpace { struct OCIO_ConstProcessorRcPtr *to_scene_linear; struct OCIO_ConstProcessorRcPtr *from_scene_linear; - int is_invertible; - int is_data; + bool is_invertible; + bool is_data; } ColorSpace; typedef struct ColorManagedDisplay { @@ -68,6 +73,14 @@ typedef struct ColorManagedView { char name[MAX_COLORSPACE_NAME]; } ColorManagedView; +typedef struct ColorManagedLook { + struct ColorManagedLook *next, *prev; + int index; + char name[MAX_COLORSPACE_NAME]; + char process_space[MAX_COLORSPACE_NAME]; + bool is_noop; +} ColorManagedLook; + /* ** Initialization / De-initialization ** */ void colormanagement_init(void); @@ -87,14 +100,18 @@ struct ColorManagedView *colormanage_view_add(const char *name); struct ColorManagedView *colormanage_view_get_indexed(int index); struct ColorManagedView *colormanage_view_get_named(const char *name); -struct ColorSpace *colormanage_colorspace_add(const char *name, const char *description, int is_invertible, int is_data); +struct ColorSpace *colormanage_colorspace_add(const char *name, const char *description, bool is_invertible, bool is_data); struct ColorSpace *colormanage_colorspace_get_named(const char *name); struct ColorSpace *colormanage_colorspace_get_roled(int role); struct ColorSpace *colormanage_colorspace_get_indexed(int index); +struct ColorManagedLook *colormanage_look_add(const char *name, const char *process_space, bool is_noop); +struct ColorManagedLook *colormanage_look_get_named(const char *name); +struct ColorManagedLook *colormanage_look_get_indexed(int index); + void colorspace_set_default_role(char *colorspace, int size, int role); void colormanage_imbuf_set_default_spaces(struct ImBuf *ibuf); void colormanage_imbuf_make_linear(struct ImBuf *ibuf, const char *from_colorspace); -#endif /* IMB_COLORMANAGEMENT_INTERN_H */ +#endif /* __IMB_COLORMANAGEMENT_INTERN_H__ */ diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h index 154941c5c09..3c8b29cf68a 100644 --- a/source/blender/imbuf/intern/IMB_filetype.h +++ b/source/blender/imbuf/intern/IMB_filetype.h @@ -94,7 +94,6 @@ int imb_savebmp(struct ImBuf *ibuf, const char *name, int flags); /* cocoa */ struct ImBuf *imb_cocoaLoadImage(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]); -short imb_cocoaSaveImage(struct ImBuf *ibuf, const char *name, int flags); /* cineon */ int imb_save_cineon(struct ImBuf *buf, const char *name, int flags); diff --git a/source/blender/imbuf/intern/IMB_indexer.h b/source/blender/imbuf/intern/IMB_indexer.h index 96f7a68d669..6173ffa9b78 100644 --- a/source/blender/imbuf/intern/IMB_indexer.h +++ b/source/blender/imbuf/intern/IMB_indexer.h @@ -25,6 +25,10 @@ #ifndef __IMB_INDEXER_H__ #define __IMB_INDEXER_H__ +/** \file IMB_indexer.h + * \ingroup imbuf + */ + #ifdef WIN32 # include <io.h> #endif diff --git a/source/blender/imbuf/intern/IMB_metadata.h b/source/blender/imbuf/intern/IMB_metadata.h index f731fd69620..a717764b44f 100644 --- a/source/blender/imbuf/intern/IMB_metadata.h +++ b/source/blender/imbuf/intern/IMB_metadata.h @@ -62,7 +62,7 @@ void IMB_metadata_free(struct ImBuf *img); * \param len - length of value buffer allocated by user. * \return - 1 (true) if ImageInfo present and value for the key found, 0 (false) otherwise */ -int IMB_metadata_get_field(struct ImBuf *img, const char *key, char *value, const size_t len); +bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *value, const size_t len); /** set user data in the ImMetaData struct, which has to be allocated with IMB_metadata_create * before calling this function. @@ -71,13 +71,13 @@ int IMB_metadata_get_field(struct ImBuf *img, const char *key, char *value, cons * \param value - the data to be written to the field. zero terminated string * \return - 1 (true) if ImageInfo present, 0 (false) otherwise */ -int IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value); +bool IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value); /** delete the key/field par in the ImMetaData struct. * \param img - the ImBuf that contains the image data * \param key - the key of the field * \return - 1 (true) if delete the key/field, 0 (false) otherwise */ -int IMB_metadata_del_field(struct ImBuf *img, const char *key); +bool IMB_metadata_del_field(struct ImBuf *img, const char *key); #endif /* __IMB_METADATA_H__ */ diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index ca0b26fa4b7..fb7033e1362 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -48,6 +48,8 @@ #include "MEM_guardedalloc.h" #include "MEM_CacheLimiterC-Api.h" +#include "BLI_utildefines.h" + void imb_freemipmapImBuf(ImBuf *ibuf) { int a; @@ -191,46 +193,48 @@ ImBuf *IMB_makeSingleUser(ImBuf *ibuf) return rval; } -short addzbufImBuf(ImBuf *ibuf) +bool addzbufImBuf(ImBuf *ibuf) { - int size; + size_t size; - if (ibuf == NULL) return FALSE; + if (ibuf == NULL) return false; IMB_freezbufImBuf(ibuf); - size = ibuf->x * ibuf->y * sizeof(unsigned int); - if ((ibuf->zbuf = MEM_mapallocN(size, "addzbufImBuf"))) { + size = (size_t)(ibuf->x * ibuf->y) * sizeof(unsigned int); + + if ((ibuf->zbuf = MEM_mapallocN(size, __func__))) { ibuf->mall |= IB_zbuf; ibuf->flags |= IB_zbuf; - return TRUE; + return true; } - return FALSE; + return false; } -short addzbuffloatImBuf(ImBuf *ibuf) +bool addzbuffloatImBuf(ImBuf *ibuf) { - int size; + size_t size; - if (ibuf == NULL) return FALSE; + if (ibuf == NULL) return false; IMB_freezbuffloatImBuf(ibuf); - size = ibuf->x * ibuf->y * sizeof(float); - if ((ibuf->zbuf_float = MEM_mapallocN(size, "addzbuffloatImBuf"))) { + size = (size_t)(ibuf->x * ibuf->y) * sizeof(float); + + if ((ibuf->zbuf_float = MEM_mapallocN(size, __func__))) { ibuf->mall |= IB_zbuffloat; ibuf->flags |= IB_zbuffloat; - return TRUE; + return true; } - return FALSE; + return false; } -short imb_addencodedbufferImBuf(ImBuf *ibuf) +bool imb_addencodedbufferImBuf(ImBuf *ibuf) { - if (ibuf == NULL) return FALSE; + if (ibuf == NULL) return false; freeencodedbufferImBuf(ibuf); @@ -239,33 +243,33 @@ short imb_addencodedbufferImBuf(ImBuf *ibuf) ibuf->encodedsize = 0; - if ((ibuf->encodedbuffer = MEM_mallocN(ibuf->encodedbuffersize, "addencodedbufferImBuf"))) { + if ((ibuf->encodedbuffer = MEM_mallocN(ibuf->encodedbuffersize, __func__))) { ibuf->mall |= IB_mem; ibuf->flags |= IB_mem; - return TRUE; + return true; } - return FALSE; + return false; } -short imb_enlargeencodedbufferImBuf(ImBuf *ibuf) +bool imb_enlargeencodedbufferImBuf(ImBuf *ibuf) { unsigned int newsize, encodedsize; void *newbuffer; - if (ibuf == NULL) return FALSE; + if (ibuf == NULL) return false; if (ibuf->encodedbuffersize < ibuf->encodedsize) { - printf("imb_enlargeencodedbufferImBuf: error in parameters\n"); - return FALSE; + printf("%s: error in parameters\n", __func__); + return false; } newsize = 2 * ibuf->encodedbuffersize; if (newsize < 10000) newsize = 10000; - newbuffer = MEM_mallocN(newsize, "enlargeencodedbufferImBuf"); - if (newbuffer == NULL) return FALSE; + newbuffer = MEM_mallocN(newsize, __func__); + if (newbuffer == NULL) return false; if (ibuf->encodedbuffer) { memcpy(newbuffer, ibuf->encodedbuffer, ibuf->encodedsize); @@ -284,59 +288,61 @@ short imb_enlargeencodedbufferImBuf(ImBuf *ibuf) ibuf->mall |= IB_mem; ibuf->flags |= IB_mem; - return TRUE; + return true; } -short imb_addrectfloatImBuf(ImBuf *ibuf) +bool imb_addrectfloatImBuf(ImBuf *ibuf) { - int size; + size_t size; - if (ibuf == NULL) return FALSE; + if (ibuf == NULL) return false; if (ibuf->rect_float) imb_freerectfloatImBuf(ibuf); /* frees mipmap too, hrm */ - size = ibuf->x * ibuf->y; - size = size * 4 * sizeof(float); + size = (size_t)(ibuf->x * ibuf->y) * sizeof(float[4]); + ibuf->channels = 4; - - if ((ibuf->rect_float = MEM_mapallocN(size, "imb_addrectfloatImBuf"))) { + if ((ibuf->rect_float = MEM_mapallocN(size, __func__))) { ibuf->mall |= IB_rectfloat; ibuf->flags |= IB_rectfloat; - return TRUE; + return true; } - return FALSE; + return false; } /* question; why also add zbuf? */ -short imb_addrectImBuf(ImBuf *ibuf) +bool imb_addrectImBuf(ImBuf *ibuf) { - int size; + size_t size; - if (ibuf == NULL) return FALSE; + if (ibuf == NULL) return false; /* don't call imb_freerectImBuf, it frees mipmaps, this call is used only too give float buffers display */ if (ibuf->rect && (ibuf->mall & IB_rect)) MEM_freeN(ibuf->rect); ibuf->rect = NULL; - size = ibuf->x * ibuf->y; - size = size * sizeof(unsigned int); + size = (size_t)(ibuf->x * ibuf->y) * sizeof(unsigned int); - if ((ibuf->rect = MEM_mapallocN(size, "imb_addrectImBuf"))) { + if ((ibuf->rect = MEM_mapallocN(size, __func__))) { ibuf->mall |= IB_rect; ibuf->flags |= IB_rect; - if (ibuf->planes > 32) return (addzbufImBuf(ibuf)); - else return TRUE; + if (ibuf->planes > 32) { + return (addzbufImBuf(ibuf)); + } + else { + return true; + } } - return FALSE; + return false; } -short imb_addtilesImBuf(ImBuf *ibuf) +bool imb_addtilesImBuf(ImBuf *ibuf) { - if (ibuf == NULL) return FALSE; + if (ibuf == NULL) return false; if (!ibuf->tiles) if ((ibuf->tiles = MEM_callocN(sizeof(unsigned int *) * ibuf->xtiles * ibuf->ytiles, "imb_tiles"))) @@ -360,28 +366,28 @@ ImBuf *IMB_allocImBuf(unsigned int x, unsigned int y, uchar planes, unsigned int ibuf->ppm[0] = ibuf->ppm[1] = IMB_DPI_DEFAULT / 0.0254f; /* IMB_DPI_DEFAULT -> pixels-per-meter */ if (flags & IB_rect) { - if (imb_addrectImBuf(ibuf) == FALSE) { + if (imb_addrectImBuf(ibuf) == false) { IMB_freeImBuf(ibuf); return NULL; } } if (flags & IB_rectfloat) { - if (imb_addrectfloatImBuf(ibuf) == FALSE) { + if (imb_addrectfloatImBuf(ibuf) == false) { IMB_freeImBuf(ibuf); return NULL; } } if (flags & IB_zbuf) { - if (addzbufImBuf(ibuf) == FALSE) { + if (addzbufImBuf(ibuf) == false) { IMB_freeImBuf(ibuf); return NULL; } } if (flags & IB_zbuffloat) { - if (addzbuffloatImBuf(ibuf) == FALSE) { + if (addzbuffloatImBuf(ibuf) == false) { IMB_freeImBuf(ibuf); return NULL; } @@ -420,7 +426,7 @@ ImBuf *IMB_dupImBuf(ImBuf *ibuf1) if (ibuf1->encodedbuffer) { ibuf2->encodedbuffersize = ibuf1->encodedbuffersize; - if (imb_addencodedbufferImBuf(ibuf2) == FALSE) { + if (imb_addencodedbufferImBuf(ibuf2) == false) { IMB_freeImBuf(ibuf2); return NULL; } diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c index eb3cfc3ade3..dabeec74a62 100644 --- a/source/blender/imbuf/intern/bmp.c +++ b/source/blender/imbuf/intern/bmp.c @@ -273,7 +273,7 @@ int imb_savebmp(struct ImBuf *ibuf, const char *name, int flags) if (!ofile) return 0; putShortLSB(19778, ofile); /* "BM" */ - putIntLSB(0, ofile); /* This can be 0 for BI_RGB bitmaps */ + putIntLSB(bytesize + BMP_FILEHEADER_SIZE + sizeof(infoheader), ofile); /* Total file size */ putShortLSB(0, ofile); /* Res1 */ putShortLSB(0, ofile); /* Res2 */ putIntLSB(BMP_FILEHEADER_SIZE + sizeof(infoheader), ofile); @@ -284,7 +284,7 @@ int imb_savebmp(struct ImBuf *ibuf, const char *name, int flags) putShortLSB(1, ofile); putShortLSB(24, ofile); putIntLSB(0, ofile); - putIntLSB(bytesize + BMP_FILEHEADER_SIZE + sizeof(infoheader), ofile); + putIntLSB(bytesize, ofile); putIntLSB((int)(ibuf->ppm[0] + 0.5), ofile); putIntLSB((int)(ibuf->ppm[1] + 0.5), ofile); putIntLSB(0, ofile); diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 0167eaccef0..366c2922739 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -28,6 +28,10 @@ * */ +/** \file blender/imbuf/intern/colormanagement.c + * \ingroup imbuf + */ + #include "IMB_colormanagement.h" #include "IMB_colormanagement_intern.h" @@ -81,13 +85,15 @@ static char global_role_default_byte[MAX_COLORSPACE_NAME]; static char global_role_default_float[MAX_COLORSPACE_NAME]; static char global_role_default_sequencer[MAX_COLORSPACE_NAME]; -static ListBase global_colorspaces = {NULL}; -static ListBase global_displays = {NULL}; -static ListBase global_views = {NULL}; +static ListBase global_colorspaces = {NULL, NULL}; +static ListBase global_displays = {NULL, NULL}; +static ListBase global_views = {NULL, NULL}; +static ListBase global_looks = {NULL, NULL}; static int global_tot_colorspace = 0; static int global_tot_display = 0; static int global_tot_view = 0; +static int global_tot_looks = 0; /* lock used by pre-cached processors getters, so processor wouldn't * be created several times @@ -99,7 +105,7 @@ static pthread_mutex_t processor_lock = BLI_MUTEX_INITIALIZER; typedef struct ColormanageProcessor { OCIO_ConstProcessorRcPtr *processor; CurveMapping *curve_mapping; - int is_data_result; + bool is_data_result; } ColormanageProcessor; static struct global_glsl_state { @@ -107,6 +113,7 @@ static struct global_glsl_state { OCIO_ConstProcessorRcPtr *processor; /* Settings of processor for comparison. */ + char look[MAX_COLORSPACE_NAME]; char view[MAX_COLORSPACE_NAME]; char display[MAX_COLORSPACE_NAME]; char input[MAX_COLORSPACE_NAME]; @@ -185,9 +192,11 @@ static struct global_glsl_state { */ typedef struct ColormanageCacheViewSettings { int flag; + int look; int view; float exposure; float gamma; + float dither; CurveMapping *curve_mapping; } ColormanageCacheViewSettings; @@ -202,8 +211,10 @@ typedef struct ColormanageCacheKey { typedef struct ColormnaageCacheData { int flag; /* view flags of cached buffer */ + int look; /* Additional artistics transform */ float exposure; /* exposure value cached buffer is calculated with */ float gamma; /* gamma value cached buffer is calculated with */ + float dither; /* dither value cached buffer is calculated with */ CurveMapping *curve_mapping; /* curve mapping used for cached buffer */ int curve_mapping_timestamp; /* time stamp of curve mapping used for cached buffer */ } ColormnaageCacheData; @@ -282,14 +293,18 @@ static void colormanage_cachedata_set(ImBuf *ibuf, ColormnaageCacheData *data) ibuf->colormanage_cache->data = data; } -static void colormanage_view_settings_to_cache(ColormanageCacheViewSettings *cache_view_settings, +static void colormanage_view_settings_to_cache(ImBuf *ibuf, + ColormanageCacheViewSettings *cache_view_settings, const ColorManagedViewSettings *view_settings) { + int look = IMB_colormanagement_look_get_named_index(view_settings->look); int view = IMB_colormanagement_view_get_named_index(view_settings->view_transform); + cache_view_settings->look = look; cache_view_settings->view = view; cache_view_settings->exposure = view_settings->exposure; cache_view_settings->gamma = view_settings->gamma; + cache_view_settings->dither = ibuf->dither; cache_view_settings->flag = view_settings->flag; cache_view_settings->curve_mapping = view_settings->curve_mapping; } @@ -364,8 +379,10 @@ static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheV */ cache_data = colormanage_cachedata_get(cache_ibuf); - if (cache_data->exposure != view_settings->exposure || + if (cache_data->look != view_settings->look || + cache_data->exposure != view_settings->exposure || cache_data->gamma != view_settings->gamma || + cache_data->dither != view_settings->dither || cache_data->flag != view_settings->flag || cache_data->curve_mapping != curve_mapping || cache_data->curve_mapping_timestamp != curve_mapping_timestamp) @@ -409,8 +426,10 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting /* store data which is needed to check whether cached buffer could be used for color managed display settings */ cache_data = MEM_callocN(sizeof(ColormnaageCacheData), "color manage cache imbuf data"); + cache_data->look = view_settings->look; cache_data->exposure = view_settings->exposure; cache_data->gamma = view_settings->gamma; + cache_data->dither = view_settings->dither; cache_data->flag = view_settings->flag; cache_data->curve_mapping = curve_mapping; cache_data->curve_mapping_timestamp = curve_mapping_timestamp; @@ -454,7 +473,8 @@ static void colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config, static void colormanage_load_config(OCIO_ConstConfigRcPtr *config) { - int tot_colorspace, tot_display, tot_display_view, index, viewindex, viewindex2; + int tot_colorspace, tot_display, tot_display_view, tot_looks; + int index, viewindex, viewindex2; const char *name; /* get roles */ @@ -470,7 +490,7 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config) for (index = 0 ; index < tot_colorspace; index++) { OCIO_ConstColorSpaceRcPtr *ocio_colorspace; const char *description; - int is_invertible, is_data; + bool is_invertible, is_data; name = OCIO_configGetColorSpaceNameByIndex(config, index); @@ -519,6 +539,21 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config) } global_tot_display = tot_display; + + /* load looks */ + tot_looks = OCIO_configGetNumLooks(config); + colormanage_look_add("None", "", true); + for (index = 0; index < tot_looks; index++) { + OCIO_ConstLookRcPtr *ocio_look; + const char *process_space; + + name = OCIO_configGetLookNameByIndex(config, index); + ocio_look = OCIO_configGetLook(config, name); + process_space = OCIO_lookGetProcessSpace(ocio_look); + OCIO_lookRelease(ocio_look); + + colormanage_look_add(name, process_space, false); + } } static void colormanage_free_config(void) @@ -566,6 +601,9 @@ static void colormanage_free_config(void) /* free views */ BLI_freelistN(&global_views); + /* free looks */ + BLI_freelistN(&global_looks); + OCIO_exit(); } @@ -705,7 +743,8 @@ static ColorSpace *display_transform_get_colorspace(const ColorManagedViewSettin return NULL; } -static OCIO_ConstProcessorRcPtr *create_display_buffer_processor(const char *view_transform, +static OCIO_ConstProcessorRcPtr *create_display_buffer_processor(const char *look, + const char *view_transform, const char *display, float exposure, float gamma, const char *from_colorspace) @@ -713,6 +752,7 @@ static OCIO_ConstProcessorRcPtr *create_display_buffer_processor(const char *vie OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig(); OCIO_DisplayTransformRcPtr *dt; OCIO_ConstProcessorRcPtr *processor; + ColorManagedLook *look_descr = colormanage_look_get_named(look); dt = OCIO_createDisplayTransform(); @@ -720,6 +760,11 @@ static OCIO_ConstProcessorRcPtr *create_display_buffer_processor(const char *vie OCIO_displayTransformSetView(dt, view_transform); OCIO_displayTransformSetDisplay(dt, display); + if (look_descr->is_noop == false) { + OCIO_displayTransformSetLooksOverrideEnabled(dt, true); + OCIO_displayTransformSetLooksOverride(dt, look); + } + /* fstop exposure control */ if (exposure != 0.0f) { OCIO_MatrixTransformRcPtr *mt; @@ -871,6 +916,7 @@ static void init_default_view_settings(const ColorManagedDisplaySettings *displa else view_settings->view_transform[0] = '\0'; + BLI_strncpy(view_settings->look, "None", sizeof(view_settings->look)); view_settings->flag = 0; view_settings->gamma = 1.0f; view_settings->exposure = 0.0f; @@ -923,7 +969,7 @@ void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace) imb_freerectImBuf(ibuf); IMB_colormanagement_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - from_colorspace, to_colorspace, TRUE); + from_colorspace, to_colorspace, true); } } @@ -953,6 +999,7 @@ static void colormanage_check_view_settings(ColorManagedDisplaySettings *display { ColorManagedDisplay *display; ColorManagedView *default_view = NULL; + ColorManagedLook *default_look = (ColorManagedLook *) global_looks.first; if (view_settings->view_transform[0] == '\0') { display = colormanage_display_get_named(display_settings->display_device); @@ -981,6 +1028,19 @@ static void colormanage_check_view_settings(ColorManagedDisplaySettings *display } } + if (view_settings->look[0] == '\0') { + BLI_strncpy(view_settings->look, default_look->name, sizeof(view_settings->look)); + } + else { + ColorManagedLook *look = colormanage_look_get_named(view_settings->look); + if (look == NULL) { + printf("Color management: %s look \"%s\" not found, setting default \"%s\".\n", + what, view_settings->look, default_look->name); + + BLI_strncpy(view_settings->look, default_look->name, sizeof(view_settings->look)); + } + } + /* OCIO_TODO: move to do_versions() */ if (view_settings->exposure == 0.0f && view_settings->gamma == 0.0f) { view_settings->exposure = 0.0f; @@ -1134,6 +1194,21 @@ void IMB_colormanagement_assign_rect_colorspace(ImBuf *ibuf, const char *name) ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA; } +const char *IMB_colormanagement_get_float_colorspace(ImBuf *ibuf) +{ + if (ibuf->float_colorspace) { + return ibuf->float_colorspace->name; + } + else { + return IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); + } +} + +const char *IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf) +{ + return ibuf->rect_colorspace->name; +} + /*********************** Threaded display buffer transform routines *************************/ typedef struct DisplayBufferThread { @@ -1151,7 +1226,7 @@ typedef struct DisplayBufferThread { int channels; float dither; - int is_data; + bool is_data; const char *byte_colorspace; const char *float_colorspace; @@ -1180,7 +1255,7 @@ static void display_buffer_init_handle(void *handle_v, int start_line, int tot_l int channels = ibuf->channels; float dither = ibuf->dither; - int is_data = ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA; + bool is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0; int offset = channels * start_line * ibuf->x; int display_buffer_byte_offset = DISPLAY_BUFFER_CHANNELS * start_line * ibuf->x; @@ -1224,8 +1299,8 @@ static float *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle int buffer_size = channels * width * height; - int is_data = handle->is_data; - int is_data_display = handle->cm_processor->is_data_result; + bool is_data = handle->is_data; + bool is_data_display = handle->cm_processor->is_data_result; linear_buffer = MEM_callocN(buffer_size * sizeof(float), "color conversion linear buffer"); @@ -1258,7 +1333,7 @@ static float *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle if (!is_data && !is_data_display) { /* convert float buffer to scene linear space */ IMB_colormanagement_transform(linear_buffer, width, height, channels, - from_colorspace, to_colorspace, FALSE); + from_colorspace, to_colorspace, false); } *is_straight_alpha = true; @@ -1277,7 +1352,7 @@ static float *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle if (!is_data && !is_data_display) { IMB_colormanagement_transform(linear_buffer, width, height, channels, - from_colorspace, to_colorspace, TRUE); + from_colorspace, to_colorspace, true); } *is_straight_alpha = false; @@ -1310,7 +1385,7 @@ static void *do_display_buffer_apply_thread(void *handle_v) int width = handle->width; int height = handle->tot_line; float dither = handle->dither; - int is_data = handle->is_data; + bool is_data = handle->is_data; if (cm_processor == NULL) { if (display_buffer_byte) { @@ -1403,8 +1478,8 @@ static void display_buffer_apply_threaded(ImBuf *ibuf, float *buffer, unsigned c display_buffer_init_handle, do_display_buffer_apply_thread); } -static int is_ibuf_rect_in_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings) +static bool is_ibuf_rect_in_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, + const ColorManagedDisplaySettings *display_settings) { if ((view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) == 0 && view_settings->exposure == 0.0f && @@ -1414,10 +1489,10 @@ static int is_ibuf_rect_in_display_space(ImBuf *ibuf, const ColorManagedViewSett const char *to_colorspace = display_transform_get_colorspace_name(view_settings, display_settings); if (to_colorspace && !strcmp(from_colorspace, to_colorspace)) - return TRUE; + return true; } - return FALSE; + return false; } static void colormanage_display_buffer_process_ex(ImBuf *ibuf, float *display_buffer, unsigned char *display_buffer_byte, @@ -1425,7 +1500,7 @@ static void colormanage_display_buffer_process_ex(ImBuf *ibuf, float *display_bu const ColorManagedDisplaySettings *display_settings) { ColormanageProcessor *cm_processor = NULL; - int skip_transform = FALSE; + bool skip_transform = false; /* if we're going to transform byte buffer, check whether transformation would * happen to the same color space as byte buffer itself is @@ -1436,7 +1511,7 @@ static void colormanage_display_buffer_process_ex(ImBuf *ibuf, float *display_bu skip_transform = is_ibuf_rect_in_display_space(ibuf, view_settings, display_settings); } - if (skip_transform == FALSE) + if (skip_transform == false) cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings); display_buffer_apply_threaded(ibuf, ibuf->rect_float, (unsigned char *) ibuf->rect, @@ -1462,7 +1537,7 @@ typedef struct ProcessorTransformThread { int start_line; int tot_line; int channels; - int predivide; + bool predivide; } ProcessorTransformThread; typedef struct ProcessorTransformInit { @@ -1471,7 +1546,7 @@ typedef struct ProcessorTransformInit { int width; int height; int channels; - int predivide; + bool predivide; } ProcessorTransformInitData; static void processor_transform_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v) @@ -1481,7 +1556,7 @@ static void processor_transform_init_handle(void *handle_v, int start_line, int int channels = init_data->channels; int width = init_data->width; - int predivide = init_data->predivide; + bool predivide = init_data->predivide; int offset = channels * start_line * width; @@ -1507,7 +1582,7 @@ static void *do_processor_transform_thread(void *handle_v) int channels = handle->channels; int width = handle->width; int height = handle->tot_line; - int predivide = handle->predivide; + bool predivide = handle->predivide; IMB_colormanagement_processor_apply(handle->cm_processor, buffer, width, height, channels, predivide); @@ -1515,7 +1590,7 @@ static void *do_processor_transform_thread(void *handle_v) } static void processor_transform_apply_threaded(float *buffer, int width, int height, int channels, - ColormanageProcessor *cm_processor, int predivide) + ColormanageProcessor *cm_processor, bool predivide) { ProcessorTransformInitData init_data; @@ -1534,7 +1609,7 @@ static void processor_transform_apply_threaded(float *buffer, int width, int hei /* convert the whole buffer from specified by name color space to another - internal implementation */ static void colormanagement_transform_ex(float *buffer, int width, int height, int channels, const char *from_colorspace, - const char *to_colorspace, int predivide, int do_threaded) + const char *to_colorspace, bool predivide, bool do_threaded) { ColormanageProcessor *cm_processor; @@ -1561,18 +1636,18 @@ static void colormanagement_transform_ex(float *buffer, int width, int height, i /* convert the whole buffer from specified by name color space to another */ void IMB_colormanagement_transform(float *buffer, int width, int height, int channels, - const char *from_colorspace, const char *to_colorspace, int predivide) + const char *from_colorspace, const char *to_colorspace, bool predivide) { - colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, FALSE); + colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false); } /* convert the whole buffer from specified by name color space to another * will do threaded conversion */ void IMB_colormanagement_transform_threaded(float *buffer, int width, int height, int channels, - const char *from_colorspace, const char *to_colorspace, int predivide) + const char *from_colorspace, const char *to_colorspace, bool predivide) { - colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, TRUE); + colormanagement_transform_ex(buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true); } void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace) @@ -1633,7 +1708,7 @@ void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], ColorSpac OCIO_processorApplyRGB(processor, pixel); } -void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4], int predivide, ColorSpace *colorspace) +void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4], bool predivide, ColorSpace *colorspace) { OCIO_ConstProcessorRcPtr *processor; @@ -1653,7 +1728,7 @@ void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4], int predi } } -void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, struct ColorSpace *colorspace, int predivide) +void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, struct ColorSpace *colorspace, bool predivide) { OCIO_ConstProcessorRcPtr *processor; @@ -1732,7 +1807,7 @@ void IMB_colormanagement_pixel_to_display_space_v3(float result[3], const float } static void colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, int make_byte) + const ColorManagedDisplaySettings *display_settings, bool make_byte) { if (!ibuf->rect && make_byte) imb_addrectImBuf(ibuf); @@ -1750,7 +1825,7 @@ static void colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorMan void IMB_colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings) { - colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, FALSE); + colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false); } /* prepare image buffer to be saved on disk, applying color management if needed @@ -1764,14 +1839,14 @@ void IMB_colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorManage * in image format write callback and if float_colorspace is not NULL, no color * space transformation should be applied on this buffer. */ -ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, int save_as_render, int allocate_result, const ColorManagedViewSettings *view_settings, +ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, bool allocate_result, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, ImageFormatData *image_format_data) { ImBuf *colormanaged_ibuf = ibuf; - int do_colormanagement; + bool do_colormanagement; bool is_movie = BKE_imtype_is_movie(image_format_data->imtype); - int requires_linear_float = BKE_imtype_requires_linear_float(image_format_data->imtype); - int do_alpha_under = image_format_data->planes != R_IMF_PLANES_RGBA; + bool requires_linear_float = BKE_imtype_requires_linear_float(image_format_data->imtype); + bool do_alpha_under = image_format_data->planes != R_IMF_PLANES_RGBA; do_colormanagement = save_as_render && (is_movie || !requires_linear_float); @@ -1827,7 +1902,7 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, int save_as_render, int } if (do_colormanagement) { - int make_byte = FALSE; + bool make_byte = false; ImFileType *type; /* for proper check whether byte buffer is required by a format or not @@ -1843,7 +1918,7 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, int save_as_render, int for (type = IMB_FILE_TYPES; type->is_a; type++) { if (type->save && type->ftype(type, colormanaged_ibuf)) { if ((type->flag & IM_FTYPE_FLOAT) == 0) - make_byte = TRUE; + make_byte = true; break; } @@ -1878,7 +1953,7 @@ void IMB_colormanagement_buffer_make_display_space(float *buffer, unsigned char cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings); processor_transform_apply_threaded(display_buffer_float, width, height, channels, - cm_processor, TRUE); + cm_processor, true); IMB_buffer_byte_from_float(display_buffer, display_buffer_float, channels, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, @@ -1955,7 +2030,7 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet return (unsigned char *) ibuf->rect; } - colormanage_view_settings_to_cache(&cache_view_settings, applied_view_settings); + colormanage_view_settings_to_cache(ibuf, &cache_view_settings, applied_view_settings); colormanage_display_settings_to_cache(&cache_display_settings, display_settings); if (ibuf->invalid_rect.xmin != ibuf->invalid_rect.xmax) { @@ -1964,7 +2039,7 @@ unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSet ibuf->x, 0, 0, applied_view_settings, display_settings, ibuf->invalid_rect.xmin, ibuf->invalid_rect.ymin, ibuf->invalid_rect.xmax, ibuf->invalid_rect.ymax, - FALSE); + false); } BLI_rcti_init(&ibuf->invalid_rect, 0, 0, 0, 0); @@ -2019,7 +2094,7 @@ unsigned char *IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, vo void IMB_display_buffer_transform_apply(unsigned char *display_buffer, float *linear_buffer, int width, int height, int channels, const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, int predivide) + const ColorManagedDisplaySettings *display_settings, bool predivide) { if (global_tot_display == 0 || global_tot_view == 0) { IMB_buffer_byte_from_float(display_buffer, linear_buffer, channels, 0.0f, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, FALSE, @@ -2281,7 +2356,7 @@ static void colormanage_description_strip(char *description) } } -ColorSpace *colormanage_colorspace_add(const char *name, const char *description, int is_invertible, int is_data) +ColorSpace *colormanage_colorspace_add(const char *name, const char *description, bool is_invertible, bool is_data) { ColorSpace *colorspace, *prev_space; int counter = 1; @@ -2342,7 +2417,7 @@ ColorSpace *colormanage_colorspace_get_roled(int role) ColorSpace *colormanage_colorspace_get_indexed(int index) { - /* display indices are 1-based */ + /* color space indices are 1-based */ return BLI_findlink(&global_colorspaces, index - 1); } @@ -2387,6 +2462,71 @@ void IMB_colormanagment_colorspace_from_ibuf_ftype(ColorManagedColorspaceSetting } } +/*********************** Looks functions *************************/ + +ColorManagedLook *colormanage_look_add(const char *name, const char *process_space, bool is_noop) +{ + ColorManagedLook *look; + int index = global_tot_looks; + + look = MEM_callocN(sizeof(ColorManagedLook), "ColorManagedLook"); + look->index = index + 1; + BLI_strncpy(look->name, name, sizeof(look->name)); + BLI_strncpy(look->process_space, process_space, sizeof(look->process_space)); + look->is_noop = is_noop; + + BLI_addtail(&global_looks, look); + + global_tot_looks++; + + return look; +} + +ColorManagedLook *colormanage_look_get_named(const char *name) +{ + ColorManagedLook *look; + + for (look = global_looks.first; look; look = look->next) { + if (!strcmp(look->name, name)) { + return look; + } + } + + return NULL; +} + +ColorManagedLook *colormanage_look_get_indexed(int index) +{ + /* look indices are 1-based */ + return BLI_findlink(&global_looks, index - 1); +} + +int IMB_colormanagement_look_get_named_index(const char *name) +{ + ColorManagedLook *look; + + look = colormanage_look_get_named(name); + + if (look) { + return look->index; + } + + return 0; +} + +const char *IMB_colormanagement_look_get_indexed_name(int index) +{ + ColorManagedLook *look; + + look = colormanage_look_get_indexed(index); + + if (look) { + return look->name; + } + + return NULL; +} + /*********************** RNA helper functions *************************/ void IMB_colormanagement_display_items_add(EnumPropertyItem **items, int *totitem) @@ -2435,6 +2575,23 @@ void IMB_colormanagement_view_items_add(EnumPropertyItem **items, int *totitem, } } +void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items, int *totitem) +{ + ColorManagedLook *look; + + for (look = global_looks.first; look; look = look->next) { + EnumPropertyItem item; + + item.value = look->index; + item.name = look->name; + item.identifier = look->name; + item.icon = 0; + item.description = ""; + + RNA_enum_item_add(items, totitem, &item); + } +} + void IMB_colormanagement_colorspace_items_add(EnumPropertyItem **items, int *totitem) { ColorSpace *colorspace; @@ -2480,7 +2637,7 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe float *display_buffer_float = NULL; const int width = xmax - xmin; const int height = ymax - ymin; - int is_data = ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA; + bool is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0; if (dither != 0.0f) { /* cm_processor is NULL in cases byte_buffer's space matches display @@ -2561,7 +2718,7 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, const unsigned char *byte_buffer, int stride, int offset_x, int offset_y, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, - int xmin, int ymin, int xmax, int ymax, int update_orig_byte_buffer) + int xmin, int ymin, int xmax, int ymax, bool update_orig_byte_buffer) { if ((ibuf->rect && ibuf->rect_float) || update_orig_byte_buffer) { /* update byte buffer created by legacy color management */ @@ -2584,7 +2741,7 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, unsigned char *display_buffer = NULL; int view_flag, display_index, buffer_width; - colormanage_view_settings_to_cache(&cache_view_settings, view_settings); + colormanage_view_settings_to_cache(ibuf, &cache_view_settings, view_settings); colormanage_display_settings_to_cache(&cache_display_settings, display_settings); view_flag = 1 << (cache_view_settings.view - 1); @@ -2608,7 +2765,7 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, if (display_buffer) { ColormanageProcessor *cm_processor = NULL; - int skip_transform = 0; + bool skip_transform = false; /* byte buffer is assumed to be in imbuf's rect space, so if byte buffer * is known we could skip display->linear->display conversion in case @@ -2667,13 +2824,16 @@ ColormanageProcessor *IMB_colormanagement_display_processor_new(const ColorManag if (display_space) cm_processor->is_data_result = display_space->is_data; - cm_processor->processor = create_display_buffer_processor(applied_view_settings->view_transform, display_settings->display_device, - applied_view_settings->exposure, applied_view_settings->gamma, + cm_processor->processor = create_display_buffer_processor(applied_view_settings->look, + applied_view_settings->view_transform, + display_settings->display_device, + applied_view_settings->exposure, + applied_view_settings->gamma, global_role_scene_linear); if (applied_view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) { cm_processor->curve_mapping = curvemapping_copy(applied_view_settings->curve_mapping); - curvemapping_premultiply(cm_processor->curve_mapping, FALSE); + curvemapping_premultiply(cm_processor->curve_mapping, false); } return cm_processor; @@ -2722,7 +2882,7 @@ void IMB_colormanagement_processor_apply_v3(ColormanageProcessor *cm_processor, } void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, float *buffer, int width, int height, - int channels, int predivide) + int channels, bool predivide) { /* apply curve mapping */ if (cm_processor->curve_mapping) { @@ -2771,6 +2931,7 @@ static bool check_glsl_display_processor_changed(const ColorManagedViewSettings { return !(global_glsl_state.exposure == view_settings->exposure && global_glsl_state.gamma == view_settings->gamma && + STREQ(global_glsl_state.look, view_settings->look) && STREQ(global_glsl_state.view, view_settings->view_transform) && STREQ(global_glsl_state.display, display_settings->display_device) && STREQ(global_glsl_state.input, from_colorspace)); @@ -2787,6 +2948,7 @@ static void update_glsl_display_processor(const ColorManagedViewSettings *view_s check_glsl_display_processor_changed(view_settings, display_settings, from_colorspace)) { /* Store settings of processor for further comparison. */ + BLI_strncpy(global_glsl_state.look, view_settings->look, MAX_COLORSPACE_NAME); BLI_strncpy(global_glsl_state.view, view_settings->view_transform, MAX_COLORSPACE_NAME); BLI_strncpy(global_glsl_state.display, display_settings->display_device, MAX_COLORSPACE_NAME); BLI_strncpy(global_glsl_state.input, from_colorspace, MAX_COLORSPACE_NAME); @@ -2799,7 +2961,8 @@ static void update_glsl_display_processor(const ColorManagedViewSettings *view_s /* We're using display OCIO processor, no RGB curves yet. */ global_glsl_state.processor = - create_display_buffer_processor(global_glsl_state.view, + create_display_buffer_processor(global_glsl_state.look, + global_glsl_state.view, global_glsl_state.display, global_glsl_state.exposure, global_glsl_state.gamma, @@ -2807,6 +2970,17 @@ static void update_glsl_display_processor(const ColorManagedViewSettings *view_s } } +bool IMB_colormanagement_support_glsl_draw(const ColorManagedViewSettings *view_settings, + bool skip_curves) +{ + /* curves not supported yet */ + if (!skip_curves) + if (view_settings && (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES)) + return 0; + + return OCIO_supportGLSLDraw(); +} + /** * Configures GLSL shader for conversion from specified to * display color space @@ -2820,9 +2994,10 @@ static void update_glsl_display_processor(const ColorManagedViewSettings *view_s * This is low-level function, use glaDrawImBuf_glsl_ctx if you * only need to display given image buffer */ -int IMB_colormanagement_setup_glsl_draw_from_space(const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, - struct ColorSpace *from_colorspace, int predivide) +bool IMB_colormanagement_setup_glsl_draw_from_space(const ColorManagedViewSettings *view_settings, + const ColorManagedDisplaySettings *display_settings, + struct ColorSpace *from_colorspace, bool predivide, + bool skip_curves) { ColorManagedViewSettings default_view_settings; const ColorManagedViewSettings *applied_view_settings; @@ -2840,8 +3015,9 @@ int IMB_colormanagement_setup_glsl_draw_from_space(const ColorManagedViewSetting } /* RGB curves mapping is not supported on GPU yet. */ - if (applied_view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) - return FALSE; + if (!skip_curves) + if (applied_view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) + return false; /* Make sure OCIO processor is up-to-date. */ update_glsl_display_processor(applied_view_settings, display_settings, @@ -2851,27 +3027,27 @@ int IMB_colormanagement_setup_glsl_draw_from_space(const ColorManagedViewSetting } /* Configures GLSL shader for conversion from scene linear to display space */ -int IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_settings, - const ColorManagedDisplaySettings *display_settings, - int predivide) +bool IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_settings, + const ColorManagedDisplaySettings *display_settings, + bool predivide, bool skip_curves) { return IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, - NULL, predivide); + NULL, predivide, skip_curves); } /* Same as setup_glsl_draw_from_space, but color management settings are guessing from a given context */ -int IMB_colormanagement_setup_glsl_draw_from_space_ctx(const struct bContext *C, struct ColorSpace *from_colorspace, int predivide) +bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const struct bContext *C, struct ColorSpace *from_colorspace, bool predivide) { ColorManagedViewSettings *view_settings; ColorManagedDisplaySettings *display_settings; IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings); - return IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, from_colorspace, predivide); + return IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, from_colorspace, predivide, false); } /* Same as setup_glsl_draw, but color management settings are guessing from a given context */ -int IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, int predivide) +bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, bool predivide) { return IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, NULL, predivide); } @@ -2897,7 +3073,7 @@ void IMB_colormanagement_finish_glsl_draw(void) * When there's no need to apply transform on 2D textures, use * IMB_colormanagement_finish_glsl_transform(). */ -int IMB_colormanagement_setup_transform_from_role_glsl(int role, int predivide) +bool IMB_colormanagement_setup_transform_from_role_glsl(int role, bool predivide) { OCIO_ConstProcessorRcPtr *processor; ColorSpace *colorspace; diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index 76a5e98da7e..af9f7109106 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -565,7 +565,7 @@ void IMB_rect_from_float(ImBuf *ibuf) buffer = MEM_dupallocN(ibuf->rect_float); /* first make float buffer in byte space */ - IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, ibuf->rect_colorspace->name, TRUE); + IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, ibuf->rect_colorspace->name, true); /* convert from float's premul alpha to byte's straight alpha */ IMB_unpremultiply_rect_float(buffer, ibuf->planes, ibuf->x, ibuf->y); @@ -657,7 +657,7 @@ void IMB_float_from_rect(ImBuf *ibuf) /* then make float be in linear space */ IMB_colormanagement_colorspace_to_scene_linear(rect_float, ibuf->x, ibuf->y, ibuf->channels, - ibuf->rect_colorspace, FALSE); + ibuf->rect_colorspace, false); /* byte buffer is straight alpha, float should always be premul */ IMB_premultiply_rect_float(rect_float, ibuf->channels, ibuf->x, ibuf->y); diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c index 26dd0f2977a..bde17e17419 100644 --- a/source/blender/imbuf/intern/imageprocess.c +++ b/source/blender/imbuf/intern/imageprocess.c @@ -359,17 +359,21 @@ void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, float backcol unsigned char *cp = rect; while (a--) { - if (cp[3] == 0) { + if (cp[3] == 255) { + /* pass */ + } + else if (cp[3] == 0) { cp[0] = backcol[0] * 255; cp[1] = backcol[1] * 255; cp[2] = backcol[2] * 255; } else { - int mul = 255 - cp[3]; + float alpha = cp[3] / 255.0; + float mul = 1.0f - alpha; - cp[0] = (cp[0] * cp[3] >> 8) + mul * backcol[0] / 255; - cp[1] = (cp[1] * cp[3] >> 8) + mul * backcol[1] / 255; - cp[2] = (cp[2] * cp[3] >> 8) + mul * backcol[2] / 255; + cp[0] = (cp[0] * alpha) + mul * backcol[0]; + cp[1] = (cp[1] * alpha) + mul * backcol[1]; + cp[2] = (cp[2] * alpha) + mul * backcol[2]; } cp[3] = 255; diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 7acfe8a9dd1..dd0970a71f2 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -22,6 +22,10 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/imbuf/intern/indexer.c + * \ingroup imbuf + */ + #include <stdlib.h> #include "MEM_guardedalloc.h" diff --git a/source/blender/imbuf/intern/indexer_dv.c b/source/blender/imbuf/intern/indexer_dv.c index 7a8f8fcc752..4e8c13d2e99 100644 --- a/source/blender/imbuf/intern/indexer_dv.c +++ b/source/blender/imbuf/intern/indexer_dv.c @@ -22,6 +22,10 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/imbuf/intern/indexer_dv.c + * \ingroup imbuf + */ + #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c index 38caf224c42..a31ed5e7420 100644 --- a/source/blender/imbuf/intern/jpeg.c +++ b/source/blender/imbuf/intern/jpeg.c @@ -59,11 +59,7 @@ #define IS_maxjpg(x) ((x->ftype & JPG_MSK) == JPG_MAX) /* the types are from the jpeg lib */ -static void jpeg_error(j_common_ptr cinfo) -#ifdef __GNUC__ -__attribute__((noreturn)) -#endif -; +static void jpeg_error(j_common_ptr cinfo) ATTR_NORETURN; static void init_source(j_decompress_ptr cinfo); static boolean fill_input_buffer(j_decompress_ptr cinfo); static void skip_input_data(j_decompress_ptr cinfo, long num_bytes); diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c index fed55c05eea..2b4367528dd 100644 --- a/source/blender/imbuf/intern/metadata.c +++ b/source/blender/imbuf/intern/metadata.c @@ -63,21 +63,21 @@ void IMB_metadata_free(struct ImBuf *img) } } -int IMB_metadata_get_field(struct ImBuf *img, const char *key, char *field, const size_t len) +bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *field, const size_t len) { ImMetaData *info; - int retval = 0; + bool retval = false; if (!img) - return 0; + return false; if (!img->metadata) { - return 0; + return false; } info = img->metadata; while (info) { if (strcmp(key, info->key) == 0) { BLI_strncpy(field, info->value, len); - retval = 1; + retval = true; break; } info = info->next; @@ -85,13 +85,13 @@ int IMB_metadata_get_field(struct ImBuf *img, const char *key, char *field, cons return retval; } -int IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value) +bool IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value) { ImMetaData *info; ImMetaData *last; if (!img) - return 0; + return false; if (!img->metadata) { img->metadata = MEM_callocN(sizeof(ImMetaData), "ImMetaData"); @@ -109,15 +109,15 @@ int IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value } info->key = BLI_strdup(key); info->value = BLI_strdup(value); - return 1; + return true; } -int IMB_metadata_del_field(struct ImBuf *img, const char *key) +bool IMB_metadata_del_field(struct ImBuf *img, const char *key) { ImMetaData *p, *p1; if ((!img) || (!img->metadata)) - return (0); + return false; p = img->metadata; p1 = NULL; @@ -131,20 +131,20 @@ int IMB_metadata_del_field(struct ImBuf *img, const char *key) MEM_freeN(p->key); MEM_freeN(p->value); MEM_freeN(p); - return (1); + return true; } p1 = p; p = p->next; } - return (0); + return false; } -int IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *field) +bool IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *field) { ImMetaData *p; if (!img) - return (0); + return false; if (!img->metadata) return (IMB_metadata_add_field(img, key, field)); @@ -154,7 +154,7 @@ int IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *fi if (!strcmp(key, p->key)) { MEM_freeN(p->value); p->value = BLI_strdup(field); - return (1); + return true; } p = p->next; } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 875e01f8037..1e145347bb3 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -235,7 +235,7 @@ typedef struct PreviewImage { # undef GS #endif // #define GS(a) (*((short *)(a))) -#define GS(a) (CHECK_TYPE_INLINE(a, const char), (*((short *)(a)))) +#define GS(a) (CHECK_TYPE_INLINE(a, const char *), (*((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++; } diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h index 1495ba1b1a5..f4e2ff43fc5 100644 --- a/source/blender/makesdna/DNA_actuator_types.h +++ b/source/blender/makesdna/DNA_actuator_types.h @@ -59,7 +59,7 @@ typedef struct bActionActuator { short layer; /* Animation layer */ short end_reset; /* Ending the actuator (negative pulse) wont reset the the action to its starting frame */ short strideaxis; /* Displacement axis */ - short pad; + short blend_mode; /* Layer blending mode */ float stridelength; /* Displacement incurred by cycle */ // not in use float layer_weight; /* How much of the previous layer to use for blending. (<0 = disable, 0 = add mode) */ } bActionActuator; @@ -341,6 +341,10 @@ typedef struct bActuator { #define ACT_ACTION_FROM_PROP 6 #define ACT_ACTION_MOTION 7 +/* actionactuator->blend_mode */ +#define ACT_ACTION_BLEND 0 +#define ACT_ACTION_ADD 1 + /* ipoactuator->type */ #define ACT_IPO_PLAY 0 #define ACT_IPO_PINGPONG 1 diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h index 32a0629c338..50bbc04ccb1 100644 --- a/source/blender/makesdna/DNA_color_types.h +++ b/source/blender/makesdna/DNA_color_types.h @@ -162,6 +162,7 @@ typedef struct Scopes { typedef struct ColorManagedViewSettings { int flag, pad; + char look[64]; /* look which is being applied when displaying buffer on the screen (prior to view transform) */ char view_transform[64]; /* view transform which is being applied when displaying buffer on the screen */ float exposure; /* fstop exposure */ float gamma; /* post-display gamma transform */ diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index f1b7a7c3cc3..29e49a970d8 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -407,8 +407,10 @@ typedef struct bShrinkwrapConstraint { struct Object *target; float dist; /* distance to kept from target */ short shrinkType; /* shrink type (look on MOD shrinkwrap for values) */ - char projAxis; /* axis to project over UP_X, UP_Y, UP_Z */ - char pad[9]; + char projAxis; /* axis to project/constrain */ + char projAxisSpace; /* space to project axis in */ + float projLimit; /* distance to search */ + char pad[4]; } bShrinkwrapConstraint; /* Follow Track constraints */ diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 7ff8667f90e..2cfbbbd516b 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -184,12 +184,9 @@ typedef struct Curve { struct Object *bevobj, *taperobj, *textoncurve; struct Ipo *ipo DNA_DEPRECATED; /* old animation system, deprecated for 2.5 */ - Path *path; struct Key *key; struct Material **mat; - ListBase bev; - /* texture space, copied as one block in editobject.c */ float loc[3]; float size[3]; diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index e2863d6e465..f6516492b8f 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -73,50 +73,52 @@ typedef struct CustomData { } CustomData; /* CustomData.type */ -#define CD_MVERT 0 -#define CD_MSTICKY 1 /* DEPRECATED */ -#define CD_MDEFORMVERT 2 -#define CD_MEDGE 3 -#define CD_MFACE 4 -#define CD_MTFACE 5 -#define CD_MCOL 6 -#define CD_ORIGINDEX 7 -#define CD_NORMAL 8 -//#define CD_POLYINDEX 9 -#define CD_PROP_FLT 10 -#define CD_PROP_INT 11 -#define CD_PROP_STR 12 -#define CD_ORIGSPACE 13 /* for modifier stack face location mapping */ -#define CD_ORCO 14 -#define CD_MTEXPOLY 15 -#define CD_MLOOPUV 16 -#define CD_MLOOPCOL 17 -#define CD_TANGENT 18 -#define CD_MDISPS 19 -#define CD_PREVIEW_MCOL 20 /* for displaying weightpaint colors */ -#define CD_ID_MCOL 21 -#define CD_TEXTURE_MCOL 22 -#define CD_CLOTH_ORCO 23 -#define CD_RECAST 24 +enum { + CD_MVERT = 0, + CD_MSTICKY = 1, /* DEPRECATED */ + CD_MDEFORMVERT = 2, + CD_MEDGE = 3, + CD_MFACE = 4, + CD_MTFACE = 5, + CD_MCOL = 6, + CD_ORIGINDEX = 7, + CD_NORMAL = 8, +/* CD_POLYINDEX = 9, */ + CD_PROP_FLT = 10, + CD_PROP_INT = 11, + CD_PROP_STR = 12, + CD_ORIGSPACE = 13, /* for modifier stack face location mapping */ + CD_ORCO = 14, + CD_MTEXPOLY = 15, + CD_MLOOPUV = 16, + CD_MLOOPCOL = 17, + CD_TANGENT = 18, + CD_MDISPS = 19, + CD_PREVIEW_MCOL = 20, /* for displaying weightpaint colors */ + CD_ID_MCOL = 21, + CD_TEXTURE_MCOL = 22, + CD_CLOTH_ORCO = 23, + CD_RECAST = 24, /* BMESH ONLY START */ -#define CD_MPOLY 25 -#define CD_MLOOP 26 -#define CD_SHAPE_KEYINDEX 27 -#define CD_SHAPEKEY 28 -#define CD_BWEIGHT 29 -#define CD_CREASE 30 -#define CD_ORIGSPACE_MLOOP 31 -#define CD_PREVIEW_MLOOPCOL 32 -#define CD_BM_ELEM_PYPTR 33 + CD_MPOLY = 25, + CD_MLOOP = 26, + CD_SHAPE_KEYINDEX = 27, + CD_SHAPEKEY = 28, + CD_BWEIGHT = 29, + CD_CREASE = 30, + CD_ORIGSPACE_MLOOP = 31, + CD_PREVIEW_MLOOPCOL = 32, + CD_BM_ELEM_PYPTR = 33, /* BMESH ONLY END */ -#define CD_PAINT_MASK 34 -#define CD_GRID_PAINT_MASK 35 -#define CD_MVERT_SKIN 36 -#define CD_FREESTYLE_EDGE 37 -#define CD_FREESTYLE_FACE 38 -#define CD_NUMTYPES 39 + CD_PAINT_MASK = 34, + CD_GRID_PAINT_MASK = 35, + CD_MVERT_SKIN = 36, + CD_FREESTYLE_EDGE = 37, + CD_FREESTYLE_FACE = 38, + CD_NUMTYPES = 39, +}; /* Bits for CustomDataMask */ #define CD_MASK_MVERT (1 << CD_MVERT) @@ -162,22 +164,22 @@ typedef struct CustomData { #define CD_MASK_FREESTYLE_FACE (1LL << CD_FREESTYLE_FACE) /* CustomData.flag */ - -/* indicates layer should not be copied by CustomData_from_template or - * CustomData_copy_data */ -#define CD_FLAG_NOCOPY (1<<0) -/* indicates layer should not be freed (for layers backed by external data) */ -#define CD_FLAG_NOFREE (1<<1) -/* indicates the layer is only temporary, also implies no copy */ -#define CD_FLAG_TEMPORARY ((1<<2)|CD_FLAG_NOCOPY) -/* indicates the layer is stored in an external file */ -#define CD_FLAG_EXTERNAL (1<<3) -/* indicates external data is read into memory */ -#define CD_FLAG_IN_MEMORY (1<<4) +enum { + /* Indicates layer should not be copied by CustomData_from_template or CustomData_copy_data */ + CD_FLAG_NOCOPY = (1 << 0), + /* Indicates layer should not be freed (for layers backed by external data) */ + CD_FLAG_NOFREE = (1 << 1), + /* Indicates the layer is only temporary, also implies no copy */ + CD_FLAG_TEMPORARY = ((1 << 2) | CD_FLAG_NOCOPY), + /* Indicates the layer is stored in an external file */ + CD_FLAG_EXTERNAL = (1 << 3), + /* Indicates external data is read into memory */ + CD_FLAG_IN_MEMORY = (1 << 4), +}; /* Limits */ -#define MAX_MTFACE 8 -#define MAX_MCOL 8 +#define MAX_MTFACE 8 +#define MAX_MCOL 8 #ifdef __cplusplus } diff --git a/source/blender/makesdna/DNA_freestyle_types.h b/source/blender/makesdna/DNA_freestyle_types.h index 738377b137e..db16fa37b86 100644 --- a/source/blender/makesdna/DNA_freestyle_types.h +++ b/source/blender/makesdna/DNA_freestyle_types.h @@ -28,6 +28,10 @@ #ifndef __DNA_FREESTYLE_TYPES_H__ #define __DNA_FREESTYLE_TYPES_H__ +/** \file DNA_freestyle_types.h + * \ingroup DNA + */ + #include "DNA_listBase.h" #ifdef __cplusplus diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h index 3e641fba1ac..2699c6e576e 100644 --- a/source/blender/makesdna/DNA_ipo_types.h +++ b/source/blender/makesdna/DNA_ipo_types.h @@ -42,6 +42,8 @@ #include "DNA_ID.h" +#include "BLI_compiler_attrs.h" + /* -------------------------- Type Defines --------------------------- */ /* sometimes used - mainly for GE/Ketsji */ diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h index 0a09a82b2bb..f5ce3c8d8c1 100644 --- a/source/blender/makesdna/DNA_key_types.h +++ b/source/blender/makesdna/DNA_key_types.h @@ -60,7 +60,6 @@ typedef struct KeyBlock { int uid; /* for meshes only, match the unique number with the customdata layer */ void *data; /* array of shape key values, size is (Key->elemsize * KeyBlock->totelem) */ - float *weights; /* store an aligned array of weights from 'vgroup' */ char name[64]; /* MAX_NAME (unique name, user assigned) */ char vgroup[64]; /* MAX_VGROUP_NAME (optional vertex group), array gets allocated into 'weights' when set */ diff --git a/source/blender/makesdna/DNA_lattice_types.h b/source/blender/makesdna/DNA_lattice_types.h index 837f0c354e6..242d6f0feeb 100644 --- a/source/blender/makesdna/DNA_lattice_types.h +++ b/source/blender/makesdna/DNA_lattice_types.h @@ -68,10 +68,6 @@ typedef struct Lattice { struct MDeformVert *dvert; char vgroup[64]; /* multiply the influence, MAX_VGROUP_NAME */ - /* used while deforming, always free and NULL after use */ - float *latticedata; - float latmat[4][4]; - struct EditLatt *editlatt; } Lattice; diff --git a/source/blender/makesdna/DNA_linestyle_types.h b/source/blender/makesdna/DNA_linestyle_types.h index f5473d3d84a..19c4e057a96 100644 --- a/source/blender/makesdna/DNA_linestyle_types.h +++ b/source/blender/makesdna/DNA_linestyle_types.h @@ -28,6 +28,10 @@ #ifndef __DNA_LINESTYLE_TYPES_H__ #define __DNA_LINESTYLE_TYPES_H__ +/** \file DNA_linestyle_types.h + * \ingroup DNA + */ + #include "DNA_listBase.h" #include "DNA_ID.h" diff --git a/source/blender/makesdna/DNA_mask_types.h b/source/blender/makesdna/DNA_mask_types.h index 1b6b802f2de..4307ea57f15 100644 --- a/source/blender/makesdna/DNA_mask_types.h +++ b/source/blender/makesdna/DNA_mask_types.h @@ -58,15 +58,18 @@ typedef struct Mask { typedef struct MaskParent { // int flag; /* parenting flags */ /* not used */ - int pad; int id_type; /* type of parenting */ + int type; /* type of parenting */ ID *id; /* ID block of entity to which mask/spline is parented to * in case of parenting to movie tracking data set to MovieClip datablock */ char parent[64]; /* entity of parent to which parenting happened * in case of parenting to movie tracking data contains name of layer */ char sub_parent[64]; /* sub-entity of parent to which parenting happened * in case of parenting to movie tracking data contains name of track */ - float parent_orig[2]; /* track location at the moment of parenting */ + float parent_orig[2]; /* track location at the moment of parenting, + * stored in mask space*/ + + float parent_corners_orig[4][2]; /* Original corners of plane track at the moment of parenting */ } MaskParent; typedef struct MaskSplinePointUW { @@ -141,6 +144,12 @@ typedef struct MaskLayer { /* MaskParent->flag */ /* #define MASK_PARENT_ACTIVE (1 << 0) */ /* UNUSED */ +/* MaskParent->type */ +enum { + MASK_PARENT_POINT_TRACK = 0, /* parenting happens to point track */ + MASK_PARENT_PLANE_TRACK = 1, /* parenting happens to plane track */ +}; + /* MaskSpline->flag */ /* reserve (1 << 0) for SELECT */ enum { diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index e37d1368892..7cdb79232a9 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -79,7 +79,7 @@ typedef struct Mesh { * real faces are now stored in nface.*/ struct MFace *mface; /* array of mesh object mode faces for tessellation */ struct MTFace *mtface; /* store tessellation face UV's and texture here */ - struct TFace *tface; /* depecrated, use mtface */ + struct TFace *tface DNA_DEPRECATED; /* deprecated, use mtface */ struct MVert *mvert; /* array of verts */ struct MEdge *medge; /* array of edges */ struct MDeformVert *dvert; /* deformgroup vertices */ diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 9f9bc25a61c..1114549f2da 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -42,7 +42,7 @@ struct Image; typedef struct MFace { unsigned int v1, v2, v3, v4; short mat_nr; - char edcode, flag; /* we keep edcode, for conversion to edges draw flags in old files */ + char edcode, flag; /* we keep edcode, for conversion to edges draw flags in old files */ } MFace; typedef struct MEdge { @@ -52,44 +52,42 @@ typedef struct MEdge { } MEdge; typedef struct MDeformWeight { - int def_nr; - float weight; + int def_nr; + float weight; } MDeformWeight; typedef struct MDeformVert { struct MDeformWeight *dw; int totweight; - int flag; /* flag only in use for weightpaint now */ + int flag; /* flag only in use for weightpaint now */ } MDeformVert; typedef struct MVert { - float co[3]; - short no[3]; + float co[3]; + short no[3]; char flag, bweight; } MVert; /* tessellation vertex color data. - * at the moment alpha is abused for vertex painting - * and not used for transparency, note that red and blue are swapped */ + * at the moment alpha is abused for vertex painting and not used for transparency, note that red and blue are swapped + */ typedef struct MCol { char a, r, g, b; } MCol; -/* new face structure, replaces MFace, which is now - * only used for storing tessellations.*/ +/* new face structure, replaces MFace, which is now only used for storing tessellations.*/ typedef struct MPoly { /* offset into loop array and number of loops in the face */ int loopstart; - int totloop; /* keep signed since we need to subtract when getting the previous loop */ + int totloop; /* keep signed since we need to subtract when getting the previous loop */ short mat_nr; char flag, pad; } MPoly; -/* the e here is because we want to move away from - * relying on edge hashes.*/ +/* the e here is because we want to move away from relying on edge hashes.*/ typedef struct MLoop { - unsigned int v; /*vertex index*/ - unsigned int e; /*edge index*/ + unsigned int v; /* vertex index */ + unsigned int e; /* edge index */ } MLoop; typedef struct MTexPoly { @@ -114,9 +112,11 @@ typedef struct MLoopUV { } MLoopUV; /*mloopuv->flag*/ -#define MLOOPUV_EDGESEL 1 -#define MLOOPUV_VERTSEL 2 -#define MLOOPUV_PINNED 4 +enum { + MLOOPUV_EDGESEL = (1 << 0), + MLOOPUV_VERTSEL = (1 << 1), + MLOOPUV_PINNED = (1 << 2), +}; /** * at the moment alpha is abused for vertex painting, @@ -166,13 +166,13 @@ typedef struct MTFace { /*Custom Data Properties*/ typedef struct MFloatProperty { - float f; + float f; } MFloatProperty; typedef struct MIntProperty { - int i; + int i; } MIntProperty; typedef struct MStringProperty { - char s[255], s_len; + char s[255], s_len; } MStringProperty; typedef struct OrigSpaceFace { @@ -188,11 +188,10 @@ typedef struct MDisps { int totdisp; int level; float (*disps)[3]; - - /* Used for hiding parts of a multires mesh. Essentially the multires - * equivalent of MVert.flag's ME_HIDE bit. - * - * This is a bitmap, keep in sync with type used in BLI_bitmap.h */ + + /* Used for hiding parts of a multires mesh. Essentially the multires equivalent of MVert.flag's ME_HIDE bit. + * NOTE: This is a bitmap, keep in sync with type used in BLI_bitmap.h + */ unsigned int *hidden; } MDisps; @@ -200,15 +199,18 @@ typedef struct MDisps { typedef struct MultiresCol { float a, r, g, b; } MultiresCol; + typedef struct MultiresColFace { /* vertex colors */ MultiresCol col[4]; } MultiresColFace; + typedef struct MultiresFace { unsigned int v[4]; unsigned int mid; char flag, mat_nr, pad[2]; } MultiresFace; + typedef struct MultiresEdge { unsigned int v[2]; unsigned int mid; @@ -245,7 +247,7 @@ typedef struct Multires { /** End Multires **/ typedef struct MRecast { - int i; + int i; } MRecast; typedef struct GridPaintMask { @@ -259,20 +261,19 @@ typedef struct GridPaintMask { } GridPaintMask; typedef enum MVertSkinFlag { - /* Marks a vertex as the edge-graph root, used for calculating - * rotations for all connected edges (recursively.) Also used to - * choose a root when generating an armature. */ + /* Marks a vertex as the edge-graph root, used for calculating rotations for all connected edges (recursively). + * Also used to choose a root when generating an armature. + */ MVERT_SKIN_ROOT = 1, - /* Marks a branch vertex (vertex with more than two connected - * edges) so that it's neighbors are directly hulled together, - * rather than the default of generating intermediate frames. */ - MVERT_SKIN_LOOSE = 2 + /* Marks a branch vertex (vertex with more than two connected edges), so that it's neighbors are + * directly hulled together, rather than the default of generating intermediate frames. + */ + MVERT_SKIN_LOOSE = 2, } MVertSkinFlag; typedef struct MVertSkin { - /* Radii of the skin, define how big the generated frames - * are. Currently only the first two elements are used. */ + /* Radii of the skin, define how big the generated frames are. Currently only the first two elements are used. */ float radius[3]; /* MVertSkinFlag */ @@ -285,7 +286,9 @@ typedef struct FreestyleEdge { } FreestyleEdge; /* FreestyleEdge->flag */ -#define FREESTYLE_EDGE_MARK 1 +enum { + FREESTYLE_EDGE_MARK = 1, +}; typedef struct FreestyleFace { char flag; @@ -293,96 +296,118 @@ typedef struct FreestyleFace { } FreestyleFace; /* FreestyleFace->flag */ -#define FREESTYLE_FACE_MARK 1 - -/* mvert->flag (1=SELECT) */ -#define ME_SPHERETEST 2 -#define ME_VERT_TMP_TAG 4 -#define ME_HIDE 16 -#define ME_VERT_MERGED (1<<6) -#define ME_VERT_PBVH_UPDATE (1<<7) - -/* medge->flag (1=SELECT)*/ -#define ME_EDGEDRAW (1<<1) -#define ME_SEAM (1<<2) -#define ME_FGON (1<<3) /* no longer used (now we have ngons), only defined so we can clear it */ - /* reserve 16 for ME_HIDE */ -#define ME_EDGERENDER (1<<5) -#define ME_LOOSEEDGE (1<<7) -#define ME_EDGE_TMP_TAG (1 << 8) -#define ME_SHARP (1<<9) /* only reason this flag remains a 'short' */ +enum { + FREESTYLE_FACE_MARK = 1, +}; + +/* mvert->flag */ +enum { +/* SELECT = (1 << 0), */ + ME_SPHERETEST = (1 << 1), + ME_VERT_TMP_TAG = (1 << 2), + ME_HIDE = (1 << 4), + ME_VERT_MERGED = (1 << 6), + ME_VERT_PBVH_UPDATE = (1 << 7), +}; + +/* medge->flag */ +enum { +/* SELECT = (1 << 0), */ + ME_EDGEDRAW = (1 << 1), + ME_SEAM = (1 << 2), + ME_FGON = (1 << 3), /* no longer used (now we have ngons), only defined so we can clear it */ +/* ME_HIDE = (1 << 4), */ + ME_EDGERENDER = (1 << 5), + ME_LOOSEEDGE = (1 << 7), + ME_EDGE_TMP_TAG = (1 << 8), + ME_SHARP = (1 << 9), /* only reason this flag remains a 'short' */ +}; /* puno = vertexnormal (mface) */ -#define ME_PROJXY 16 -#define ME_PROJXZ 32 -#define ME_PROJYZ 64 +enum { + ME_PROJXY = (1 << 4), + ME_PROJXZ = (1 << 5), + ME_PROJYZ = (1 << 6), +}; /* edcode (mface) */ -#define ME_V1V2 1 -#define ME_V2V3 2 -#define ME_V3V1 4 -#define ME_V3V4 4 -#define ME_V4V1 8 +enum { + ME_V1V2 = (1 << 0), + ME_V2V3 = (1 << 1), + ME_V3V1 = (1 << 2), + ME_V3V4 = ME_V3V1, + ME_V4V1 = (1 << 3), +}; /* flag (mface) */ -#define ME_SMOOTH 1 -#define ME_FACE_SEL 2 -/* flag ME_HIDE==16 is used here too */ +enum { + ME_SMOOTH = (1 << 0), + ME_FACE_SEL = (1 << 1), +/* ME_HIDE = (1 << 4), */ +}; #define ME_POLY_LOOP_PREV(mloop, mp, i) (&(mloop)[(mp)->loopstart + (((i) + (mp)->totloop - 1) % (mp)->totloop)]) #define ME_POLY_LOOP_NEXT(mloop, mp, i) (&(mloop)[(mp)->loopstart + (((i) + 1) % (mp)->totloop)]) /* mselect->type */ -#define ME_VSEL 0 -#define ME_ESEL 1 -#define ME_FSEL 2 +enum { + ME_VSEL = 0, + ME_ESEL = 1, + ME_FSEL = 2, +}; /* mtface->flag */ -#define TF_SELECT 1 /* use MFace hide flag (after 2.43), should be able to reuse after 2.44 */ -#define TF_ACTIVE 2 /* deprecated! */ -#define TF_SEL1 4 -#define TF_SEL2 8 -#define TF_SEL3 16 -#define TF_SEL4 32 +enum { + TF_SELECT = (1 << 0), /* use MFace hide flag (after 2.43), should be able to reuse after 2.44 */ + TF_ACTIVE = (1 << 1), /* deprecated! */ + TF_SEL1 = (1 << 2), + TF_SEL2 = (1 << 3), + TF_SEL3 = (1 << 4), + TF_SEL4 = (1 << 5), +}; /* mtface->mode */ -#define TF_DYNAMIC 1 -#define TF_ALPHASORT 2 -#define TF_TEX 4 -#define TF_SHAREDVERT 8 -#define TF_LIGHT 16 - -#define TF_CONVERTED 32 /* tface converted to material */ - -#define TF_SHAREDCOL 64 -#define TF_TILES 128 /* deprecated */ -#define TF_BILLBOARD 256 -#define TF_TWOSIDE 512 -#define TF_INVISIBLE 1024 - -#define TF_OBCOL 2048 -#define TF_BILLBOARD2 4096 /* with Z axis constraint */ -#define TF_SHADOW 8192 -#define TF_BMFONT 16384 +enum { + TF_DYNAMIC = (1 << 0), + TF_ALPHASORT = (1 << 1), + TF_TEX = (1 << 2), + TF_SHAREDVERT = (1 << 3), + TF_LIGHT = (1 << 4), + + TF_CONVERTED = (1 << 5), /* tface converted to material */ + + TF_SHAREDCOL = (1 << 6), + TF_TILES = (1 << 7), /* deprecated */ + TF_BILLBOARD = (1 << 8), + TF_TWOSIDE = (1 << 9), + TF_INVISIBLE = (1 << 10), + + TF_OBCOL = (1 << 11), + TF_BILLBOARD2 = (1 << 12), /* with Z axis constraint */ + TF_SHADOW = (1 << 13), + TF_BMFONT = (1 << 14), +}; /* mtface->transp, values 1-4 are used as flags in the GL, WARNING, TF_SUB cant work with this */ -#define TF_SOLID 0 -#define TF_ADD 1 -#define TF_ALPHA 2 -#define TF_CLIP 4 /* clipmap alpha/binary alpha all or nothing! */ - -/* sub is not available in the user interface anymore */ -#define TF_SUB 3 +enum { + TF_SOLID = 0, + TF_ADD = (1 << 0), + TF_ALPHA = (1 << 1), + TF_CLIP = (1 << 2), /* clipmap alpha/binary alpha all or nothing! */ + TF_SUB = 3, /* sub is not available in the user interface anymore */ +}; /* mtface->unwrap */ -#define TF_DEPRECATED1 1 -#define TF_DEPRECATED2 2 -#define TF_DEPRECATED3 4 -#define TF_DEPRECATED4 8 -#define TF_PIN1 16 -#define TF_PIN2 32 -#define TF_PIN3 64 -#define TF_PIN4 128 - -#endif +enum { + TF_DEPRECATED1 = (1 << 0), + TF_DEPRECATED2 = (1 << 1), + TF_DEPRECATED3 = (1 << 2), + TF_DEPRECATED4 = (1 << 3), + TF_PIN1 = (1 << 4), + TF_PIN2 = (1 << 5), + TF_PIN3 = (1 << 6), + TF_PIN4 = (1 << 7), +}; + +#endif /* __DNA_MESHDATA_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_meta_types.h b/source/blender/makesdna/DNA_meta_types.h index 56683bf4797..8bbe53b33a6 100644 --- a/source/blender/makesdna/DNA_meta_types.h +++ b/source/blender/makesdna/DNA_meta_types.h @@ -65,8 +65,6 @@ typedef struct MetaBall { ID id; struct AnimData *adt; - struct BoundBox *bb; - ListBase elems; ListBase disp; ListBase *editelems; /* not saved in files, note we use pointer for editmode check */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 0b07605d22d..6b4c225aab5 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -29,7 +29,8 @@ #include "DNA_listBase.h" /* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE! - * (ONLY ADD NEW ITEMS AT THE END) */ + * (ONLY ADD NEW ITEMS AT THE END) + */ typedef enum ModifierType { eModifierType_None = 0, @@ -84,14 +85,14 @@ typedef enum ModifierType { } ModifierType; typedef enum ModifierMode { - eModifierMode_Realtime = (1<<0), - eModifierMode_Render = (1<<1), - eModifierMode_Editmode = (1<<2), - eModifierMode_OnCage = (1<<3), - eModifierMode_Expanded = (1<<4), - eModifierMode_Virtual = (1<<5), - eModifierMode_ApplyOnSpline = (1<<6), - eModifierMode_DisableTemporary = (1 << 31) + eModifierMode_Realtime = (1 << 0), + eModifierMode_Render = (1 << 1), + eModifierMode_Editmode = (1 << 2), + eModifierMode_OnCage = (1 << 3), + eModifierMode_Expanded = (1 << 4), + eModifierMode_Virtual = (1 << 5), + eModifierMode_ApplyOnSpline = (1 << 6), + eModifierMode_DisableTemporary = (1 << 31) } ModifierMode; typedef struct ModifierData { @@ -99,19 +100,19 @@ typedef struct ModifierData { int type, mode; int stackindex, pad; - char name[64]; /* MAX_NAME */ - + char name[64]; /* MAX_NAME */ + /* XXX for timing info set by caller... solve later? (ton) */ struct Scene *scene; - + char *error; } ModifierData; typedef enum { - eSubsurfModifierFlag_Incremental = (1<<0), - eSubsurfModifierFlag_DebugIncr = (1<<1), - eSubsurfModifierFlag_ControlEdges = (1<<2), - eSubsurfModifierFlag_SubsurfUv = (1<<3) + eSubsurfModifierFlag_Incremental = (1 << 0), + eSubsurfModifierFlag_DebugIncr = (1 << 1), + eSubsurfModifierFlag_ControlEdges = (1 << 2), + eSubsurfModifierFlag_SubsurfUv = (1 << 3), } SubsurfModifierFlag; /* not a real modifier */ @@ -120,7 +121,7 @@ typedef struct MappingInfoModifierData { struct Tex *texture; struct Object *map_object; - char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ + char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ int uvlayer_tmp; int texmapping; } MappingInfoModifierData; @@ -137,7 +138,7 @@ typedef struct LatticeModifierData { ModifierData modifier; struct Object *object; - char name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + char name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ float strength; char pad[4]; } LatticeModifierData; @@ -146,18 +147,20 @@ typedef struct CurveModifierData { ModifierData modifier; struct Object *object; - char name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ - short defaxis; /* axis along which curve deforms */ + char name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + short defaxis; /* axis along which curve deforms */ char pad[6]; } CurveModifierData; /* CurveModifierData->defaxis */ -#define MOD_CURVE_POSX 1 -#define MOD_CURVE_POSY 2 -#define MOD_CURVE_POSZ 3 -#define MOD_CURVE_NEGX 4 -#define MOD_CURVE_NEGY 5 -#define MOD_CURVE_NEGZ 6 +enum { + MOD_CURVE_POSX = 1, + MOD_CURVE_POSY = 2, + MOD_CURVE_POSZ = 3, + MOD_CURVE_NEGX = 4, + MOD_CURVE_NEGY = 5, + MOD_CURVE_NEGZ = 6, +}; typedef struct BuildModifierData { ModifierData modifier; @@ -169,20 +172,24 @@ typedef struct BuildModifierData { /* Mask Modifier */ typedef struct MaskModifierData { ModifierData modifier; - - struct Object *ob_arm; /* armature to use to in place of hardcoded vgroup */ - char vgroup[64]; /* name of vertex group to use to mask, MAX_VGROUP_NAME */ - - int mode; /* using armature or hardcoded vgroup */ - int flag; /* flags for various things */ + + struct Object *ob_arm; /* armature to use to in place of hardcoded vgroup */ + char vgroup[64]; /* name of vertex group to use to mask, MAX_VGROUP_NAME */ + + int mode; /* using armature or hardcoded vgroup */ + int flag; /* flags for various things */ } MaskModifierData; /* Mask Modifier -> mode */ -#define MOD_MASK_MODE_VGROUP 0 -#define MOD_MASK_MODE_ARM 1 +enum { + MOD_MASK_MODE_VGROUP = 0, + MOD_MASK_MODE_ARM = 1, +}; /* Mask Modifier -> flag */ -#define MOD_MASK_INV (1<<0) +enum { + MOD_MASK_INV = (1 << 0), +}; typedef struct ArrayModifierData { ModifierData modifier; @@ -229,18 +236,24 @@ typedef struct ArrayModifierData { } ArrayModifierData; /* ArrayModifierData->fit_type */ -#define MOD_ARR_FIXEDCOUNT 0 -#define MOD_ARR_FITLENGTH 1 -#define MOD_ARR_FITCURVE 2 +enum { + MOD_ARR_FIXEDCOUNT = 0, + MOD_ARR_FITLENGTH = 1, + MOD_ARR_FITCURVE = 2, +}; /* ArrayModifierData->offset_type */ -#define MOD_ARR_OFF_CONST (1<<0) -#define MOD_ARR_OFF_RELATIVE (1<<1) -#define MOD_ARR_OFF_OBJ (1<<2) +enum { + MOD_ARR_OFF_CONST = (1 << 0), + MOD_ARR_OFF_RELATIVE = (1 << 1), + MOD_ARR_OFF_OBJ = (1 << 2), +}; /* ArrayModifierData->flags */ -#define MOD_ARR_MERGE (1<<0) -#define MOD_ARR_MERGEFINAL (1<<1) +enum { + MOD_ARR_MERGE = (1 << 0), + MOD_ARR_MERGEFINAL = (1 << 1), +}; typedef struct MirrorModifierData { ModifierData modifier; @@ -252,14 +265,16 @@ typedef struct MirrorModifierData { } MirrorModifierData; /* MirrorModifierData->flag */ -#define MOD_MIR_CLIPPING (1<<0) -#define MOD_MIR_MIRROR_U (1<<1) -#define MOD_MIR_MIRROR_V (1<<2) -#define MOD_MIR_AXIS_X (1<<3) -#define MOD_MIR_AXIS_Y (1<<4) -#define MOD_MIR_AXIS_Z (1<<5) -#define MOD_MIR_VGROUP (1<<6) -#define MOD_MIR_NO_MERGE (1<<7) +enum { + MOD_MIR_CLIPPING = (1 << 0), + MOD_MIR_MIRROR_U = (1 << 1), + MOD_MIR_MIRROR_V = (1 << 2), + MOD_MIR_AXIS_X = (1 << 3), + MOD_MIR_AXIS_Y = (1 << 4), + MOD_MIR_AXIS_Z = (1 << 5), + MOD_MIR_VGROUP = (1 << 6), + MOD_MIR_NO_MERGE = (1 << 7), +}; typedef struct EdgeSplitModifierData { ModifierData modifier; @@ -269,8 +284,10 @@ typedef struct EdgeSplitModifierData { } EdgeSplitModifierData; /* EdgeSplitModifierData->flags */ -#define MOD_EDGESPLIT_FROMANGLE (1<<1) -#define MOD_EDGESPLIT_FROMFLAG (1<<2) +enum { + MOD_EDGESPLIT_FROMANGLE = (1 << 1), + MOD_EDGESPLIT_FROMFLAG = (1 << 2), +}; typedef struct BevelModifierData { ModifierData modifier; @@ -282,29 +299,29 @@ typedef struct BevelModifierData { short val_flags; /* flags used to interpret the bevel value */ short lim_flags; /* flags to tell the tool how to limit the bevel */ short e_flags; /* flags to direct how edge weights are applied to verts */ - float bevel_angle; /* if the MOD_BEVEL_ANGLE is set, this will be how "sharp" an edge must be before it gets beveled */ - char defgrp_name[64]; /* if the MOD_BEVEL_VWEIGHT option is set, this will be the name of the vert group, MAX_VGROUP_NAME */ + /* if the MOD_BEVEL_ANGLE is set, this will be how "sharp" an edge must be before it gets beveled */ + float bevel_angle; + /* if the MOD_BEVEL_VWEIGHT option is set, this will be the name of the vert group, MAX_VGROUP_NAME */ + char defgrp_name[64]; } BevelModifierData; -#define MOD_BEVEL_VERT (1 << 1) -// #define MOD_BEVEL_RADIUS (1 << 2) -#define MOD_BEVEL_ANGLE (1 << 3) -#define MOD_BEVEL_WEIGHT (1 << 4) -#define MOD_BEVEL_VGROUP (1 << 5) -#define MOD_BEVEL_EMIN (1 << 7) -#define MOD_BEVEL_EMAX (1 << 8) -// #define MOD_BEVEL_RUNNING (1 << 9) -// #define MOD_BEVEL_RES (1 << 10) -// #define MOD_BEVEL_EVEN (1 << 11) /* this is a new setting not related to old (trunk bmesh bevel code) but adding -// * here because they are mixed - campbell */ -// #define MOD_BEVEL_DIST (1 << 12) /* same as above */ -#define MOD_BEVEL_OVERLAP_OK (1 << 13) - - -/* Smoke modifier flags */ -#define MOD_SMOKE_TYPE_DOMAIN (1 << 0) -#define MOD_SMOKE_TYPE_FLOW (1 << 1) -#define MOD_SMOKE_TYPE_COLL (1 << 2) +enum { + MOD_BEVEL_VERT = (1 << 1), +/* MOD_BEVEL_RADIUS = (1 << 2), */ + MOD_BEVEL_ANGLE = (1 << 3), + MOD_BEVEL_WEIGHT = (1 << 4), + MOD_BEVEL_VGROUP = (1 << 5), + MOD_BEVEL_EMIN = (1 << 7), + MOD_BEVEL_EMAX = (1 << 8), +/* MOD_BEVEL_RUNNING = (1 << 9), */ +/* MOD_BEVEL_RES = (1 << 10), */ + /* This is a new setting not related to old (trunk bmesh bevel code) + * but adding here because they are mixed - campbell + */ +/* MOD_BEVEL_EVEN = (1 << 11), */ +/* MOD_BEVEL_DIST = (1 << 12), */ /* same as above */ + MOD_BEVEL_OVERLAP_OK = (1 << 13), +}; typedef struct SmokeModifierData { ModifierData modifier; @@ -316,70 +333,79 @@ typedef struct SmokeModifierData { int type; /* domain, inflow, outflow, ... */ } SmokeModifierData; +/* Smoke modifier flags */ +enum { + MOD_SMOKE_TYPE_DOMAIN = (1 << 0), + MOD_SMOKE_TYPE_FLOW = (1 << 1), + MOD_SMOKE_TYPE_COLL = (1 << 2), +}; + typedef struct DisplaceModifierData { ModifierData modifier; /* keep in sync with MappingInfoModifierData */ struct Tex *texture; struct Object *map_object; - char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ + char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ int uvlayer_tmp; int texmapping; /* end MappingInfoModifierData */ float strength; int direction; - char defgrp_name[64]; /* MAX_VGROUP_NAME */ + char defgrp_name[64]; /* MAX_VGROUP_NAME */ float midlevel; int pad; } DisplaceModifierData; /* DisplaceModifierData->direction */ enum { - MOD_DISP_DIR_X = 0, - MOD_DISP_DIR_Y = 1, - MOD_DISP_DIR_Z = 2, - MOD_DISP_DIR_NOR = 3, + MOD_DISP_DIR_X = 0, + MOD_DISP_DIR_Y = 1, + MOD_DISP_DIR_Z = 2, + MOD_DISP_DIR_NOR = 3, MOD_DISP_DIR_RGB_XYZ = 4, }; /* DisplaceModifierData->texmapping */ enum { - MOD_DISP_MAP_LOCAL = 0, + MOD_DISP_MAP_LOCAL = 0, MOD_DISP_MAP_GLOBAL = 1, MOD_DISP_MAP_OBJECT = 2, - MOD_DISP_MAP_UV = 3 + MOD_DISP_MAP_UV = 3, }; typedef struct UVProjectModifierData { ModifierData modifier; /* the objects which do the projecting */ - struct Object *projectors[10]; /* MOD_UVPROJECT_MAX */ - struct Image *image; /* the image to project */ + struct Object *projectors[10]; /* MOD_UVPROJECT_MAXPROJECTORS */ + struct Image *image; /* the image to project */ int flags; int num_projectors; float aspectx, aspecty; float scalex, scaley; - char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ + char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ int uvlayer_tmp, pad; } UVProjectModifierData; #define MOD_UVPROJECT_MAXPROJECTORS 10 /* UVProjectModifierData->flags */ -#define MOD_UVPROJECT_OVERRIDEIMAGE (1<<0) +enum { + MOD_UVPROJECT_OVERRIDEIMAGE = (1 << 0), +}; typedef struct DecimateModifierData { ModifierData modifier; float percent; /* (mode == MOD_DECIM_MODE_COLLAPSE) */ - short iter; /* (mode == MOD_DECIM_MODE_UNSUBDIV) */ + short iter; /* (mode == MOD_DECIM_MODE_UNSUBDIV) */ char delimit; /* (mode == MOD_DECIM_MODE_DISSOLVE) */ char pad; - float angle; /* (mode == MOD_DECIM_MODE_DISSOLVE) */ + float angle; /* (mode == MOD_DECIM_MODE_DISSOLVE) */ - char defgrp_name[64]; /* MAX_VGROUP_NAME */ + char defgrp_name[64]; /* MAX_VGROUP_NAME */ short flag, mode; /* runtime only */ @@ -389,20 +415,15 @@ typedef struct DecimateModifierData { enum { MOD_DECIM_FLAG_INVERT_VGROUP = (1 << 0), MOD_DECIM_FLAG_TRIANGULATE = (1 << 1), /* for collapse only. dont convert tri pairs back to quads */ - MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS = (1 << 2) /* for dissolve only. collapse all verts between 2 faces */ + MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS = (1 << 2), /* for dissolve only. collapse all verts between 2 faces */ }; enum { MOD_DECIM_MODE_COLLAPSE, MOD_DECIM_MODE_UNSUBDIV, - MOD_DECIM_MODE_DISSOLVE /* called planar in the UI */ + MOD_DECIM_MODE_DISSOLVE, /* called planar in the UI */ }; -/* Smooth modifier flags */ -#define MOD_SMOOTH_X (1<<1) -#define MOD_SMOOTH_Y (1<<2) -#define MOD_SMOOTH_Z (1<<3) - typedef struct SmoothModifierData { ModifierData modifier; float fac; @@ -411,17 +432,12 @@ typedef struct SmoothModifierData { } SmoothModifierData; -/* Cast modifier flags */ -#define MOD_CAST_X (1<<1) -#define MOD_CAST_Y (1<<2) -#define MOD_CAST_Z (1<<3) -#define MOD_CAST_USE_OB_TRANSFORM (1<<4) -#define MOD_CAST_SIZE_FROM_RADIUS (1<<5) - -/* Cast modifier projection types */ -#define MOD_CAST_TYPE_SPHERE 0 -#define MOD_CAST_TYPE_CYLINDER 1 -#define MOD_CAST_TYPE_CUBOID 2 +/* Smooth modifier flags */ +enum { + MOD_SMOOTH_X = (1 << 1), + MOD_SMOOTH_Y = (1 << 2), + MOD_SMOOTH_Z = (1 << 3), +}; typedef struct CastModifierData { ModifierData modifier; @@ -430,18 +446,26 @@ typedef struct CastModifierData { float fac; float radius; float size; - char defgrp_name[64]; /* MAX_VGROUP_NAME */ + char defgrp_name[64]; /* MAX_VGROUP_NAME */ short flag, type; } CastModifierData; -/* WaveModifierData.flag */ -#define MOD_WAVE_X (1<<1) -#define MOD_WAVE_Y (1<<2) -#define MOD_WAVE_CYCL (1<<3) -#define MOD_WAVE_NORM (1<<4) -#define MOD_WAVE_NORM_X (1<<5) -#define MOD_WAVE_NORM_Y (1<<6) -#define MOD_WAVE_NORM_Z (1<<7) +/* Cast modifier flags */ +enum { + /* And what bout (1 << 0) flag? ;) */ + MOD_CAST_X = (1 << 1), + MOD_CAST_Y = (1 << 2), + MOD_CAST_Z = (1 << 3), + MOD_CAST_USE_OB_TRANSFORM = (1 << 4), + MOD_CAST_SIZE_FROM_RADIUS = (1 << 5), +}; + +/* Cast modifier projection types */ +enum { + MOD_CAST_TYPE_SPHERE = 0, + MOD_CAST_TYPE_CYLINDER = 1, + MOD_CAST_TYPE_CUBOID = 2, +}; typedef struct WaveModifierData { ModifierData modifier; @@ -449,13 +473,13 @@ typedef struct WaveModifierData { /* keep in sync with MappingInfoModifierData */ struct Tex *texture; struct Object *map_object; - char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ + char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ int uvlayer_tmp; int texmapping; /* end MappingInfoModifierData */ struct Object *objectcenter; - char defgrp_name[64]; /* MAX_VGROUP_NAME */ + char defgrp_name[64]; /* MAX_VGROUP_NAME */ short flag, pad; @@ -466,30 +490,42 @@ typedef struct WaveModifierData { float pad1; } WaveModifierData; +/* WaveModifierData.flag */ +enum { + /* And what bout (1 << 0) flag? ;) */ + MOD_WAVE_X = (1 << 1), + MOD_WAVE_Y = (1 << 2), + MOD_WAVE_CYCL = (1 << 3), + MOD_WAVE_NORM = (1 << 4), + MOD_WAVE_NORM_X = (1 << 5), + MOD_WAVE_NORM_Y = (1 << 6), + MOD_WAVE_NORM_Z = (1 << 7), +}; + typedef struct ArmatureModifierData { ModifierData modifier; - short deformflag, multi; /* deformflag replaces armature->deformflag */ + short deformflag, multi; /* deformflag replaces armature->deformflag */ int pad2; struct Object *object; - float *prevCos; /* stored input of previous modifier, for vertexgroup blending */ - char defgrp_name[64]; /* MAX_VGROUP_NAME */ + float *prevCos; /* stored input of previous modifier, for vertexgroup blending */ + char defgrp_name[64]; /* MAX_VGROUP_NAME */ } ArmatureModifierData; typedef struct HookModifierData { ModifierData modifier; struct Object *object; - char subtarget[64]; /* optional name of bone target, MAX_ID_NAME-2 */ - - float parentinv[4][4]; /* matrix making current transform unmodified */ - float cent[3]; /* visualization of hook */ - float falloff; /* if not zero, falloff is distance where influence zero */ - - int *indexar; /* if NULL, it's using vertexgroup */ + char subtarget[64]; /* optional name of bone target, MAX_ID_NAME-2 */ + + float parentinv[4][4]; /* matrix making current transform unmodified */ + float cent[3]; /* visualization of hook */ + float falloff; /* if not zero, falloff is distance where influence zero */ + + int *indexar; /* if NULL, it's using vertexgroup */ int totindex; float force; - char name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + char name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ } HookModifierData; typedef struct SoftbodyModifierData { @@ -497,36 +533,36 @@ typedef struct SoftbodyModifierData { } SoftbodyModifierData; typedef struct ClothModifierData { - ModifierData modifier; + ModifierData modifier; - struct Scene *scene; /* the context, time etc is here */ - struct Cloth *clothObject; /* The internal data structure for cloth. */ - struct ClothSimSettings *sim_parms; /* definition is in DNA_cloth_types.h */ + struct Scene *scene; /* the context, time etc is here */ + struct Cloth *clothObject; /* The internal data structure for cloth. */ + struct ClothSimSettings *sim_parms; /* definition is in DNA_cloth_types.h */ struct ClothCollSettings *coll_parms; /* definition is in DNA_cloth_types.h */ - struct PointCache *point_cache; /* definition is in DNA_object_force.h */ + struct PointCache *point_cache; /* definition is in DNA_object_force.h */ struct ListBase ptcaches; } ClothModifierData; typedef struct CollisionModifierData { - ModifierData modifier; - - struct MVert *x; /* position at the beginning of the frame */ - struct MVert *xnew; /* position at the end of the frame */ - struct MVert *xold; /* unsued atm, but was discussed during sprint */ + ModifierData modifier; + + struct MVert *x; /* position at the beginning of the frame */ + struct MVert *xnew; /* position at the end of the frame */ + struct MVert *xold; /* unused atm, but was discussed during sprint */ struct MVert *current_xnew; /* new position at the actual inter-frame step */ - struct MVert *current_x; /* position at the actual inter-frame step */ - struct MVert *current_v; /* (xnew - x) at the actual inter-frame step */ - - struct MFace *mfaces; /* object face data */ - + struct MVert *current_x; /* position at the actual inter-frame step */ + struct MVert *current_v; /* (xnew - x) at the actual inter-frame step */ + + struct MFace *mfaces; /* object face data */ + unsigned int numverts; unsigned int numfaces; - float time_x, time_xnew; /* cfra time of modifier */ - struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */ + float time_x, time_xnew; /* cfra time of modifier */ + struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */ } CollisionModifierData; typedef struct SurfaceModifierData { - ModifierData modifier; + ModifierData modifier; struct MVert *x; /* old position */ struct MVert *v; /* velocity */ @@ -538,11 +574,6 @@ typedef struct SurfaceModifierData { int cfra, numverts; } SurfaceModifierData; -typedef enum { - eBooleanModifierOp_Intersect = 0, - eBooleanModifierOp_Union = 1, - eBooleanModifierOp_Difference = 2, -} BooleanModifierOp; typedef struct BooleanModifierData { ModifierData modifier; @@ -550,11 +581,11 @@ typedef struct BooleanModifierData { int operation, pad; } BooleanModifierData; -#define MOD_MDEF_INVERT_VGROUP (1<<0) -#define MOD_MDEF_DYNAMIC_BIND (1<<1) - -#define MOD_MDEF_VOLUME 0 -#define MOD_MDEF_SURFACE 1 +typedef enum { + eBooleanModifierOp_Intersect = 0, + eBooleanModifierOp_Union = 1, + eBooleanModifierOp_Difference = 2, +} BooleanModifierOp; typedef struct MDefInfluence { int vertex; @@ -569,45 +600,49 @@ typedef struct MDefCell { typedef struct MeshDeformModifierData { ModifierData modifier; - struct Object *object; /* mesh object */ - char defgrp_name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + struct Object *object; /* mesh object */ + char defgrp_name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ short gridsize, flag, mode, pad; /* result of static binding */ - MDefInfluence *bindinfluences; /* influences */ - int *bindoffsets; /* offsets into influences array */ - float *bindcagecos; /* coordinates that cage was bound with */ - int totvert, totcagevert; /* total vertices in mesh and cage */ + MDefInfluence *bindinfluences; /* influences */ + int *bindoffsets; /* offsets into influences array */ + float *bindcagecos; /* coordinates that cage was bound with */ + int totvert, totcagevert; /* total vertices in mesh and cage */ /* result of dynamic binding */ - MDefCell *dyngrid; /* grid with dynamic binding cell points */ - MDefInfluence *dyninfluences; /* dynamic binding vertex influences */ - int *dynverts, *pad2; /* is this vertex bound or not? */ - int dyngridsize; /* size of the dynamic bind grid */ - int totinfluence; /* total number of vertex influences */ - float dyncellmin[3]; /* offset of the dynamic bind grid */ - float dyncellwidth; /* width of dynamic bind cell */ - float bindmat[4][4]; /* matrix of cage at binding time */ + MDefCell *dyngrid; /* grid with dynamic binding cell points */ + MDefInfluence *dyninfluences; /* dynamic binding vertex influences */ + int *dynverts, *pad2; /* is this vertex bound or not? */ + int dyngridsize; /* size of the dynamic bind grid */ + int totinfluence; /* total number of vertex influences */ + float dyncellmin[3]; /* offset of the dynamic bind grid */ + float dyncellwidth; /* width of dynamic bind cell */ + float bindmat[4][4]; /* matrix of cage at binding time */ /* deprecated storage */ - float *bindweights; /* deprecated inefficient storage */ - float *bindcos; /* deprecated storage of cage coords */ + float *bindweights; /* deprecated inefficient storage */ + float *bindcos; /* deprecated storage of cage coords */ /* runtime */ - void (*bindfunc)(struct Scene *scene, - struct MeshDeformModifierData *mmd, - float *vertexcos, int totvert, float cagemat[4][4]); + void (*bindfunc)(struct Scene *scene, struct MeshDeformModifierData *mmd, + float *vertexcos, int totvert, float cagemat[4][4]); } MeshDeformModifierData; -typedef enum { - eParticleSystemFlag_Pars = (1<<0), - eParticleSystemFlag_psys_updated = (1<<1), - eParticleSystemFlag_file_loaded = (1<<2), -} ParticleSystemModifierFlag; +enum { + MOD_MDEF_INVERT_VGROUP = (1 << 0), + MOD_MDEF_DYNAMIC_BIND = (1 << 1), +}; + +enum { + MOD_MDEF_VOLUME = 0, + MOD_MDEF_SURFACE = 1, +}; typedef struct ParticleSystemModifierData { ModifierData modifier; + struct ParticleSystem *psys; struct DerivedMesh *dm; int totdmvert, totdmedge, totdmface; @@ -615,38 +650,46 @@ typedef struct ParticleSystemModifierData { } ParticleSystemModifierData; typedef enum { - eParticleInstanceFlag_Parents = (1<<0), - eParticleInstanceFlag_Children = (1<<1), - eParticleInstanceFlag_Path = (1<<2), - eParticleInstanceFlag_Unborn = (1<<3), - eParticleInstanceFlag_Alive = (1<<4), - eParticleInstanceFlag_Dead = (1<<5), - eParticleInstanceFlag_KeepShape = (1<<6), - eParticleInstanceFlag_UseSize = (1<<7), + eParticleSystemFlag_Pars = (1 << 0), + eParticleSystemFlag_psys_updated = (1 << 1), + eParticleSystemFlag_file_loaded = (1 << 2), +} ParticleSystemModifierFlag; + +typedef enum { + eParticleInstanceFlag_Parents = (1 << 0), + eParticleInstanceFlag_Children = (1 << 1), + eParticleInstanceFlag_Path = (1 << 2), + eParticleInstanceFlag_Unborn = (1 << 3), + eParticleInstanceFlag_Alive = (1 << 4), + eParticleInstanceFlag_Dead = (1 << 5), + eParticleInstanceFlag_KeepShape = (1 << 6), + eParticleInstanceFlag_UseSize = (1 << 7), } ParticleInstanceModifierFlag; typedef struct ParticleInstanceModifierData { ModifierData modifier; + struct Object *ob; short psys, flag, axis, rt; float position, random_position; } ParticleInstanceModifierData; typedef enum { - eExplodeFlag_CalcFaces = (1<<0), - eExplodeFlag_PaSize = (1<<1), - eExplodeFlag_EdgeCut = (1<<2), - eExplodeFlag_Unborn = (1<<3), - eExplodeFlag_Alive = (1<<4), - eExplodeFlag_Dead = (1<<5), + eExplodeFlag_CalcFaces = (1 << 0), + eExplodeFlag_PaSize = (1 << 1), + eExplodeFlag_EdgeCut = (1 << 2), + eExplodeFlag_Unborn = (1 << 3), + eExplodeFlag_Alive = (1 << 4), + eExplodeFlag_Dead = (1 << 5), } ExplodeModifierFlag; typedef struct ExplodeModifierData { ModifierData modifier; + int *facepa; short flag, vgroup; float protect; - char uvname[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ + char uvname[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ } ExplodeModifierData; typedef struct MultiresModifierData { @@ -657,83 +700,93 @@ typedef struct MultiresModifierData { } MultiresModifierData; typedef enum { - eMultiresModifierFlag_ControlEdges = (1<<0), - eMultiresModifierFlag_PlainUv = (1<<1), + eMultiresModifierFlag_ControlEdges = (1 << 0), + eMultiresModifierFlag_PlainUv = (1 << 1), } MultiresModifierFlag; typedef struct FluidsimModifierData { ModifierData modifier; - - struct FluidsimSettings *fss; /* definition is in DNA_object_fluidsim.h */ - struct PointCache *point_cache; /* definition is in DNA_object_force.h */ + + struct FluidsimSettings *fss; /* definition is in DNA_object_fluidsim.h */ + struct PointCache *point_cache; /* definition is in DNA_object_force.h */ } FluidsimModifierData; typedef struct ShrinkwrapModifierData { ModifierData modifier; - struct Object *target; /* shrink target */ + struct Object *target; /* shrink target */ struct Object *auxTarget; /* additional shrink target */ - char vgroup_name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ - float keepDist; /* distance offset to keep from mesh/projection point */ - short shrinkType; /* shrink type projection */ - short shrinkOpts; /* shrink options */ - float projLimit; /* limit the projection ray cast */ - char projAxis; /* axis to project over */ - - /* - * if using projection over vertex normal this controls the - * the level of subsurface that must be done before getting the - * vertex coordinates and normal + char vgroup_name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + float keepDist; /* distance offset to keep from mesh/projection point */ + short shrinkType; /* shrink type projection */ + short shrinkOpts; /* shrink options */ + float projLimit; /* limit the projection ray cast */ + char projAxis; /* axis to project over */ + + /* If using projection over vertex normal this controls the level of subsurface that must be done + * before getting the vertex coordinates and normal */ char subsurfLevels; char pad[2]; - } ShrinkwrapModifierData; /* Shrinkwrap->shrinkType */ -#define MOD_SHRINKWRAP_NEAREST_SURFACE 0 -#define MOD_SHRINKWRAP_PROJECT 1 -#define MOD_SHRINKWRAP_NEAREST_VERTEX 2 +enum { + MOD_SHRINKWRAP_NEAREST_SURFACE = 0, + MOD_SHRINKWRAP_PROJECT = 1, + MOD_SHRINKWRAP_NEAREST_VERTEX = 2, +}; /* Shrinkwrap->shrinkOpts */ -#define MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR (1<<0) /* allow shrinkwrap to move the vertex in the positive direction of axis */ -#define MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR (1<<1) /* allow shrinkwrap to move the vertex in the negative direction of axis */ +enum { + /* allow shrinkwrap to move the vertex in the positive direction of axis */ + MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR = (1 << 0), + /* allow shrinkwrap to move the vertex in the negative direction of axis */ + MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR = (1 << 1), -#define MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (1<<3) /* ignore vertex moves if a vertex ends projected on a front face of the target */ -#define MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (1<<4) /* ignore vertex moves if a vertex ends projected on a back face of the target */ + /* ignore vertex moves if a vertex ends projected on a front face of the target */ + MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE = (1 << 3), + /* ignore vertex moves if a vertex ends projected on a back face of the target */ + MOD_SHRINKWRAP_CULL_TARGET_BACKFACE = (1 << 4), -#define MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE (1<<5) /* distance is measure to the front face of the target */ + MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE = (1 << 5), /* distance is measure to the front face of the target */ +}; -#define MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS (1<<0) -#define MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS (1<<1) -#define MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS (1<<2) -#define MOD_SHRINKWRAP_PROJECT_OVER_NORMAL 0 /* projection over normal is used if no axis is selected */ +/* Shrinkwrap->projAxis */ +enum { + MOD_SHRINKWRAP_PROJECT_OVER_NORMAL = 0, /* projection over normal is used if no axis is selected */ + MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS = (1 << 0), + MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS = (1 << 1), + MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS = (1 << 2), +}; typedef struct SimpleDeformModifierData { ModifierData modifier; - struct Object *origin; /* object to control the origin of modifier space coordinates */ - char vgroup_name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ - float factor; /* factors to control simple deforms */ - float limit[2]; /* lower and upper limit */ + struct Object *origin; /* object to control the origin of modifier space coordinates */ + char vgroup_name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + float factor; /* factors to control simple deforms */ + float limit[2]; /* lower and upper limit */ - char mode; /* deform function */ - char axis; /* lock axis (for taper and strech) */ + char mode; /* deform function */ + char axis; /* lock axis (for taper and strech) */ char pad[2]; } SimpleDeformModifierData; -#define MOD_SIMPLEDEFORM_MODE_TWIST 1 -#define MOD_SIMPLEDEFORM_MODE_BEND 2 -#define MOD_SIMPLEDEFORM_MODE_TAPER 3 -#define MOD_SIMPLEDEFORM_MODE_STRETCH 4 - -#define MOD_SIMPLEDEFORM_LOCK_AXIS_X (1<<0) -#define MOD_SIMPLEDEFORM_LOCK_AXIS_Y (1<<1) +enum { + MOD_SIMPLEDEFORM_MODE_TWIST = 1, + MOD_SIMPLEDEFORM_MODE_BEND = 2, + MOD_SIMPLEDEFORM_MODE_TAPER = 3, + MOD_SIMPLEDEFORM_MODE_STRETCH = 4, +}; -#define MOD_UVPROJECT_MAX 10 +enum { + MOD_SIMPLEDEFORM_LOCK_AXIS_X = (1 << 0), + MOD_SIMPLEDEFORM_LOCK_AXIS_Y = (1 << 1), +}; typedef struct ShapeKeyModifierData { ModifierData modifier; @@ -742,11 +795,12 @@ typedef struct ShapeKeyModifierData { typedef struct SolidifyModifierData { ModifierData modifier; - char defgrp_name[64]; /* name of vertex group to use, MAX_VGROUP_NAME */ - float offset; /* new surface offset level*/ - float offset_fac; /* midpoint of the offset */ - float offset_fac_vg; /* factor for the minimum weight to use when vgroups are used, avoids 0.0 weights giving duplicate geometry */ - float offset_clamp; /* clamp offset based on surrounding geometry */ + char defgrp_name[64]; /* name of vertex group to use, MAX_VGROUP_NAME */ + float offset; /* new surface offset level*/ + float offset_fac; /* midpoint of the offset */ + /* factor for the minimum weight to use when vgroups are used, avoids 0.0 weights giving duplicate geometry */ + float offset_fac_vg; + float offset_clamp; /* clamp offset based on surrounding geometry */ float pad; float crease_inner; float crease_outer; @@ -756,98 +810,107 @@ typedef struct SolidifyModifierData { short mat_ofs_rim; } SolidifyModifierData; -#define MOD_SOLIDIFY_RIM (1 << 0) -#define MOD_SOLIDIFY_EVEN (1 << 1) -#define MOD_SOLIDIFY_NORMAL_CALC (1 << 2) -#define MOD_SOLIDIFY_VGROUP_INV (1 << 3) -#define MOD_SOLIDIFY_RIM_MATERIAL (1 << 4) /* deprecated, used in do_versions */ -#define MOD_SOLIDIFY_FLIP (1 << 5) +enum { + MOD_SOLIDIFY_RIM = (1 << 0), + MOD_SOLIDIFY_EVEN = (1 << 1), + MOD_SOLIDIFY_NORMAL_CALC = (1 << 2), + MOD_SOLIDIFY_VGROUP_INV = (1 << 3), + MOD_SOLIDIFY_RIM_MATERIAL = (1 << 4), /* deprecated, used in do_versions */ + MOD_SOLIDIFY_FLIP = (1 << 5), +}; typedef struct ScrewModifierData { ModifierData modifier; + struct Object *ob_axis; - int steps; - int render_steps; - int iter; - float screw_ofs; - float angle; - short axis; - short flag; + int steps; + int render_steps; + int iter; + float screw_ofs; + float angle; + short axis; + short flag; } ScrewModifierData; -#define MOD_SCREW_NORMAL_FLIP (1 << 0) -#define MOD_SCREW_NORMAL_CALC (1 << 1) -#define MOD_SCREW_OBJECT_OFFSET (1 << 2) -// #define MOD_SCREW_OBJECT_ANGLE (1 << 4) -#define MOD_SCREW_SMOOTH_SHADING (1 << 5) +enum { + MOD_SCREW_NORMAL_FLIP = (1 << 0), + MOD_SCREW_NORMAL_CALC = (1 << 1), + MOD_SCREW_OBJECT_OFFSET = (1 << 2), +/* MOD_SCREW_OBJECT_ANGLE = (1 << 4), */ + MOD_SCREW_SMOOTH_SHADING = (1 << 5), +}; typedef struct OceanModifierData { ModifierData modifier; - + struct Ocean *ocean; struct OceanCache *oceancache; - int resolution; - int spatial_size; - - float wind_velocity; - - float damp; - float smallest_wave; - float depth; - - float wave_alignment; - float wave_direction; - float wave_scale; - - float chop_amount; - float foam_coverage; - float time; - - int bakestart; - int bakeend; - - char cachepath[1024]; // FILE_MAX - char foamlayername[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ - char cached; - char geometry_mode; + int resolution; + int spatial_size; - char flag; - char refresh; + float wind_velocity; - short repeat_x; - short repeat_y; + float damp; + float smallest_wave; + float depth; - int seed; + float wave_alignment; + float wave_direction; + float wave_scale; - float size; - - float foam_fade; + float chop_amount; + float foam_coverage; + float time; - int pad; + int bakestart; + int bakeend; -} OceanModifierData; + char cachepath[1024]; /* FILE_MAX */ + char foamlayername[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ + char cached; + char geometry_mode; + + char flag; + char refresh; + + short repeat_x; + short repeat_y; + + int seed; -#define MOD_OCEAN_GEOM_GENERATE 0 -#define MOD_OCEAN_GEOM_DISPLACE 1 -#define MOD_OCEAN_GEOM_SIM_ONLY 2 + float size; + + float foam_fade; -#define MOD_OCEAN_REFRESH_RESET 1 -#define MOD_OCEAN_REFRESH_SIM 2 -#define MOD_OCEAN_REFRESH_ADD 4 -#define MOD_OCEAN_REFRESH_CLEAR_CACHE 8 -#define MOD_OCEAN_REFRESH_TOPOLOGY 16 + int pad; +} OceanModifierData; -#define MOD_OCEAN_GENERATE_FOAM 1 -#define MOD_OCEAN_GENERATE_NORMALS 2 +enum { + MOD_OCEAN_GEOM_GENERATE = 0, + MOD_OCEAN_GEOM_DISPLACE = 1, + MOD_OCEAN_GEOM_SIM_ONLY = 2, +}; +enum { + MOD_OCEAN_REFRESH_RESET = (1 << 0), + MOD_OCEAN_REFRESH_SIM = (1 << 1), + MOD_OCEAN_REFRESH_ADD = (1 << 2), + MOD_OCEAN_REFRESH_CLEAR_CACHE = (1 << 3), + MOD_OCEAN_REFRESH_TOPOLOGY = (1 << 4), +}; + +enum { + MOD_OCEAN_GENERATE_FOAM = (1 << 0), + MOD_OCEAN_GENERATE_NORMALS = (1 << 1), +}; typedef struct WarpModifierData { ModifierData modifier; /* keep in sync with MappingInfoModifierData */ struct Tex *texture; struct Object *map_object; - char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ + char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ int uvlayer_tmp; int texmapping; /* end MappingInfoModifierData */ @@ -855,7 +918,7 @@ typedef struct WarpModifierData { struct Object *object_from; struct Object *object_to; struct CurveMapping *curfalloff; - char defgrp_name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + char defgrp_name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ float strength; float falloff_radius; char flag; /* not used yet */ @@ -866,189 +929,175 @@ typedef struct WarpModifierData { #define MOD_WARP_VOLUME_PRESERVE 1 typedef enum { - eWarp_Falloff_None = 0, - eWarp_Falloff_Curve = 1, - eWarp_Falloff_Sharp = 2, /* PROP_SHARP */ - eWarp_Falloff_Smooth = 3, /* PROP_SMOOTH */ - eWarp_Falloff_Root = 4, /* PROP_ROOT */ - eWarp_Falloff_Linear = 5, /* PROP_LIN */ - eWarp_Falloff_Const = 6, /* PROP_CONST */ - eWarp_Falloff_Sphere = 7, /* PROP_SPHERE */ + eWarp_Falloff_None = 0, + eWarp_Falloff_Curve = 1, + eWarp_Falloff_Sharp = 2, /* PROP_SHARP */ + eWarp_Falloff_Smooth = 3, /* PROP_SMOOTH */ + eWarp_Falloff_Root = 4, /* PROP_ROOT */ + eWarp_Falloff_Linear = 5, /* PROP_LIN */ + eWarp_Falloff_Const = 6, /* PROP_CONST */ + eWarp_Falloff_Sphere = 7, /* PROP_SPHERE */ /* PROP_RANDOM not used */ } WarpModifierFalloff; typedef struct WeightVGEditModifierData { ModifierData modifier; - /* Note: I tried to keep everything logically ordered - provided the - * alignment constraints... */ + char defgrp_name[64]; /* Name of vertex group to edit. MAX_VGROUP_NAME. */ - char defgrp_name[64]; /* Name of vertex group to edit. MAX_VGROUP_NAME. */ - - short edit_flags; /* Using MOD_WVG_EDIT_* flags. */ - short falloff_type; /* Using MOD_WVG_MAPPING_* defines. */ - float default_weight; /* Weight for vertices not in vgroup. */ + short edit_flags; /* Using MOD_WVG_EDIT_* flags. */ + short falloff_type; /* Using MOD_WVG_MAPPING_* defines. */ + float default_weight; /* Weight for vertices not in vgroup. */ /* Mapping stuff. */ struct CurveMapping *cmap_curve; /* The custom mapping curve! */ /* The add/remove vertices weight thresholds. */ - float add_threshold, rem_threshold; + float add_threshold, rem_threshold; /* Masking options. */ - float mask_constant; /* The global "influence", if no vgroup nor tex is used as mask. */ - /* Name of mask vertex group from which to get weight factors. */ - char mask_defgrp_name[64]; /* MAX_VGROUP_NAME */ + float mask_constant; /* The global "influence", if no vgroup nor tex is used as mask. */ + char mask_defgrp_name[64]; /* Name of mask vertex group from which to get weight factors. MAX_VGROUP_NAME */ /* Texture masking. */ - int mask_tex_use_channel; /* Which channel to use as weightf. */ + int mask_tex_use_channel; /* Which channel to use as weightf. */ struct Tex *mask_texture; /* The texture. */ struct Object *mask_tex_map_obj; /* Name of the map object. */ - /* How to map the texture (using MOD_DISP_MAP_* constants). */ - int mask_tex_mapping; - char mask_tex_uvlayer_name[64]; /* Name of the UV map. MAX_CUSTOMDATA_LAYER_NAME */ + int mask_tex_mapping; /* How to map the texture (using MOD_DISP_MAP_* enums). */ + char mask_tex_uvlayer_name[64]; /* Name of the UV map. MAX_CUSTOMDATA_LAYER_NAME */ /* Padding... */ int pad_i1; } WeightVGEditModifierData; /* WeightVGEdit flags. */ -/* Use parametric mapping. */ -//#define MOD_WVG_EDIT_MAP (1 << 0) -/* Use curve mapping. */ -//#define MOD_WVG_EDIT_CMAP (1 << 1) -/* Reverse weights (in the [0.0, 1.0] standard range). */ -//#define MOD_WVG_EDIT_REVERSE_WEIGHTS (1 << 2) -/* Add vertices with higher weight than threshold to vgroup. */ -#define MOD_WVG_EDIT_ADD2VG (1 << 3) -/* Remove vertices with lower weight than threshold from vgroup. */ -#define MOD_WVG_EDIT_REMFVG (1 << 4) -/* Clamp weights. */ -//#define MOD_WVG_EDIT_CLAMP (1 << 5) +enum { + /* (1 << 0), (1 << 1) and (1 << 2) are free for future use! */ + MOD_WVG_EDIT_ADD2VG = (1 << 3), /* Add vertices with higher weight than threshold to vgroup. */ + MOD_WVG_EDIT_REMFVG = (1 << 4), /* Remove vertices with lower weight than threshold from vgroup. */ +}; typedef struct WeightVGMixModifierData { ModifierData modifier; - /* XXX Note: I tried to keep everything logically ordered - provided the - * alignment constraints... */ + char defgrp_name_a[64]; /* Name of vertex group to modify/weight. MAX_VGROUP_NAME. */ + char defgrp_name_b[64]; /* Name of other vertex group to mix in. MAX_VGROUP_NAME. */ + float default_weight_a; /* Default weight value for first vgroup. */ + float default_weight_b; /* Default weight value to mix in. */ + char mix_mode; /* How second vgroups weights affect first ones */ + char mix_set; /* What vertices to affect. */ - char defgrp_name_a[64]; /* Name of vertex group to modify/weight. MAX_VGROUP_NAME. */ - char defgrp_name_b[64]; /* Name of other vertex group to mix in. MAX_VGROUP_NAME. */ - float default_weight_a; /* Default weight value for first vgroup. */ - float default_weight_b; /* Default weight value to mix in. */ - char mix_mode; /* How second vgroups weights affect first ones */ - char mix_set; /* What vertices to affect. */ - - char pad_c1[6]; + char pad_c1[6]; /* Masking options. */ - float mask_constant; /* The global "influence", if no vgroup nor tex is used as mask. */ - /* Name of mask vertex group from which to get weight factors. */ - char mask_defgrp_name[64]; /* MAX_VGROUP_NAME */ + float mask_constant; /* The global "influence", if no vgroup nor tex is used as mask. */ + char mask_defgrp_name[64]; /* Name of mask vertex group from which to get weight factors. MAX_VGROUP_NAME */ /* Texture masking. */ - int mask_tex_use_channel; /* Which channel to use as weightf. */ - struct Tex *mask_texture; /* The texture. */ - struct Object *mask_tex_map_obj; /* Name of the map object. */ - int mask_tex_mapping; /* How to map the texture! */ - char mask_tex_uvlayer_name[64]; /* Name of the UV map. MAX_CUSTOMDATA_LAYER_NAME. */ + int mask_tex_use_channel; /* Which channel to use as weightf. */ + struct Tex *mask_texture; /* The texture. */ + struct Object *mask_tex_map_obj; /* Name of the map object. */ + int mask_tex_mapping; /* How to map the texture! */ + char mask_tex_uvlayer_name[64]; /* Name of the UV map. MAX_CUSTOMDATA_LAYER_NAME. */ /* Padding... */ int pad_i1; } WeightVGMixModifierData; /* How second vgroup's weights affect first ones. */ -#define MOD_WVG_MIX_SET 1 /* Second weights replace weights. */ -#define MOD_WVG_MIX_ADD 2 /* Second weights are added to weights. */ -#define MOD_WVG_MIX_SUB 3 /* Second weights are subtracted from weights. */ -#define MOD_WVG_MIX_MUL 4 /* Second weights are multiplied with weights. */ -#define MOD_WVG_MIX_DIV 5 /* Second weights divide weights. */ -#define MOD_WVG_MIX_DIF 6 /* Difference between second weights and weights. */ -#define MOD_WVG_MIX_AVG 7 /* Average of both weights. */ +enum { + MOD_WVG_MIX_SET = 1, /* Second weights replace weights. */ + MOD_WVG_MIX_ADD = 2, /* Second weights are added to weights. */ + MOD_WVG_MIX_SUB = 3, /* Second weights are subtracted from weights. */ + MOD_WVG_MIX_MUL = 4, /* Second weights are multiplied with weights. */ + MOD_WVG_MIX_DIV = 5, /* Second weights divide weights. */ + MOD_WVG_MIX_DIF = 6, /* Difference between second weights and weights. */ + MOD_WVG_MIX_AVG = 7, /* Average of both weights. */ +}; /* What vertices to affect. */ -#define MOD_WVG_SET_ALL 1 /* Affect all vertices. */ -#define MOD_WVG_SET_A 2 /* Affect only vertices in first vgroup. */ -#define MOD_WVG_SET_B 3 /* Affect only vertices in second vgroup. */ -#define MOD_WVG_SET_OR 4 /* Affect only vertices in one vgroup or the other. */ -#define MOD_WVG_SET_AND 5 /* Affect only vertices in both vgroups. */ +enum { + MOD_WVG_SET_ALL = 1, /* Affect all vertices. */ + MOD_WVG_SET_A = 2, /* Affect only vertices in first vgroup. */ + MOD_WVG_SET_B = 3, /* Affect only vertices in second vgroup. */ + MOD_WVG_SET_OR = 4, /* Affect only vertices in one vgroup or the other. */ + MOD_WVG_SET_AND = 5, /* Affect only vertices in both vgroups. */ +}; typedef struct WeightVGProximityModifierData { ModifierData modifier; - /* Note: I tried to keep everything logically ordered - provided the - * alignment constraints... */ - - char defgrp_name[64]; /* Name of vertex group to modify/weight. MAX_VGROUP_NAME. */ + char defgrp_name[64]; /* Name of vertex group to modify/weight. MAX_VGROUP_NAME. */ /* Proximity modes. */ - int proximity_mode; - int proximity_flags; + int proximity_mode; + int proximity_flags; /* Target object from which to calculate vertices distances. */ struct Object *proximity_ob_target; /* Masking options. */ - float mask_constant; /* The global "influence", if no vgroup nor tex is used as mask. */ - /* Name of mask vertex group from which to get weight factors. */ - char mask_defgrp_name[64]; /* MAX_VGROUP_NAME */ + float mask_constant; /* The global "influence", if no vgroup nor tex is used as mask. */ + char mask_defgrp_name[64]; /* Name of mask vertex group from which to get weight factors. MAX_VGROUP_NAME */ /* Texture masking. */ - int mask_tex_use_channel; /* Which channel to use as weightf. */ - struct Tex *mask_texture; /* The texture. */ - struct Object *mask_tex_map_obj; /* Name of the map object. */ - int mask_tex_mapping; /* How to map the texture! */ - char mask_tex_uvlayer_name[64]; /* Name of the UV Map. MAX_CUSTOMDATA_LAYER_NAME. */ + int mask_tex_use_channel; /* Which channel to use as weightf. */ + struct Tex *mask_texture; /* The texture. */ + struct Object *mask_tex_map_obj; /* Name of the map object. */ + int mask_tex_mapping; /* How to map the texture! */ + char mask_tex_uvlayer_name[64]; /* Name of the UV Map. MAX_CUSTOMDATA_LAYER_NAME. */ - float min_dist, max_dist; /* Distances mapping to 0.0/1.0 weights. */ + float min_dist, max_dist; /* Distances mapping to 0.0/1.0 weights. */ /* Put here to avoid breaking existing struct... */ - short falloff_type; /* Using MOD_WVG_MAPPING_* defines. */ + short falloff_type; /* Using MOD_WVG_MAPPING_* enums. */ /* Padding... */ short pad_s1; } WeightVGProximityModifierData; /* Modes of proximity weighting. */ -/* Dist from target object to affected object. */ -#define MOD_WVG_PROXIMITY_OBJECT 1 /* source vertex to other location */ -/* Dist from target object to vertex. */ -#define MOD_WVG_PROXIMITY_GEOMETRY 2 /* source vertex to other geometry */ +enum { + MOD_WVG_PROXIMITY_OBJECT = 1, /* source vertex to other location */ + MOD_WVG_PROXIMITY_GEOMETRY = 2, /* source vertex to other geometry */ +}; /* Flags options for proximity weighting. */ -/* Use nearest vertices of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */ -#define MOD_WVG_PROXIMITY_GEOM_VERTS (1 << 0) -/* Use nearest edges of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */ -#define MOD_WVG_PROXIMITY_GEOM_EDGES (1 << 1) -/* Use nearest faces of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */ -#define MOD_WVG_PROXIMITY_GEOM_FACES (1 << 2) +enum { + /* Use nearest vertices of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */ + MOD_WVG_PROXIMITY_GEOM_VERTS = (1 << 0), + /* Use nearest edges of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */ + MOD_WVG_PROXIMITY_GEOM_EDGES = (1 << 1), + /* Use nearest faces of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */ + MOD_WVG_PROXIMITY_GEOM_FACES = (1 << 2), +}; /* Defines common to all WeightVG modifiers. */ /* Mapping modes. */ -#define MOD_WVG_MAPPING_NONE 0 -#define MOD_WVG_MAPPING_CURVE 1 -#define MOD_WVG_MAPPING_SHARP 2 /* PROP_SHARP */ -#define MOD_WVG_MAPPING_SMOOTH 3 /* PROP_SMOOTH */ -#define MOD_WVG_MAPPING_ROOT 4 /* PROP_ROOT */ -/* PROP_LIN not used (same as NONE, here...). */ -/* PROP_CONST not used. */ -#define MOD_WVG_MAPPING_SPHERE 7 /* PROP_SPHERE */ -#define MOD_WVG_MAPPING_RANDOM 8 /* PROP_RANDOM */ -#define MOD_WVG_MAPPING_STEP 9 /* Median Step. */ +enum { + MOD_WVG_MAPPING_NONE = 0, + MOD_WVG_MAPPING_CURVE = 1, + MOD_WVG_MAPPING_SHARP = 2, /* PROP_SHARP */ + MOD_WVG_MAPPING_SMOOTH = 3, /* PROP_SMOOTH */ + MOD_WVG_MAPPING_ROOT = 4, /* PROP_ROOT */ + /* PROP_LIN not used (same as NONE, here...). */ + /* PROP_CONST not used. */ + MOD_WVG_MAPPING_SPHERE = 7, /* PROP_SPHERE */ + MOD_WVG_MAPPING_RANDOM = 8, /* PROP_RANDOM */ + MOD_WVG_MAPPING_STEP = 9, /* Median Step. */ +}; /* Tex channel to be used as mask. */ -#define MOD_WVG_MASK_TEX_USE_INT 1 -#define MOD_WVG_MASK_TEX_USE_RED 2 -#define MOD_WVG_MASK_TEX_USE_GREEN 3 -#define MOD_WVG_MASK_TEX_USE_BLUE 4 -#define MOD_WVG_MASK_TEX_USE_HUE 5 -#define MOD_WVG_MASK_TEX_USE_SAT 6 -#define MOD_WVG_MASK_TEX_USE_VAL 7 -#define MOD_WVG_MASK_TEX_USE_ALPHA 8 - -/* Dynamic paint modifier flags */ -#define MOD_DYNAMICPAINT_TYPE_CANVAS (1 << 0) -#define MOD_DYNAMICPAINT_TYPE_BRUSH (1 << 1) +enum { + MOD_WVG_MASK_TEX_USE_INT = 1, + MOD_WVG_MASK_TEX_USE_RED = 2, + MOD_WVG_MASK_TEX_USE_GREEN = 3, + MOD_WVG_MASK_TEX_USE_BLUE = 4, + MOD_WVG_MASK_TEX_USE_HUE = 5, + MOD_WVG_MASK_TEX_USE_SAT = 6, + MOD_WVG_MASK_TEX_USE_VAL = 7, + MOD_WVG_MASK_TEX_USE_ALPHA = 8, +}; typedef struct DynamicPaintModifierData { ModifierData modifier; @@ -1059,18 +1108,23 @@ typedef struct DynamicPaintModifierData { int pad; } DynamicPaintModifierData; -/* Remesh modifier */ +/* Dynamic paint modifier flags */ +enum { + MOD_DYNAMICPAINT_TYPE_CANVAS = (1 << 0), + MOD_DYNAMICPAINT_TYPE_BRUSH = (1 << 1), +}; +/* Remesh modifier */ typedef enum RemeshModifierFlags { - MOD_REMESH_FLOOD_FILL = 1, + MOD_REMESH_FLOOD_FILL = 1, MOD_REMESH_SMOOTH_SHADING = 2, } RemeshModifierFlags; typedef enum RemeshModifierMode { /* blocky */ - MOD_REMESH_CENTROID = 0, + MOD_REMESH_CENTROID = 0, /* smooth */ - MOD_REMESH_MASS_POINT = 1, + MOD_REMESH_MASS_POINT = 1, /* keeps sharp edges */ MOD_REMESH_SHARP_FEATURES = 2, } RemeshModifierMode; @@ -1078,8 +1132,7 @@ typedef enum RemeshModifierMode { typedef struct RemeshModifierData { ModifierData modifier; - /* floodfill option, controls how small components can be - * before they are removed */ + /* floodfill option, controls how small components can be before they are removed */ float threshold; /* ratio between size of model and grid */ @@ -1096,14 +1149,13 @@ typedef struct RemeshModifierData { } RemeshModifierData; /* Skin modifier */ - typedef struct SkinModifierData { ModifierData modifier; float branch_smoothing; char flag; - + char symmetry_axes; char pad[2]; @@ -1111,20 +1163,20 @@ typedef struct SkinModifierData { /* SkinModifierData.symmetry_axes */ enum { - MOD_SKIN_SYMM_X = 1, - MOD_SKIN_SYMM_Y = 2, - MOD_SKIN_SYMM_Z = 4, + MOD_SKIN_SYMM_X = (1 << 0), + MOD_SKIN_SYMM_Y = (1 << 1), + MOD_SKIN_SYMM_Z = (1 << 2), }; /* SkinModifierData.flag */ enum { - MOD_SKIN_SMOOTH_SHADING = 1 + MOD_SKIN_SMOOTH_SHADING = 1, }; /* Triangulate modifier */ - typedef struct TriangulateModifierData { ModifierData modifier; + int flag; int pad; } TriangulateModifierData; @@ -1133,39 +1185,43 @@ enum { MOD_TRIANGULATE_BEAUTY = (1 << 0), }; -/* Smooth modifier flags */ -#define MOD_LAPLACIANSMOOTH_X (1<<1) -#define MOD_LAPLACIANSMOOTH_Y (1<<2) -#define MOD_LAPLACIANSMOOTH_Z (1<<3) -#define MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME (1 << 4) -#define MOD_LAPLACIANSMOOTH_NORMALIZED (1 << 5) - typedef struct LaplacianSmoothModifierData { ModifierData modifier; + float lambda, lambda_border, pad1; - char defgrp_name[64]; /* MAX_VGROUP_NAME */ + char defgrp_name[64]; /* MAX_VGROUP_NAME */ short flag, repeat; } LaplacianSmoothModifierData; +/* Smooth modifier flags */ +enum { + MOD_LAPLACIANSMOOTH_X = (1 << 1), + MOD_LAPLACIANSMOOTH_Y = (1 << 2), + MOD_LAPLACIANSMOOTH_Z = (1 << 3), + MOD_LAPLACIANSMOOTH_PRESERVE_VOLUME = (1 << 4), + MOD_LAPLACIANSMOOTH_NORMALIZED = (1 << 5), +}; + typedef struct UVWarpModifierData { ModifierData modifier; char axis_u, axis_v; char pad[6]; - float center[2]; /* used for rotate/scale */ + float center[2]; /* used for rotate/scale */ struct Object *object_src; /* source */ - char bone_src[64]; /* optional name of bone target, MAX_ID_NAME-2 */ + char bone_src[64]; /* optional name of bone target, MAX_ID_NAME-2 */ struct Object *object_dst; /* target */ - char bone_dst[64]; /* optional name of bone target, MAX_ID_NAME-2 */ + char bone_dst[64]; /* optional name of bone target, MAX_ID_NAME-2 */ - char vgroup_name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ - char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ + char vgroup_name[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + char uvlayer_name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ } UVWarpModifierData; /* cache modifier */ typedef struct MeshCacheModifierData { ModifierData modifier; + char flag; char type; /* file format */ char time_mode; @@ -1192,29 +1248,29 @@ typedef struct MeshCacheModifierData { float eval_time; float eval_factor; - char filepath[1024]; // FILE_MAX + char filepath[1024]; /* FILE_MAX */ } MeshCacheModifierData; enum { MOD_MESHCACHE_TYPE_MDD = 1, - MOD_MESHCACHE_TYPE_PC2 = 2 + MOD_MESHCACHE_TYPE_PC2 = 2, }; enum { MOD_MESHCACHE_DEFORM_OVERWRITE = 0, - MOD_MESHCACHE_DEFORM_INTEGRATE = 1 + MOD_MESHCACHE_DEFORM_INTEGRATE = 1, }; enum { - MOD_MESHCACHE_INTERP_NONE = 0, - MOD_MESHCACHE_INTERP_LINEAR = 1, - // MOD_MESHCACHE_INTERP_CARDINAL = 2 + MOD_MESHCACHE_INTERP_NONE = 0, + MOD_MESHCACHE_INTERP_LINEAR = 1, +/* MOD_MESHCACHE_INTERP_CARDINAL = 2, */ }; enum { - MOD_MESHCACHE_TIME_FRAME = 0, + MOD_MESHCACHE_TIME_FRAME = 0, MOD_MESHCACHE_TIME_SECONDS = 1, - MOD_MESHCACHE_TIME_FACTOR = 2, + MOD_MESHCACHE_TIME_FACTOR = 2, }; enum { diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 9ff4392242e..0ed620c4632 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -720,8 +720,10 @@ typedef struct NodeTexBase { typedef struct NodeTexSky { NodeTexBase base; + int sky_model; float sun_direction[3]; float turbidity; + float ground_albedo; } NodeTexSky; typedef struct NodeTexImage { @@ -827,6 +829,10 @@ typedef struct NodeTranslateData { char pad[6]; } NodeTranslateData; +typedef struct NodePlaneTrackDeformData { + char tracking_object[64]; + char plane_track_name[64]; +} NodePlaneTrackDeformData; typedef struct NodeShaderScript { int mode; @@ -888,6 +894,10 @@ typedef struct NodeShaderNormalMap { #define SHD_TOON_DIFFUSE 0 #define SHD_TOON_GLOSSY 1 +/* hair components */ +#define SHD_HAIR_REFLECTION 0 +#define SHD_HAIR_TRANSMISSION 1 + /* blend texture */ #define SHD_BLEND_LINEAR 0 #define SHD_BLEND_QUADRATIC 1 @@ -933,9 +943,9 @@ typedef struct NodeShaderNormalMap { #define SHD_WAVE_BANDS 0 #define SHD_WAVE_RINGS 1 -#define SHD_WAVE_SINE 0 -#define SHD_WAVE_SAW 1 -#define SHD_WAVE_TRI 2 +/* sky texture */ +#define SHD_SKY_OLD 0 +#define SHD_SKY_NEW 1 /* image/environment texture */ #define SHD_COLORSPACE_NONE 0 @@ -965,6 +975,11 @@ typedef struct NodeShaderNormalMap { #define SHD_NORMAL_MAP_BLENDER_OBJECT 3 #define SHD_NORMAL_MAP_BLENDER_WORLD 4 +/* subsurface */ +#define SHD_SUBSURFACE_COMPATIBLE 0 // Deprecated +#define SHD_SUBSURFACE_CUBIC 1 +#define SHD_SUBSURFACE_GAUSSIAN 2 + /* blur node */ #define CMP_NODE_BLUR_ASPECT_NONE 0 #define CMP_NODE_BLUR_ASPECT_Y 1 diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index de34f101c31..2ff697f513f 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -41,7 +41,7 @@ #ifdef __cplusplus extern "C" { #endif - + struct Object; struct AnimData; struct Ipo; @@ -100,7 +100,10 @@ typedef struct BoundBox { } BoundBox; /* boundbox flag */ -#define OB_BB_DISABLED 1 +enum { + BOUNDBOX_DISABLED = (1 << 0), + BOUNDBOX_DIRTY = (1 << 1), +}; typedef struct Object { ID id; @@ -130,7 +133,6 @@ typedef struct Object { ListBase constraintChannels DNA_DEPRECATED; // XXX deprecated... old animation system ListBase effect DNA_DEPRECATED; // XXX deprecated... keep for readfile - ListBase disp; /* list of DispList, used by lattice, metaballs curve & surfaces */ ListBase defbase; /* list of bDeformGroup (vertex groups) names and flag only */ ListBase modifiers; /* list of ModifierData structures */ @@ -140,7 +142,7 @@ typedef struct Object { /* materials */ struct Material **mat; /* material slots */ char *matbits; /* a boolean field, with each byte 1 if corresponding material is linked to object */ - int totcol; /* copy of mesh or curve or meta */ + int totcol; /* copy of mesh, curve & meta struct member of same name (keep in sync) */ int actcol; /* currently selected material in the UI */ /* rot en drot have to be together! (transform('r' en 's')) */ @@ -276,6 +278,9 @@ typedef struct Object { struct RigidBodyCon *rigidbody_constraint; /* settings for Bullet constraint */ float ima_ofs[2]; /* offset for image empties */ + + /* Runtime valuated curve-specific data, not stored in the file */ + struct CurveCache *curve_cache; } Object; /* Warning, this is not used anymore because hooks are now modifiers */ @@ -318,26 +323,28 @@ typedef struct DupliObject { /* **************** OBJECT ********************* */ /* used many places... should be specialized */ -#define SELECT 1 +#define SELECT 1 /* type */ -#define OB_EMPTY 0 -#define OB_MESH 1 -#define OB_CURVE 2 -#define OB_SURF 3 -#define OB_FONT 4 -#define OB_MBALL 5 +enum { + OB_EMPTY = 0, + OB_MESH = 1, + OB_CURVE = 2, + OB_SURF = 3, + OB_FONT = 4, + OB_MBALL = 5, -#define OB_LAMP 10 -#define OB_CAMERA 11 + OB_LAMP = 10, + OB_CAMERA = 11, -#define OB_SPEAKER 12 + OB_SPEAKER = 12, -// #define OB_WAVE 21 -#define OB_LATTICE 22 +/* OB_WAVE = 21, */ + OB_LATTICE = 22, /* 23 and 24 are for life and sector (old file compat.) */ -#define OB_ARMATURE 25 + OB_ARMATURE = 25, +}; /* check if the object type supports materials */ #define OB_TYPE_SUPPORT_MATERIAL(_type) \ @@ -346,6 +353,8 @@ typedef struct DupliObject { (ELEM(_type, OB_MESH, OB_LATTICE)) #define OB_TYPE_SUPPORT_EDITMODE(_type) \ (ELEM7(_type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE)) +#define OB_TYPE_SUPPORT_PARVERT(_type) \ + (ELEM4(_type, OB_MESH, OB_SURF, OB_CURVE, OB_LATTICE)) /* is this ID type used as object data */ #define OB_DATA_SUPPORT_ID(_id_type) \ @@ -355,263 +364,300 @@ typedef struct DupliObject { ID_ME: case ID_CU: case ID_MB: case ID_LA: case ID_SPK: case ID_CA: case ID_LT: case ID_AR /* partype: first 4 bits: type */ -#define PARTYPE 15 -#define PAROBJECT 0 -#define PARCURVE 1 -#define PARKEY 2 +enum { + PARTYPE = (1 << 4) - 1, + PAROBJECT = 0, + PARCURVE = 1, + PARKEY = 2, -#define PARSKEL 4 -#define PARVERT1 5 -#define PARVERT3 6 -#define PARBONE 7 + PARSKEL = 4, + PARVERT1 = 5, + PARVERT3 = 6, + PARBONE = 7, /* slow parenting - is not threadsafe and/or may give errors after jumping */ -#define PARSLOW 16 + PARSLOW = 16, +}; /* (short) transflag */ /* flags 1 and 2 were unused or relics from past features */ -#define OB_NEG_SCALE 4 -#define OB_DUPLI (8+16+256+512+2048) -#define OB_DUPLIFRAMES 8 -#define OB_DUPLIVERTS 16 -#define OB_DUPLIROT 32 -#define OB_DUPLINOSPEED 64 -/*#define OB_POWERTRACK 128*/ /*UNUSED*/ -#define OB_DUPLIGROUP 256 -#define OB_DUPLIFACES 512 -#define OB_DUPLIFACES_SCALE 1024 -#define OB_DUPLIPARTS 2048 -#define OB_RENDER_DUPLI 4096 -#define OB_NO_CONSTRAINTS 8192 /* runtime constraints disable */ -#define OB_NO_PSYS_UPDATE 16384 /* hack to work around particle issue */ +enum { + OB_NEG_SCALE = 1 << 2, + OB_DUPLIFRAMES = 1 << 3, + OB_DUPLIVERTS = 1 << 4, + OB_DUPLIROT = 1 << 5, + OB_DUPLINOSPEED = 1 << 6, +/* OB_POWERTRACK = 1 << 7,*/ /*UNUSED*/ + OB_DUPLIGROUP = 1 << 8, + OB_DUPLIFACES = 1 << 9, + OB_DUPLIFACES_SCALE = 1 << 10, + OB_DUPLIPARTS = 1 << 11, + OB_RENDER_DUPLI = 1 << 12, + OB_NO_CONSTRAINTS = 1 << 13, /* runtime constraints disable */ + OB_NO_PSYS_UPDATE = 1 << 14, /* hack to work around particle issue */ + + OB_DUPLI = OB_DUPLIFRAMES | OB_DUPLIVERTS | OB_DUPLIGROUP | OB_DUPLIFACES | OB_DUPLIPARTS, +}; /* (short) ipoflag */ /* XXX: many old flags for features removed due to incompatibility * with new system and/or other design issues were here */ /* for stride/path editing (XXX: NEEDS REVIEW) */ -#define OB_DISABLE_PATH 1024 +#define OB_DISABLE_PATH (1 << 10) /* (short) trackflag / upflag */ -#define OB_POSX 0 -#define OB_POSY 1 -#define OB_POSZ 2 -#define OB_NEGX 3 -#define OB_NEGY 4 -#define OB_NEGZ 5 +enum { + OB_POSX = 0, + OB_POSY = 1, + OB_POSZ = 2, + OB_NEGX = 3, + OB_NEGY = 4, + OB_NEGZ = 5, +}; /* gameflag in game.h */ /* dt: no flags */ -#define OB_BOUNDBOX 1 -#define OB_WIRE 2 -#define OB_SOLID 3 -#define OB_MATERIAL 4 -#define OB_TEXTURE 5 -#define OB_RENDER 6 +enum { + OB_BOUNDBOX = 1, + OB_WIRE = 2, + OB_SOLID = 3, + OB_MATERIAL = 4, + OB_TEXTURE = 5, + OB_RENDER = 6, -#define OB_PAINT 100 /* temporary used in draw code */ + OB_PAINT = 100, /* temporary used in draw code */ +}; /* dtx: flags (short) */ -#define OB_DRAWBOUNDOX (1 << 0) -#define OB_AXIS (1 << 1) -#define OB_TEXSPACE (1 << 2) -#define OB_DRAWNAME (1 << 3) -#define OB_DRAWIMAGE (1 << 4) +enum { + OB_DRAWBOUNDOX = 1 << 0, + OB_AXIS = 1 << 1, + OB_TEXSPACE = 1 << 2, + OB_DRAWNAME = 1 << 3, + OB_DRAWIMAGE = 1 << 4, /* for solid+wire display */ -#define OB_DRAWWIRE (1 << 5) + OB_DRAWWIRE = 1 << 5, /* for overdraw s*/ -#define OB_DRAWXRAY (1 << 6) + OB_DRAWXRAY = 1 << 6, /* enable transparent draw */ -#define OB_DRAWTRANSP (1 << 7) -#define OB_DRAW_ALL_EDGES (1 << 8) /* only for meshes currently */ + OB_DRAWTRANSP = 1 << 7, + OB_DRAW_ALL_EDGES = 1 << 8, /* only for meshes currently */ +}; /* empty_drawtype: no flags */ -#define OB_ARROWS 1 -#define OB_PLAINAXES 2 -#define OB_CIRCLE 3 -#define OB_SINGLE_ARROW 4 -#define OB_CUBE 5 -#define OB_EMPTY_SPHERE 6 -#define OB_EMPTY_CONE 7 -#define OB_EMPTY_IMAGE 8 +enum { + OB_ARROWS = 1, + OB_PLAINAXES = 2, + OB_CIRCLE = 3, + OB_SINGLE_ARROW = 4, + OB_CUBE = 5, + OB_EMPTY_SPHERE = 6, + OB_EMPTY_CONE = 7, + OB_EMPTY_IMAGE = 8, +}; /* boundtype */ -#define OB_BOUND_BOX 0 -#define OB_BOUND_SPHERE 1 -#define OB_BOUND_CYLINDER 2 -#define OB_BOUND_CONE 3 -#define OB_BOUND_TRIANGLE_MESH 4 -#define OB_BOUND_CONVEX_HULL 5 -/* #define OB_BOUND_DYN_MESH 6 */ /*UNUSED*/ -#define OB_BOUND_CAPSULE 7 +enum { + OB_BOUND_BOX = 0, + OB_BOUND_SPHERE = 1, + OB_BOUND_CYLINDER = 2, + OB_BOUND_CONE = 3, + OB_BOUND_TRIANGLE_MESH = 4, + OB_BOUND_CONVEX_HULL = 5, +/* OB_BOUND_DYN_MESH = 6, */ /*UNUSED*/ + OB_BOUND_CAPSULE = 7, +}; /* **************** BASE ********************* */ -/* also needed for base!!!!! or rather, thy interfere....*/ +/* also needed for base!!!!! or rather, they interfere....*/ /* base->flag and ob->flag */ -#define BA_WAS_SEL 2 -#define BA_HAS_RECALC_OB 4 -#define BA_HAS_RECALC_DATA 8 +#define BA_WAS_SEL (1 << 1) +#define BA_HAS_RECALC_OB (1 << 2) +#define BA_HAS_RECALC_DATA (1 << 3) /* NOTE: this was used as a proper setting in past, so nullify before using */ -#define BA_TEMP_TAG 32 +#define BA_TEMP_TAG (1 << 5) -/* #define BA_FROMSET 128 */ /*UNUSED*/ +/* #define BA_FROMSET (1 << 7) */ /*UNUSED*/ -#define BA_TRANSFORM_CHILD 256 /* child of a transformed object */ -#define BA_TRANSFORM_PARENT 8192 /* parent of a transformed object */ +#define BA_TRANSFORM_CHILD (1 << 8) /* child of a transformed object */ +#define BA_TRANSFORM_PARENT (1 << 13) /* parent of a transformed object */ /* an initial attempt as making selection more specific! */ -#define BA_DESELECT 0 -#define BA_SELECT 1 +#define BA_DESELECT 0 +#define BA_SELECT 1 -#define OB_FROMDUPLI 512 -#define OB_DONE 1024 -// #define OB_RADIO 2048 /* deprecated */ -#define OB_FROMGROUP 4096 +#define OB_FROMDUPLI (1 << 9) +#define OB_DONE (1 << 10) +/* #define OB_RADIO (1 << 11) */ /* deprecated */ +#define OB_FROMGROUP (1 << 12) /* WARNING - when adding flags check on PSYS_RECALC */ /* ob->recalc (flag bits!) */ -#define OB_RECALC_OB (1 << 0) -#define OB_RECALC_DATA (1 << 1) +enum { + OB_RECALC_OB = 1 << 0, + OB_RECALC_DATA = 1 << 1, /* time flag is set when time changes need recalc, so baked systems can ignore it */ -#define OB_RECALC_TIME (1 << 2) + OB_RECALC_TIME = 1 << 2, /* only use for matching any flag, NOT as an argument since more flags may be added. */ -#define OB_RECALC_ALL (OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME) + OB_RECALC_ALL = OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME, +}; /* controller state */ -#define OB_MAX_STATES 30 +#define OB_MAX_STATES 30 /* collision masks */ -#define OB_MAX_COL_MASKS 8 +#define OB_MAX_COL_MASKS 8 /* ob->gameflag */ -#define OB_DYNAMIC 1 -#define OB_CHILD 2 -#define OB_ACTOR 4 -#define OB_INERTIA_LOCK_X 8 -#define OB_INERTIA_LOCK_Y 16 -#define OB_INERTIA_LOCK_Z 32 -#define OB_DO_FH 64 -#define OB_ROT_FH 128 -#define OB_ANISOTROPIC_FRICTION 256 -#define OB_GHOST 512 -#define OB_RIGID_BODY 1024 -#define OB_BOUNDS 2048 - -#define OB_COLLISION_RESPONSE 4096 -#define OB_SECTOR 8192 -#define OB_PROP 16384 -#define OB_MAINACTOR 32768 - -#define OB_COLLISION 65536 -#define OB_SOFT_BODY 0x20000 -#define OB_OCCLUDER 0x40000 -#define OB_SENSOR 0x80000 -#define OB_NAVMESH 0x100000 -#define OB_HASOBSTACLE 0x200000 -#define OB_CHARACTER 0x400000 +enum { + OB_DYNAMIC = 1 << 0, + OB_CHILD = 1 << 1, + OB_ACTOR = 1 << 2, + OB_INERTIA_LOCK_X = 1 << 3, + OB_INERTIA_LOCK_Y = 1 << 4, + OB_INERTIA_LOCK_Z = 1 << 5, + OB_DO_FH = 1 << 6, + OB_ROT_FH = 1 << 7, + OB_ANISOTROPIC_FRICTION = 1 << 8, + OB_GHOST = 1 << 9, + OB_RIGID_BODY = 1 << 10, + OB_BOUNDS = 1 << 11, + + OB_COLLISION_RESPONSE = 1 << 12, + OB_SECTOR = 1 << 13, + OB_PROP = 1 << 14, + OB_MAINACTOR = 1 << 15, + + OB_COLLISION = 1 << 16, + OB_SOFT_BODY = 1 << 17, + OB_OCCLUDER = 1 << 18, + OB_SENSOR = 1 << 19, + OB_NAVMESH = 1 << 20, + OB_HASOBSTACLE = 1 << 21, + OB_CHARACTER = 1 << 22, +}; /* ob->gameflag2 */ -#define OB_NEVER_DO_ACTIVITY_CULLING 1 -#define OB_LOCK_RIGID_BODY_X_AXIS 4 -#define OB_LOCK_RIGID_BODY_Y_AXIS 8 -#define OB_LOCK_RIGID_BODY_Z_AXIS 16 -#define OB_LOCK_RIGID_BODY_X_ROT_AXIS 32 -#define OB_LOCK_RIGID_BODY_Y_ROT_AXIS 64 -#define OB_LOCK_RIGID_BODY_Z_ROT_AXIS 128 - -/* #define OB_LIFE (OB_PROP|OB_DYNAMIC|OB_ACTOR|OB_MAINACTOR|OB_CHILD) */ +enum { + OB_NEVER_DO_ACTIVITY_CULLING = 1 << 0, + OB_LOCK_RIGID_BODY_X_AXIS = 1 << 2, + OB_LOCK_RIGID_BODY_Y_AXIS = 1 << 3, + OB_LOCK_RIGID_BODY_Z_AXIS = 1 << 4, + OB_LOCK_RIGID_BODY_X_ROT_AXIS = 1 << 5, + OB_LOCK_RIGID_BODY_Y_ROT_AXIS = 1 << 6, + OB_LOCK_RIGID_BODY_Z_ROT_AXIS = 1 << 7, + +/* OB_LIFE = OB_PROP | OB_DYNAMIC | OB_ACTOR | OB_MAINACTOR | OB_CHILD, */ +}; /* ob->body_type */ -#define OB_BODY_TYPE_NO_COLLISION 0 -#define OB_BODY_TYPE_STATIC 1 -#define OB_BODY_TYPE_DYNAMIC 2 -#define OB_BODY_TYPE_RIGID 3 -#define OB_BODY_TYPE_SOFT 4 -#define OB_BODY_TYPE_OCCLUDER 5 -#define OB_BODY_TYPE_SENSOR 6 -#define OB_BODY_TYPE_NAVMESH 7 -#define OB_BODY_TYPE_CHARACTER 8 +enum { + OB_BODY_TYPE_NO_COLLISION = 0, + OB_BODY_TYPE_STATIC = 1, + OB_BODY_TYPE_DYNAMIC = 2, + OB_BODY_TYPE_RIGID = 3, + OB_BODY_TYPE_SOFT = 4, + OB_BODY_TYPE_OCCLUDER = 5, + OB_BODY_TYPE_SENSOR = 6, + OB_BODY_TYPE_NAVMESH = 7, + OB_BODY_TYPE_CHARACTER = 8, +}; /* ob->depsflag */ -#define OB_DEPS_EXTRA_OB_RECALC 1 -#define OB_DEPS_EXTRA_DATA_RECALC 2 +enum { + OB_DEPS_EXTRA_OB_RECALC = 1 << 0, + OB_DEPS_EXTRA_DATA_RECALC = 1 << 1, +}; /* ob->scavisflag */ -#define OB_VIS_SENS 1 -#define OB_VIS_CONT 2 -#define OB_VIS_ACT 4 +enum { + OB_VIS_SENS = 1 << 0, + OB_VIS_CONT = 1 << 1, + OB_VIS_ACT = 1 << 2, +}; /* ob->scaflag */ -#define OB_SHOWSENS 64 -#define OB_SHOWACT 128 -#define OB_ADDSENS 256 -#define OB_ADDCONT 512 -#define OB_ADDACT 1024 -#define OB_SHOWCONT 2048 -#define OB_ALLSTATE 4096 -#define OB_INITSTBIT 8192 -#define OB_DEBUGSTATE 16384 -#define OB_SHOWSTATE 32768 +enum { + OB_SHOWSENS = 1 << 6, + OB_SHOWACT = 1 << 7, + OB_ADDSENS = 1 << 8, + OB_ADDCONT = 1 << 9, + OB_ADDACT = 1 << 10, + OB_SHOWCONT = 1 << 11, + OB_ALLSTATE = 1 << 12, + OB_INITSTBIT = 1 << 13, + OB_DEBUGSTATE = 1 << 14, + OB_SHOWSTATE = 1 << 15, +}; /* ob->restrictflag */ -#define OB_RESTRICT_VIEW 1 -#define OB_RESTRICT_SELECT 2 -#define OB_RESTRICT_RENDER 4 +enum { + OB_RESTRICT_VIEW = 1 << 0, + OB_RESTRICT_SELECT = 1 << 1, + OB_RESTRICT_RENDER = 1 << 2, +}; /* ob->shapeflag */ -#define OB_SHAPE_LOCK 1 -#define OB_SHAPE_TEMPLOCK 2 // deprecated -#define OB_SHAPE_EDIT_MODE 4 +enum { + OB_SHAPE_LOCK = 1 << 0, + OB_SHAPE_TEMPLOCK = 1 << 1, /* deprecated */ + OB_SHAPE_EDIT_MODE = 1 << 2, +}; /* ob->nlaflag */ - /* WARNING: flags (1<<0) and (1<<1) were from old animsys */ +enum { + /* WARNING: flags (1 << 0) and (1 << 1) were from old animsys */ /* object-channel expanded status */ -#define OB_ADS_COLLAPSED (1<<10) + OB_ADS_COLLAPSED = 1 << 10, /* object's ipo-block */ -#define OB_ADS_SHOWIPO (1<<11) + OB_ADS_SHOWIPO = 1 << 11, /* object's constraint channels */ -#define OB_ADS_SHOWCONS (1<<12) + OB_ADS_SHOWCONS = 1 << 12, /* object's material channels */ -#define OB_ADS_SHOWMATS (1<<13) + OB_ADS_SHOWMATS = 1 << 13, /* object's marticle channels */ -#define OB_ADS_SHOWPARTS (1<<14) + OB_ADS_SHOWPARTS = 1 << 14, +}; /* ob->protectflag */ -#define OB_LOCK_LOCX 1 -#define OB_LOCK_LOCY 2 -#define OB_LOCK_LOCZ 4 -#define OB_LOCK_LOC 7 -#define OB_LOCK_ROTX 8 -#define OB_LOCK_ROTY 16 -#define OB_LOCK_ROTZ 32 -#define OB_LOCK_ROT 56 -#define OB_LOCK_SCALEX 64 -#define OB_LOCK_SCALEY 128 -#define OB_LOCK_SCALEZ 256 -#define OB_LOCK_SCALE 448 -#define OB_LOCK_ROTW 512 -#define OB_LOCK_ROT4D 1024 +enum { + OB_LOCK_LOCX = 1 << 0, + OB_LOCK_LOCY = 1 << 1, + OB_LOCK_LOCZ = 1 << 2, + OB_LOCK_LOC = OB_LOCK_LOCX | OB_LOCK_LOCY | OB_LOCK_LOCZ, + OB_LOCK_ROTX = 1 << 3, + OB_LOCK_ROTY = 1 << 4, + OB_LOCK_ROTZ = 1 << 5, + OB_LOCK_ROT = OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ, + OB_LOCK_SCALEX = 1 << 6, + OB_LOCK_SCALEY = 1 << 7, + OB_LOCK_SCALEZ = 1 << 8, + OB_LOCK_SCALE = OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ, + OB_LOCK_ROTW = 1 << 9, + OB_LOCK_ROT4D = 1 << 10, +}; /* ob->mode */ typedef enum ObjectMode { - OB_MODE_OBJECT = 0, - OB_MODE_EDIT = 1, - OB_MODE_SCULPT = 2, - OB_MODE_VERTEX_PAINT = 4, - OB_MODE_WEIGHT_PAINT = 8, - OB_MODE_TEXTURE_PAINT = 16, - OB_MODE_PARTICLE_EDIT = 32, - OB_MODE_POSE = 64 + OB_MODE_OBJECT = 0, + OB_MODE_EDIT = 1 << 0, + OB_MODE_SCULPT = 1 << 1, + OB_MODE_VERTEX_PAINT = 1 << 2, + OB_MODE_WEIGHT_PAINT = 1 << 3, + OB_MODE_TEXTURE_PAINT = 1 << 4, + OB_MODE_PARTICLE_EDIT = 1 << 5, + OB_MODE_POSE = 1 << 6, } ObjectMode; /* any mode where the brush system is used */ -#define OB_MODE_ALL_PAINT (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT) +#define OB_MODE_ALL_PAINT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT) #define MAX_DUPLI_RECUR 8 diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index 29fcaf3bf73..b7ca3066b4f 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -272,7 +272,9 @@ typedef struct ParticleSystem { struct DerivedMesh *hair_in_dm, *hair_out_dm; /* input/output for cloth simulation */ struct Object *target_ob; - struct Object *lattice; + + struct LatticeDeformData *lattice_deform_data; /* run-time only lattice deformation data */ + struct Object *parent; /* particles from global space -> parent space */ struct ListBase targets; /* used for keyed and boid physics */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index ceb745cf90a..e8f55ac047c 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -693,8 +693,8 @@ typedef struct GameData { #define RAS_STORE_VBO 3 /* vsync */ -#define VSYNC_OFF 0 -#define VSYNC_ON 1 +#define VSYNC_ON 0 +#define VSYNC_OFF 1 #define VSYNC_ADAPTIVE 2 /* GameData.flag */ @@ -981,17 +981,6 @@ typedef struct ToolSettings { * paint */ float vgroup_weight; - /* Subdivide Settings */ - short cornertype; - short pad1; - /*Triangle to Quad conversion threshold*/ - float jointrilimit; - /* Editmode Tools */ - float degr; - short step; - short turn; - - float extr_offs; /* extrude offset */ float doublimit; /* remove doubles limit */ float normalsize; /* size of normals */ short automerge; @@ -999,30 +988,21 @@ typedef struct ToolSettings { /* Selection Mode for Mesh */ short selectmode; - /* Primitive Settings */ - /* UV Sphere */ - short segments; - short rings; - - /* Cylinder - Tube - Circle */ - short vertices; - /* UV Calculation */ - short unwrapper; - float uvcalc_radius; - float uvcalc_cubesize; + char unwrapper; + char uvcalc_flag; + char uv_flag; + char uv_selectmode; + float uvcalc_margin; - short uvcalc_mapdir; - short uvcalc_mapalign; - short uvcalc_flag; - short uv_flag, uv_selectmode; - short pad2; - - /* Grease Pencil */ - short gpencil_flags; - + /* Auto-IK */ - short autoik_chainlen; + short autoik_chainlen; /* runtime only */ + + /* Grease Pencil */ + char gpencil_flags; + + char pad[5]; /* Image Paint (8 byttse aligned please!) */ struct ImagePaintSettings imapaint; @@ -1035,16 +1015,13 @@ typedef struct ToolSettings { /* Select Group Threshold */ float select_thresh; - - /* Graph Editor */ - float clean_thresh; /* Auto-Keying Mode */ short autokey_mode, autokey_flag; /* defines in DNA_userdef_types.h */ /* Multires */ char multires_subdiv_type; - char pad3[5]; + char pad3[1]; /* Skeleton generation */ short skgen_resolution; diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 9d840ad13e8..ec86a4739c5 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -112,22 +112,48 @@ typedef struct Panel { /* the part from uiBlock that needs saved in file */ void *activedata; /* runtime for panel manipulation */ } Panel; -typedef struct uiList { /* some list UI data need to be saved in file */ +/* uiList dynamic data... */ +/* These two Lines with # tell makesdna this struct can be excluded. */ +# +# +typedef struct uiListDyn { + int height; /* Number of rows needed to draw all elements. */ + int visual_height; /* Actual visual height of the list (in rows). */ + int visual_height_min; /* Minimal visual height of the list (in rows). */ + + int items_len; /* Number of items in collection. */ + int items_shown; /* Number of items actually visible after filtering. */ + + /* Filtering data. */ + int *items_filter_flags; /* items_len length. */ + int *items_filter_neworder; /* org_idx -> new_idx, items_len length. */ +} uiListDyn; + +typedef struct uiList { /* some list UI data need to be saved in file */ struct uiList *next, *prev; - struct uiListType *type; /* runtime */ - void *padp; + struct uiListType *type; /* runtime */ - char list_id[64]; /* defined as UI_MAX_NAME_STR */ + char list_id[64]; /* defined as UI_MAX_NAME_STR */ - int layout_type; /* How items are layedout in the list */ - int padi; + int layout_type; /* How items are layedout in the list */ + int flag; int list_scroll; - int list_size; + int list_grip; int list_last_len; - int list_grip_size; -/* char list_search[64]; */ + int padi1; + + /* Filtering data. */ + char filter_byname[64]; /* defined as UI_MAX_NAME_STR */ + int filter_flag; + int filter_sort_flag; + + /* Custom sub-classes properties. */ + IDProperty *properties; + + /* Dynamic data (runtime). */ + uiListDyn *dyn_data; } uiList; typedef struct ScrArea { @@ -232,13 +258,38 @@ typedef struct ARegion { #define PNL_DEFAULT_CLOSED 1 #define PNL_NO_HEADER 2 -/* uilist layout_type */ +/* uiList layout_type */ enum { UILST_LAYOUT_DEFAULT = 0, UILST_LAYOUT_COMPACT = 1, UILST_LAYOUT_GRID = 2, }; +/* uiList flag */ +enum { + UILST_SCROLL_TO_ACTIVE_ITEM = 1 << 0, /* Scroll list to make active item visible. */ + UILST_RESIZING = 1 << 1, /* We are currently resizing, deactivate autosize! */ +}; + +/* uiList filter flags (dyn_data) */ +enum { + UILST_FLT_ITEM = 1 << 31, /* This item has passed the filter process successfully. */ +}; + +/* uiList filter options */ +enum { + UILST_FLT_SHOW = 1 << 0, /* Show filtering UI. */ + UILST_FLT_EXCLUDE = UILST_FLT_ITEM, /* Exclude filtered items, *must* use this same value. */ +}; + +/* uiList filter orderby type */ +enum { + UILST_FLT_SORT_ALPHA = 1 << 0, + UILST_FLT_SORT_REVERSE = 1 << 31 /* Special value, bitflag used to reverse order! */ +}; + +#define UILST_FLT_SORT_MASK (((unsigned int)UILST_FLT_SORT_REVERSE) - 1) + /* regiontype, first two are the default set */ /* Do NOT change order, append on end. Types are hardcoded needed */ enum { diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h index d8cf80d047b..1b946c829fd 100644 --- a/source/blender/makesdna/DNA_sensor_types.h +++ b/source/blender/makesdna/DNA_sensor_types.h @@ -60,6 +60,7 @@ typedef struct bMouseSensor { short pad2; } bMouseSensor; +/* DEPRECATED */ typedef struct bTouchSensor { char name[64]; /* MAX_NAME */ struct Material *ma; @@ -235,7 +236,7 @@ typedef struct bJoystickSensor { /* sensor->type */ #define SENS_ALWAYS 0 -#define SENS_TOUCH 1 +#define SENS_TOUCH 1 /* DEPRECATED */ #define SENS_NEAR 2 #define SENS_KEYBOARD 3 #define SENS_PROPERTY 4 diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index c562a1fefae..0478ff567a0 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -132,8 +132,9 @@ typedef struct SpaceButs { short mainb, mainbo, mainbuser; /* context tabs */ short re_align, align; /* align for panels */ short preview; /* preview is signal to refresh */ - short texture_context; /* texture context selector (material, world, brush)*/ - char flag, pad; + /* texture context selector (material, lamp, particles, world, other)*/ + short texture_context, texture_context_prev; + char flag, pad[7]; void *path; /* runtime */ int pathflag, dataicon; /* runtime */ @@ -246,6 +247,13 @@ typedef struct SpaceOops { View2D v2d DNA_DEPRECATED; /* deprecated, copied to region */ ListBase tree; + + /* treestore is an ordered list of TreeStoreElem's from outliner tree; + * Note that treestore may contain duplicate elements if element + * is used multiple times in outliner tree (e. g. linked objects) + * Also note that BLI_mempool can not be read/written in DNA directly, + * therefore readfile.c/writefile.c linearize treestore into TreeStore structure + */ struct BLI_mempool *treestore; /* search stuff */ @@ -253,7 +261,9 @@ typedef struct SpaceOops { struct TreeStoreElem search_tse; short flag, outlinevis, storeflag, search_flags; - struct GHash *treehash; + + /* pointers to treestore elements, grouped by (id, type, nr) in hashtable for faster searching */ + void *treehash; } SpaceOops; @@ -1083,6 +1093,8 @@ typedef struct SpaceClip { int around, pad4; /* pivot point for transforms */ + float cursor[2]; /* Mask editor 2d cursor */ + MaskSpaceInfo mask_info; } SpaceClip; diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 0b6e5f9c7bb..fcd0575f1c5 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -263,7 +263,7 @@ typedef struct TexMapping { float loc[3], rot[3], size[3]; int flag; char projx, projy, projz, mapping; - int pad; + int type; float mat[4][4]; float min[3], max[3]; @@ -287,6 +287,12 @@ typedef struct ColorMapping { #define TEXMAP_CLIP_MAX 2 #define TEXMAP_UNIT_MATRIX 4 +/* texmap->type */ +#define TEXMAP_TYPE_POINT 0 +#define TEXMAP_TYPE_TEXTURE 1 +#define TEXMAP_TYPE_VECTOR 2 +#define TEXMAP_TYPE_NORMAL 3 + /* colormap->flag */ #define COLORMAP_USE_RAMP 1 diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h index 04cd69bc5ae..49c1e3ed35d 100644 --- a/source/blender/makesdna/DNA_tracking_types.h +++ b/source/blender/makesdna/DNA_tracking_types.h @@ -144,6 +144,44 @@ typedef struct MovieTrackingTrack { struct bGPdata *gpd; /* grease-pencil data */ } MovieTrackingTrack; +typedef struct MovieTrackingPlaneMarker { + /* Corners of the plane in the following order: + * + * Y + * ^ + * | (3) --- (2) + * | | | + * | | | + * | | | + * | (0) --- (1) + * +-------------> X + * + * The coordinates are stored in frame normalized coordinates. + */ + float corners[4][2]; + + int framenr; /* Number of frame plane marker is associated with */ + int flag; /* Marker's flag (alive, ...) */ +} MovieTrackingPlaneMarker; + +typedef struct MovieTrackingPlaneTrack { + struct MovieTrackingPlaneTrack *next, *prev; + + char name[64]; /* MAX_NAME */ + + MovieTrackingTrack **point_tracks; /* Array of point tracks used to define this plane. + * Each element is a pointer to MovieTrackingTrack. */ + int point_tracksnr, pad; /* Number of tracks in point_tracks array. */ + + MovieTrackingPlaneMarker *markers; /* Markers in the plane track */ + int markersnr; /* Count of markers in track (size of markers array) */ + + int flag; /* flags (selection, ...) */ + + /* Runtime data */ + int last_marker, pad2; /* Most recently used marker */ +} MovieTrackingPlaneTrack; + typedef struct MovieTrackingSettings { int flag; @@ -225,6 +263,7 @@ typedef struct MovieTrackingObject { float scale; /* scale of object solution in amera space */ ListBase tracks; /* list of tracks use to tracking this object */ + ListBase plane_tracks; /* list of plane tracks used by this object */ MovieTrackingReconstruction reconstruction; /* reconstruction data for this object */ /* reconstruction options */ @@ -280,9 +319,11 @@ typedef struct MovieTracking { MovieTrackingSettings settings; /* different tracking-related settings */ MovieTrackingCamera camera; /* camera intrinsics */ ListBase tracks; /* list of tracks used for camera object */ + ListBase plane_tracks; /* list of plane tracks used by camera object */ MovieTrackingReconstruction reconstruction; /* reconstruction data for camera object */ MovieTrackingStabilization stabilization; /* stabilization data */ - MovieTrackingTrack *act_track; /* active track */ + MovieTrackingTrack *act_track; /* active track */ + MovieTrackingPlaneTrack *act_plane_track; /* active plane track */ ListBase objects; int objectnr, tot_object; /* index of active object and total number of objects */ @@ -432,4 +473,17 @@ enum { TRACKING_COVERAGE_OK = 2 }; +/* MovieTrackingPlaneMarker->flag */ +enum { + PLANE_MARKER_DISABLED = (1 << 0), + PLANE_MARKER_TRACKED = (1 << 1), +}; + +/* MovieTrackingPlaneTrack->flag */ +enum { + PLANE_TRACK_HIDDEN = (1 << 1), + PLANE_TRACK_LOCKED = (1 << 2), + PLANE_TRACK_AUTOKEY = (1 << 3), +}; + #endif /* __DNA_TRACKING_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index e0c5cd5608e..1621f7c6cb6 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -286,6 +286,9 @@ typedef struct ThemeSpace { char preview_stitch_unstitchable[4]; char preview_stitch_active[4]; + char uv_shadow[4]; + char uv_others[4]; + char match[4]; /* outliner - filter match */ char selected_highlight[4]; /* outliner - selected item */ diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 27aef3b8ec6..07a679be571 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -339,6 +339,12 @@ typedef struct wmOperator { #define OPERATOR_RETVAL_CHECK(ret) (void)ret, BLI_assert(ret != 0 && (ret & OPERATOR_FLAGS_ALL) == ret) /* wmOperator flag */ -#define OP_GRAB_POINTER 1 +enum { + OP_GRAB_POINTER = (1 << 0), + + /* low level flag so exec() operators can tell if they were invoked, use with care. + * typically this shouldn't make any difference, but it rare cases its needed (see smooth-view) */ + OP_IS_INVOKE = (1 << 1), +}; #endif /* __DNA_WINDOWMANAGER_TYPES_H__ */ diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index 70c79fa393c..cae607949a9 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -29,6 +29,7 @@ add_definitions(-DWITH_DNA_GHASH) blender_include_dirs( ../../../../intern/guardedalloc + ../../../../intern/atomic ../../blenlib .. ) @@ -80,6 +81,8 @@ set(SRC ${SRC_DNA_INC} ) +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/dna.c PROPERTIES GENERATED TRUE) + blender_add_lib(bf_dna "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/makesdna/intern/SConscript b/source/blender/makesdna/intern/SConscript index c0db40dcfd2..7c3af30ee83 100644 --- a/source/blender/makesdna/intern/SConscript +++ b/source/blender/makesdna/intern/SConscript @@ -46,7 +46,9 @@ dna = env.Clone() makesdna_tool.Append(CCFLAGS = '-DBASE_HEADER="\\"source/blender/makesdna/\\"" ') makesdna_tool.Append (CPPPATH = ['#/intern/guardedalloc', - '../../makesdna', '../../bmesh']) + '#/intern/atomic', + '../../makesdna', '../../bmesh', + '../../blenlib']) if env['OURPLATFORM'] == 'linuxcross': USE_WINE = True # when cross compiling on linux 64bit this is useful diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index 1225821102a..ed7f6f5d765 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -530,7 +530,7 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap) #ifdef WITH_DNA_GHASH /* create a ghash lookup to speed up */ - sdna->structs_map = BLI_ghash_str_new("init_structDNA gh"); + sdna->structs_map = BLI_ghash_str_new_ex("init_structDNA gh", sdna->nr_structs); for (nr = 0; nr < sdna->nr_structs; nr++) { sp = sdna->structs[nr]; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 3a4eb66bc19..c3a8148431a 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -31,6 +31,8 @@ #include "RNA_types.h" +#include "BLI_compiler_attrs.h" + #ifdef __cplusplus extern "C" { #endif @@ -621,7 +623,6 @@ extern StructRNA RNA_ThemeWidgetStateColors; extern StructRNA RNA_TimelineMarker; extern StructRNA RNA_Timer; extern StructRNA RNA_ToolSettings; -extern StructRNA RNA_TouchSensor; extern StructRNA RNA_TrackToConstraint; extern StructRNA RNA_TransformConstraint; extern StructRNA RNA_TransformSequence; @@ -1035,15 +1036,15 @@ void RNA_struct_property_unset(PointerRNA *ptr, const char *identifier); /* python compatible string representation of this property, (must be freed!) */ char *RNA_property_as_string(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int index, int max_prop_length); char *RNA_pointer_as_string(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop_ptr, PointerRNA *ptr_prop); -char *RNA_pointer_as_string_keywords_ex(struct bContext *C, PointerRNA *ptr, PointerRNA *ptr_default, - const short skip_optional_value, const short all_args, +char *RNA_pointer_as_string_keywords_ex(struct bContext *C, PointerRNA *ptr, + const bool skip_optional_value, const bool all_args, const int max_prop_length, PropertyRNA *iterprop); -char *RNA_pointer_as_string_keywords(struct bContext *C, PointerRNA *ptr, PointerRNA *ptr_default, - const short skip_optional_value, const short all_args, +char *RNA_pointer_as_string_keywords(struct bContext *C, PointerRNA *ptr, + const bool skip_optional_value, const bool all_args, const int max_prop_length); -char *RNA_function_as_string_keywords(struct bContext *C, FunctionRNA *func, PointerRNA *ptr_default, - const short as_function, const short all_args, +char *RNA_function_as_string_keywords(struct bContext *C, FunctionRNA *func, + const bool as_function, const bool all_args, const int max_prop_length); /* Function */ @@ -1074,10 +1075,11 @@ void RNA_parameter_get(ParameterList *parms, PropertyRNA *parm, void **value); void RNA_parameter_get_lookup(ParameterList *parms, const char *identifier, void **value); void RNA_parameter_set(ParameterList *parms, PropertyRNA *parm, const void *value); void RNA_parameter_set_lookup(ParameterList *parms, const char *identifier, const void *value); -int RNA_parameter_length_get(ParameterList *parms, PropertyRNA *parm); -int RNA_parameter_length_get_data(ParameterList *parms, PropertyRNA *parm, void *data); -void RNA_parameter_length_set(ParameterList *parms, PropertyRNA *parm, int length); -void RNA_parameter_length_set_data(ParameterList *parms, PropertyRNA *parm, void *data, int length); +/* Only for PROP_DYNAMIC properties! */ +int RNA_parameter_dynamic_length_get(ParameterList *parms, PropertyRNA *parm); +int RNA_parameter_dynamic_length_get_data(ParameterList *parms, PropertyRNA *parm, void *data); +void RNA_parameter_dynamic_length_set(ParameterList *parms, PropertyRNA *parm, int length); +void RNA_parameter_dynamic_length_set_data(ParameterList *parms, PropertyRNA *parm, void *data, int length); int RNA_function_call(struct bContext *C, struct ReportList *reports, PointerRNA *ptr, FunctionRNA *func, ParameterList *parms); @@ -1085,17 +1087,9 @@ int RNA_function_call_lookup(struct bContext *C, struct ReportList *reports, Poi const char *identifier, ParameterList *parms); int RNA_function_call_direct(struct bContext *C, struct ReportList *reports, PointerRNA *ptr, - FunctionRNA *func, const char *format, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 5, 6))) -#endif -; + FunctionRNA *func, const char *format, ...) ATTR_PRINTF_FORMAT(5, 6); int RNA_function_call_direct_lookup(struct bContext *C, struct ReportList *reports, PointerRNA *ptr, - const char *identifier, const char *format, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 5, 6))) -#endif -; + const char *identifier, const char *format, ...) ATTR_PRINTF_FORMAT(5, 6); int RNA_function_call_direct_va(struct bContext *C, struct ReportList *reports, PointerRNA *ptr, FunctionRNA *func, const char *format, va_list args); int RNA_function_call_direct_va_lookup(struct bContext *C, struct ReportList *reports, PointerRNA *ptr, @@ -1121,17 +1115,19 @@ StructRNA *ID_code_to_RNA_type(short idcode); # define RNA_warning(format, ...) _RNA_warning("%s: " format "\n", __FUNCTION__, __VA_ARGS__) #endif -void _RNA_warning(const char *format, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 1, 2))) -#endif -; +void _RNA_warning(const char *format, ...) ATTR_PRINTF_FORMAT(1, 2); /* Equals test (skips pointers and collections) * is_strict false assumes uninitialized properties are equal */ -bool RNA_property_equals(struct PointerRNA *a, struct PointerRNA *b, struct PropertyRNA *prop, bool is_strict); -bool RNA_struct_equals(struct PointerRNA *a, struct PointerRNA *b, bool is_strict); +typedef enum eRNAEqualsMode { + RNA_EQ_STRICT, /* set/unset ignored */ + RNA_EQ_UNSET_MATCH_ANY, /* unset property matches anything */ + RNA_EQ_UNSET_MATCH_NONE /* unset property never matches set property */ +} eRNAEqualsMode; + +bool RNA_property_equals(struct PointerRNA *a, struct PointerRNA *b, struct PropertyRNA *prop, eRNAEqualsMode mode); +bool RNA_struct_equals(struct PointerRNA *a, struct PointerRNA *b, eRNAEqualsMode mode); #ifdef __cplusplus } diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index 924fc505fda..d686a5951eb 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -42,8 +42,8 @@ extern "C" { BlenderRNA *RNA_create(void); void RNA_define_free(BlenderRNA *brna); void RNA_free(BlenderRNA *brna); -void RNA_define_verify_sdna(int verify); -void RNA_define_animate_sdna(int animate); +void RNA_define_verify_sdna(bool verify); +void RNA_define_animate_sdna(bool animate); void RNA_init(void); void RNA_exit(void); @@ -164,7 +164,7 @@ void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *update void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable); void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable); -void RNA_def_property_update_runtime(PropertyRNA *prop, void *func); +void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func); void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getlength); void RNA_def_property_boolean_funcs(PropertyRNA *prop, const char *get, const char *set); diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 86d043b839a..d33d3df8a5e 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -169,6 +169,8 @@ extern EnumPropertyItem linestyle_alpha_modifier_type_items[]; extern EnumPropertyItem linestyle_thickness_modifier_type_items[]; extern EnumPropertyItem linestyle_geometry_modifier_type_items[]; +extern EnumPropertyItem window_cursor_items[]; + struct bContext; struct PointerRNA; struct PropertyRNA; diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 69cb2caf058..43bf1973c33 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -69,27 +69,27 @@ typedef struct PropertyPointerRNA { /* Property */ typedef enum PropertyType { - PROP_BOOLEAN = 0, - PROP_INT = 1, - PROP_FLOAT = 2, - PROP_STRING = 3, - PROP_ENUM = 4, - PROP_POINTER = 5, - PROP_COLLECTION = 6 + PROP_BOOLEAN = 0, + PROP_INT = 1, + PROP_FLOAT = 2, + PROP_STRING = 3, + PROP_ENUM = 4, + PROP_POINTER = 5, + PROP_COLLECTION = 6, } PropertyType; /* also update rna_property_subtype_unit when you change this */ typedef enum PropertyUnit { - PROP_UNIT_NONE = (0 << 16), - PROP_UNIT_LENGTH = (1 << 16), /* m */ - PROP_UNIT_AREA = (2 << 16), /* m^2 */ - PROP_UNIT_VOLUME = (3 << 16), /* m^3 */ - PROP_UNIT_MASS = (4 << 16), /* kg */ - PROP_UNIT_ROTATION = (5 << 16), /* radians */ - PROP_UNIT_TIME = (6 << 16), /* frame */ - PROP_UNIT_VELOCITY = (7 << 16), /* m/s */ + PROP_UNIT_NONE = (0 << 16), + PROP_UNIT_LENGTH = (1 << 16), /* m */ + PROP_UNIT_AREA = (2 << 16), /* m^2 */ + PROP_UNIT_VOLUME = (3 << 16), /* m^3 */ + PROP_UNIT_MASS = (4 << 16), /* kg */ + PROP_UNIT_ROTATION = (5 << 16), /* radians */ + PROP_UNIT_TIME = (6 << 16), /* frame */ + PROP_UNIT_VELOCITY = (7 << 16), /* m/s */ PROP_UNIT_ACCELERATION = (8 << 16), /* m/(s^2) */ - PROP_UNIT_CAMERA = (9 << 16) /* mm */ + PROP_UNIT_CAMERA = (9 << 16), /* mm */ } PropertyUnit; #define RNA_SUBTYPE_UNIT(subtype) ((subtype) & 0x00FF0000) @@ -105,95 +105,101 @@ typedef enum PropertyUnit { * node socket button subtypes! */ typedef enum PropertySubType { - PROP_NONE = 0, + PROP_NONE = 0, /* strings */ - PROP_FILEPATH = 1, - PROP_DIRPATH = 2, - PROP_FILENAME = 3, - PROP_BYTESTRING = 4, /* a string which should be represented as bytes in python, still NULL terminated though. */ + PROP_FILEPATH = 1, + PROP_DIRPATH = 2, + PROP_FILENAME = 3, + PROP_BYTESTRING = 4, /* a string which should be represented as bytes in python, NULL terminated though. */ /* 5 was used by "PROP_TRANSLATE" sub-type, which is now a flag. */ - PROP_PASSWORD = 6, /* a string which should not be displayed in UI */ + PROP_PASSWORD = 6, /* a string which should not be displayed in UI */ /* numbers */ - PROP_UNSIGNED = 13, - PROP_PERCENTAGE = 14, - PROP_FACTOR = 15, - PROP_ANGLE = 16 | PROP_UNIT_ROTATION, - PROP_TIME = 17 | PROP_UNIT_TIME, + PROP_UNSIGNED = 13, + PROP_PERCENTAGE = 14, + PROP_FACTOR = 15, + PROP_ANGLE = 16 | PROP_UNIT_ROTATION, + PROP_TIME = 17 | PROP_UNIT_TIME, /* distance in 3d space, don't use for pixel distance for eg. */ - PROP_DISTANCE = 18 | PROP_UNIT_LENGTH, - PROP_DISTANCE_CAMERA = 19 | PROP_UNIT_CAMERA, + PROP_DISTANCE = 18 | PROP_UNIT_LENGTH, + PROP_DISTANCE_CAMERA = 19 | PROP_UNIT_CAMERA, /* number arrays */ - PROP_COLOR = 20, - PROP_TRANSLATION = 21 | PROP_UNIT_LENGTH, - PROP_DIRECTION = 22, - PROP_VELOCITY = 23 | PROP_UNIT_VELOCITY, - PROP_ACCELERATION = 24 | PROP_UNIT_ACCELERATION, - PROP_MATRIX = 25, - PROP_EULER = 26 | PROP_UNIT_ROTATION, - PROP_QUATERNION = 27, - PROP_AXISANGLE = 28, - PROP_XYZ = 29, - PROP_XYZ_LENGTH = 29 | PROP_UNIT_LENGTH, - PROP_COLOR_GAMMA = 30, /* used for colors which would be color managed before display */ - PROP_COORDS = 31, /* generic array, no units applied, only that x/y/z/w are used (python vec) */ + PROP_COLOR = 20, + PROP_TRANSLATION = 21 | PROP_UNIT_LENGTH, + PROP_DIRECTION = 22, + PROP_VELOCITY = 23 | PROP_UNIT_VELOCITY, + PROP_ACCELERATION = 24 | PROP_UNIT_ACCELERATION, + PROP_MATRIX = 25, + PROP_EULER = 26 | PROP_UNIT_ROTATION, + PROP_QUATERNION = 27, + PROP_AXISANGLE = 28, + PROP_XYZ = 29, + PROP_XYZ_LENGTH = 29 | PROP_UNIT_LENGTH, + PROP_COLOR_GAMMA = 30, /* used for colors which would be color managed before display */ + PROP_COORDS = 31, /* generic array, no units applied, only that x/y/z/w are used (python vec) */ /* booleans */ - PROP_LAYER = 40, - PROP_LAYER_MEMBER = 41 + PROP_LAYER = 40, + PROP_LAYER_MEMBER = 41, } PropertySubType; -/* Make sure enums are updated with thses */ -/* HIGHEST FLAG IN USE: 1 << 29 */ +/* Make sure enums are updated with these */ +/* HIGHEST FLAG IN USE: 1 << 30 */ typedef enum PropertyFlag { /* editable means the property is editable in the user * interface, properties are editable by default except * for pointers and collections. */ - PROP_EDITABLE = (1 << 0), + PROP_EDITABLE = (1 << 0), /* this property is editable even if it is lib linked, * meaning it will get lost on reload, but it's useful * for editing. */ - PROP_LIB_EXCEPTION = (1 << 16), + PROP_LIB_EXCEPTION = (1 << 16), /* animatable means the property can be driven by some * other input, be it animation curves, expressions, .. * properties are animatable by default except for pointers * and collections */ - PROP_ANIMATABLE = (1 << 1), + PROP_ANIMATABLE = (1 << 1), /* icon */ - PROP_ICONS_CONSECUTIVE = (1 << 12), + PROP_ICONS_CONSECUTIVE = (1 << 12), /* hidden in the user interface */ - PROP_HIDDEN = (1 << 19), + PROP_HIDDEN = (1 << 19), /* do not write in presets */ - PROP_SKIP_SAVE = (1 << 28), - - /* function paramater flags */ - PROP_REQUIRED = (1 << 2), - PROP_OUTPUT = (1 << 3), - PROP_RNAPTR = (1 << 11), + PROP_SKIP_SAVE = (1 << 28), + + /* function parameter flags */ + PROP_REQUIRED = (1 << 2), + PROP_OUTPUT = (1 << 3), + PROP_RNAPTR = (1 << 11), + /* This allows for non-breaking API updates, when adding non-critical new parameter to a callback function. + * This way, old py code defining funcs without that parameter would still work. + * WARNING: any parameter after the first PYFUNC_OPTIONAL one will be considered as optional! + * NOTE: only for input parameters! + */ + PROP_PYFUNC_OPTIONAL = (1 << 30), /* registering */ - PROP_REGISTER = (1 << 4), - PROP_REGISTER_OPTIONAL = (1 << 4) | (1 << 5), + PROP_REGISTER = (1 << 4), + PROP_REGISTER_OPTIONAL = PROP_REGISTER | (1 << 5), /* pointers */ - PROP_ID_REFCOUNT = (1 << 6), + PROP_ID_REFCOUNT = (1 << 6), /* disallow assigning a variable to its self, eg an object tracking its self * only apply this to types that are derived from an ID ()*/ - PROP_ID_SELF_CHECK = (1 << 20), + PROP_ID_SELF_CHECK = (1 << 20), /* use for... * - pointers: in the UI and python so unsetting or setting to None won't work * - strings: so our internal generated get/length/set functions know to do NULL checks before access [#30865] */ - PROP_NEVER_NULL = (1 << 18), + PROP_NEVER_NULL = (1 << 18), /* currently only used for UI, this is similar to PROP_NEVER_NULL * except that the value may be NULL at times, used for ObData, where an Empty's will be NULL * but setting NULL on a mesh object is not possible. So, if its not NULL, setting NULL cant be done! */ - PROP_NEVER_UNLINK = (1 << 25), + PROP_NEVER_UNLINK = (1 << 25), /* flag contains multiple enums. * note: not to be confused with prop->enumbitflags @@ -201,33 +207,33 @@ typedef enum PropertyFlag { * * note: these can't be animated so use with care. */ - PROP_ENUM_FLAG = (1 << 21), + PROP_ENUM_FLAG = (1 << 21), /* need context for update function */ - PROP_CONTEXT_UPDATE = (1 << 22), + PROP_CONTEXT_UPDATE = (1 << 22), PROP_CONTEXT_PROPERTY_UPDATE = (1 << 22) | (1 << 27), /* Use for arrays or for any data that should not have a reference kept * most common case is functions that return arrays where the array */ - PROP_THICK_WRAP = (1 << 23), + PROP_THICK_WRAP = (1 << 23), /* Reject values outside limits, use for python api only so far * this is for use when silently clamping string length will give * bad behavior later. Could also enforce this for INT's and other types. * note: currently no support for function arguments or non utf8 paths (filepaths) */ - PROP_NEVER_CLAMP = (1 << 26), + PROP_NEVER_CLAMP = (1 << 26), /* internal flags */ - PROP_BUILTIN = (1 << 7), - PROP_EXPORT = (1 << 8), - PROP_RUNTIME = (1 << 9), - PROP_IDPROPERTY = (1 << 10), - PROP_RAW_ACCESS = (1 << 13), - PROP_RAW_ARRAY = (1 << 14), - PROP_FREE_POINTERS = (1 << 15), - PROP_DYNAMIC = (1 << 17), /* for dynamic arrays, and retvals of type string */ - PROP_ENUM_NO_CONTEXT = (1 << 24), /* for enum that shouldn't be contextual */ - PROP_ENUM_NO_TRANSLATE = (1 << 29), /* for enums that shouldn't be translated (e.g. renderlayers' names in nodes) */ + PROP_BUILTIN = (1 << 7), + PROP_EXPORT = (1 << 8), + PROP_RUNTIME = (1 << 9), + PROP_IDPROPERTY = (1 << 10), + PROP_RAW_ACCESS = (1 << 13), + PROP_RAW_ARRAY = (1 << 14), + PROP_FREE_POINTERS = (1 << 15), + PROP_DYNAMIC = (1 << 17), /* for dynamic arrays, and retvals of type string */ + PROP_ENUM_NO_CONTEXT = (1 << 24), /* for enum that shouldn't be contextual */ + PROP_ENUM_NO_TRANSLATE = (1 << 29), /* for enums not to be translated (e.g. renderlayers' names in nodes) */ } PropertyFlag; typedef struct CollectionPropertyIterator { @@ -332,23 +338,23 @@ typedef struct ParameterDynAlloc { /* Function */ typedef enum FunctionFlag { - FUNC_NO_SELF = 1, /* for static functions */ - FUNC_USE_SELF_TYPE = 2, /* for class methods, only used when FUNC_NO_SELF is set */ - FUNC_USE_MAIN = 4, - FUNC_USE_CONTEXT = 8, - FUNC_USE_REPORTS = 16, - FUNC_USE_SELF_ID = 2048, - FUNC_ALLOW_WRITE = 4096, + FUNC_NO_SELF = (1 << 0), /* for static functions */ + FUNC_USE_SELF_TYPE = (1 << 1), /* for class methods, only used when FUNC_NO_SELF is set */ + FUNC_USE_MAIN = (1 << 2), + FUNC_USE_CONTEXT = (1 << 3), + FUNC_USE_REPORTS = (1 << 4), + FUNC_USE_SELF_ID = (1 << 11), + FUNC_ALLOW_WRITE = (1 << 12), /* registering */ - FUNC_REGISTER = 32, - FUNC_REGISTER_OPTIONAL = 32 | 64, + FUNC_REGISTER = (1 << 5), + FUNC_REGISTER_OPTIONAL = FUNC_REGISTER | (1 << 6), /* internal flags */ - FUNC_BUILTIN = 128, - FUNC_EXPORT = 256, - FUNC_RUNTIME = 512, - FUNC_FREE_POINTERS = 1024 + FUNC_BUILTIN = (1 << 7), + FUNC_EXPORT = (1 << 8), + FUNC_RUNTIME = (1 << 9), + FUNC_FREE_POINTERS = (1 << 10), } FunctionFlag; typedef void (*CallFunc)(struct bContext *C, struct ReportList *reports, PointerRNA *ptr, ParameterList *parms); @@ -359,15 +365,15 @@ typedef struct FunctionRNA FunctionRNA; typedef enum StructFlag { /* indicates that this struct is an ID struct, and to use refcounting */ - STRUCT_ID = 1, - STRUCT_ID_REFCOUNT = 2, - STRUCT_UNDO = 4, /* defaults on, clear for user preferences and similar */ + STRUCT_ID = (1 << 0), + STRUCT_ID_REFCOUNT = (1 << 1), + STRUCT_UNDO = (1 << 2), /* defaults on, clear for user preferences and similar */ /* internal flags */ - STRUCT_RUNTIME = 8, - STRUCT_GENERATED = 16, - STRUCT_FREE_POINTERS = 32, - STRUCT_NO_IDPROPERTIES = 64 /* Menu's and Panels don't need properties */ + STRUCT_RUNTIME = (1 << 3), + STRUCT_GENERATED = (1 << 4), + STRUCT_FREE_POINTERS = (1 << 5), + STRUCT_NO_IDPROPERTIES = (1 << 6), /* Menu's and Panels don't need properties */ } StructFlag; typedef int (*StructValidateFunc)(struct PointerRNA *ptr, void *data, int *have_function); diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript index 2d0c4260c97..dfe1ebb3385 100644 --- a/source/blender/makesrna/SConscript +++ b/source/blender/makesrna/SConscript @@ -36,6 +36,7 @@ incs = [ '.', './intern', '#/intern/guardedalloc', + '#/intern/atomic', '#/intern/memutil', '#/extern/glew/include', '#/intern/audaspace/intern', diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 592c518e9c0..d901897cbc4 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -23,9 +23,6 @@ # # ***** END GPL LICENSE BLOCK ***** -# Generated code has some unused vars we can ignore. -remove_strict_flags() - if(CMAKE_COMPILER_IS_GNUCC) # add here so we fail early. set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=implicit-function-declaration") @@ -124,7 +121,7 @@ set(APISRC ) string(REGEX REPLACE "rna_([a-zA-Z0-9_-]*).c" "${CMAKE_CURRENT_BINARY_DIR}/rna_\\1_gen.c" GENSRC "${DEFSRC}") -set_source_files_properties(GENSRC PROPERTIES GENERATED true) +set_source_files_properties(${GENSRC} PROPERTIES GENERATED TRUE) set(SRC_RNA_INC ../RNA_access.h @@ -276,6 +273,7 @@ blender_include_dirs( ../../../../intern/audaspace/intern ../../../../intern/cycles/blender ../../../../intern/guardedalloc + ../../../../intern/atomic ../../../../intern/memutil ../../../../intern/smoke/extern ) diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index c158facca7c..a908b403c03 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -2273,11 +2273,12 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA valstr = "*"; } - /* this must be kept in sync with RNA_parameter_length_get_data, + /* this must be kept in sync with RNA_parameter_dynamic_length_get_data and RNA_parameter_get, * we could just call the function directly, but this is faster */ if (flag & PROP_DYNAMIC) { - fprintf(f, "\t%s_len = %s((int *)_data);\n", dparm->prop->identifier, pout ? "" : "*"); - data_str = "(&(((char *)_data)[sizeof(void *)]))"; + fprintf(f, "\t%s_len = %s((ParameterDynAlloc *)_data)->array_tot;\n", dparm->prop->identifier, + pout ? "(int *)&" : "(int)"); + data_str = "(&(((ParameterDynAlloc *)_data)->array))"; } else { data_str = "_data"; @@ -2691,7 +2692,11 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F } + /* ensure func(void) if there are no args */ + if (first) fprintf(f, "void"); + fprintf(f, ")"); + if (close_prototype) fprintf(f, ";\n"); } @@ -2763,7 +2768,7 @@ static void rna_generate_struct_prototypes(FILE *f) static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, PropertyRNA *prop) { - char *strnest = "", *errnest = ""; + char *strnest = (char *)"", *errnest = (char *)""; int len, freenest = 0; if (nest != NULL) { @@ -3329,6 +3334,12 @@ static void rna_generate(BlenderRNA *brna, FILE *f, const char *filename, const fprintf(f, "#include \"%s\"\n", api_filename); fprintf(f, "\n"); + /* we want the included C files to have warnings enabled but for the generated code + * ignore unused-parameter warnings which are hard to prevent */ +#ifdef __GNUC__ + fprintf(f, "#pragma GCC diagnostic ignored \"-Wunused-parameter\"\n\n"); +#endif + fprintf(f, "/* Autogenerated Functions */\n\n"); for (ds = DefRNA.structs.first; ds; ds = ds->cont.next) { @@ -3544,8 +3555,12 @@ static const char *cpp_classes = "" " } \n" "#define COLLECTION_PROPERTY_LOOKUP_INT_TRUE(sname, identifier) \\\n" " inline static int sname##_##identifier##_lookup_int_wrap(PointerRNA *ptr, int key, PointerRNA *r_ptr) \\\n" -" { return sname##_##identifier##_lookup_int(ptr, key, r_ptr); } \n" -"\n" +" { \\\n" +" int found = sname##_##identifier##_lookup_int(ptr, key, r_ptr); \\\n" +" if (!found) \\\n" +" memset(r_ptr, 0, sizeof(*r_ptr)); \\\n" +" return found; \\\n" +" } \n" "#define COLLECTION_PROPERTY_LOOKUP_STRING_FALSE(sname, identifier) \\\n" " inline static int sname##_##identifier##_lookup_string_wrap(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) \\\n" " { \\\n" @@ -3573,8 +3588,12 @@ static const char *cpp_classes = "" " } \n" "#define COLLECTION_PROPERTY_LOOKUP_STRING_TRUE(sname, identifier) \\\n" " inline static int sname##_##identifier##_lookup_string_wrap(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) \\\n" -" { return sname##_##identifier##_lookup_string(ptr, key, r_ptr); } \n" -"\n" +" { \\\n" +" int found = sname##_##identifier##_lookup_string(ptr, key, r_ptr); \\\n" +" if (!found) \\\n" +" memset(r_ptr, 0, sizeof(*r_ptr)); \\\n" +" return found; \\\n" +" } \n" "#define COLLECTION_PROPERTY(collection_funcs, type, sname, identifier, has_length, has_lookup_int, has_lookup_string) \\\n" " typedef CollectionIterator<type, sname##_##identifier##_begin, \\\n" " sname##_##identifier##_next, sname##_##identifier##_end> identifier##_iterator; \\\n" diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 26febf217a6..075f852a032 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -36,6 +36,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "WM_types.h" @@ -57,7 +58,7 @@ EnumPropertyItem id_type_items[] = { {ID_KE, "KEY", ICON_SHAPEKEY_DATA, "Key", ""}, {ID_LA, "LAMP", ICON_LAMP_DATA, "Lamp", ""}, {ID_LI, "LIBRARY", ICON_LIBRARY_DATA_DIRECT, "Library", ""}, - {ID_LS, "LINESTYLE", ICON_PARTICLE_DATA, "FreestyleLineStyle", ""}, /* FIXME proper icon */ + {ID_LS, "LINESTYLE", ICON_BRUSH_DATA, "Line Style", ""}, /* FIXME proper icon */ {ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""}, {ID_MA, "MATERIAL", ICON_MATERIAL_DATA, "Material", ""}, {ID_MB, "META", ICON_META_DATA, "MetaBall", ""}, diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index f3e561cde0a..341ba02fd47 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -49,6 +49,7 @@ #include "BKE_context.h" #include "BKE_idcode.h" #include "BKE_idprop.h" +#include "BKE_fcurve.h" #include "BKE_main.h" #include "BKE_report.h" @@ -650,7 +651,7 @@ static PropertyRNA *RNA_struct_find_nested(PointerRNA *ptr, StructRNA *srna) { PropertyRNA *prop = NULL; - RNA_STRUCT_BEGIN(ptr, iprop) + RNA_STRUCT_BEGIN (ptr, iprop) { /* This assumes that there can only be one user of this nested struct */ if (RNA_property_pointer_type(ptr, iprop) == srna) { @@ -673,7 +674,7 @@ bool RNA_struct_contains_property(PointerRNA *ptr, PropertyRNA *prop_test) iterprop = RNA_struct_iterator_property(ptr->type); - RNA_PROP_BEGIN(ptr, itemptr, iterprop) + RNA_PROP_BEGIN (ptr, itemptr, iterprop) { /* PropertyRNA *prop = itemptr.data; */ if (prop_test == (PropertyRNA *)itemptr.data) { @@ -721,7 +722,7 @@ FunctionRNA *RNA_struct_find_function(StructRNA *srna, const char *identifier) func = NULL; - RNA_PROP_BEGIN(&tptr, funcptr, iterprop) + RNA_PROP_BEGIN (&tptr, funcptr, iterprop) { if (strcmp(identifier, RNA_function_identifier(funcptr.data)) == 0) { func = funcptr.data; @@ -1512,14 +1513,24 @@ bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop) return (prop->flag & PROP_EDITABLE) != 0; } -bool RNA_property_animated(PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop)) +bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop) { - /* would need to ask animation system */ + int len = 1, index; + bool driven; + + if (!prop) + return false; + + if (RNA_property_array_check(prop)) + len = RNA_property_array_length(ptr, prop); + + for (index = 0; index < len; index++) + if (rna_get_fcurve(ptr, prop, index, NULL, &driven)) + return true; return false; } - /* this function is to check if its possible to create a valid path from the ID * its slow so don't call in a loop */ bool RNA_property_path_from_ID_check(PointerRNA *ptr, PropertyRNA *prop) @@ -3329,7 +3340,7 @@ static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *pro } /* no item property pointer, can still be id property, or * property of a type derived from the collection pointer type */ - RNA_PROP_BEGIN(ptr, itemptr, prop) + RNA_PROP_BEGIN (ptr, itemptr, prop) { if (itemptr.data) { if (itemprop) { @@ -4164,7 +4175,7 @@ static char *rna_idp_path_create(IDP_Chain *child_link) { DynStr *dynstr = BLI_dynstr_new(); char *path; - short first = TRUE; + bool is_first = true; int tot = 0; IDP_Chain *link = child_link; @@ -4183,13 +4194,13 @@ static char *rna_idp_path_create(IDP_Chain *child_link) for (link = link_prev; link; link = link->up) { /* pass */ if (link->index >= 0) { - BLI_dynstr_appendf(dynstr, first ? "%s[%d]" : ".%s[%d]", link->name, link->index); + BLI_dynstr_appendf(dynstr, is_first ? "%s[%d]" : ".%s[%d]", link->name, link->index); } else { - BLI_dynstr_appendf(dynstr, first ? "%s" : ".%s", link->name); + BLI_dynstr_appendf(dynstr, is_first ? "%s" : ".%s", link->name); } - first = FALSE; + is_first = false; } path = BLI_dynstr_get_cstring(dynstr); @@ -4408,10 +4419,12 @@ char *RNA_path_full_struct_py(struct PointerRNA *ptr) data_path = RNA_path_from_ID_to_struct(ptr); - ret = BLI_sprintfN("%s.%s", - id_path, data_path); + /* XXX data_path may be NULL (see #36788), do we want to get the 'bpy.data.foo["bar"].(null)' stuff? */ + ret = BLI_sprintfN("%s.%s", id_path, data_path); - MEM_freeN(data_path); + if (data_path) { + MEM_freeN(data_path); + } MEM_freeN(id_path); return ret; @@ -4982,7 +4995,7 @@ static char *rna_pointer_as_string__idprop(bContext *C, PointerRNA *ptr) BLI_dynstr_append(dynstr, "{"); - RNA_STRUCT_BEGIN(ptr, prop) + RNA_STRUCT_BEGIN (ptr, prop) { propname = RNA_property_identifier(prop); @@ -5030,9 +5043,9 @@ char *RNA_pointer_as_string(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *p } } -/* context and ptr_default can be NULL */ -char *RNA_pointer_as_string_keywords_ex(bContext *C, PointerRNA *ptr, PointerRNA *ptr_default, - const short as_function, const short all_args, +/* context can be NULL */ +char *RNA_pointer_as_string_keywords_ex(bContext *C, PointerRNA *ptr, + const bool as_function, const bool all_args, const int max_prop_length, PropertyRNA *iterprop) { @@ -5042,14 +5055,10 @@ char *RNA_pointer_as_string_keywords_ex(bContext *C, PointerRNA *ptr, PointerRNA DynStr *dynstr = BLI_dynstr_new(); char *cstring, *buf; - int first_iter = TRUE, ok = TRUE; + bool first_iter = true; int flag; - /* only to get the orginal props for comparisons */ - PropertyRNA *prop_default; - char *buf_default; - - RNA_PROP_BEGIN(ptr, propptr, iterprop) + RNA_PROP_BEGIN (ptr, propptr, iterprop) { prop = propptr.data; @@ -5068,45 +5077,37 @@ char *RNA_pointer_as_string_keywords_ex(bContext *C, PointerRNA *ptr, PointerRNA if (as_function && (flag & PROP_REQUIRED)) { /* required args don't have useful defaults */ BLI_dynstr_appendf(dynstr, first_iter ? "%s" : ", %s", arg_name); - first_iter = FALSE; + first_iter = false; } else { - if (as_function && RNA_property_type(prop) == PROP_POINTER) { - /* don't expand pointers for functions */ - if (flag & PROP_NEVER_NULL) { - /* we cant really do the right thing here. arg=arg?, hrmf! */ - buf = BLI_strdup(arg_name); - } - else { - buf = BLI_strdup("None"); - } + bool ok = true; + + if (all_args == true) { + /* pass */ } - else { - buf = RNA_property_as_string(C, ptr, prop, -1, max_prop_length); + else if (RNA_struct_idprops_check(ptr->type)) { + ok = RNA_property_is_set(ptr, prop); } - ok = TRUE; - - if (all_args == FALSE && ptr_default) { - /* not verbose, so only add in attributes that use non-default values - * slow but good for tooltips */ - prop_default = RNA_struct_find_property(ptr_default, arg_name); - - if (prop_default) { - buf_default = RNA_property_as_string(C, ptr_default, prop_default, -1, max_prop_length); - - if (strcmp(buf, buf_default) == 0) - ok = FALSE; /* values match, don't bother printing */ - - MEM_freeN(buf_default); - } - } if (ok) { + if (as_function && RNA_property_type(prop) == PROP_POINTER) { + /* don't expand pointers for functions */ + if (flag & PROP_NEVER_NULL) { + /* we cant really do the right thing here. arg=arg?, hrmf! */ + buf = BLI_strdup(arg_name); + } + else { + buf = BLI_strdup("None"); + } + } + else { + buf = RNA_property_as_string(C, ptr, prop, -1, max_prop_length); + } + BLI_dynstr_appendf(dynstr, first_iter ? "%s=%s" : ", %s=%s", arg_name, buf); - first_iter = FALSE; + first_iter = false; + MEM_freeN(buf); } - - MEM_freeN(buf); } } RNA_PROP_END; @@ -5116,20 +5117,20 @@ char *RNA_pointer_as_string_keywords_ex(bContext *C, PointerRNA *ptr, PointerRNA return cstring; } -char *RNA_pointer_as_string_keywords(bContext *C, PointerRNA *ptr, PointerRNA *ptr_default, - const short as_function, const short all_args, +char *RNA_pointer_as_string_keywords(bContext *C, PointerRNA *ptr, + const bool as_function, const bool all_args, const int max_prop_length) { PropertyRNA *iterprop; iterprop = RNA_struct_iterator_property(ptr->type); - return RNA_pointer_as_string_keywords_ex(C, ptr, ptr_default, as_function, all_args, + return RNA_pointer_as_string_keywords_ex(C, ptr, as_function, all_args, max_prop_length, iterprop); } -char *RNA_function_as_string_keywords(bContext *C, FunctionRNA *func, PointerRNA *ptr_default, - const short as_function, const short all_args, +char *RNA_function_as_string_keywords(bContext *C, FunctionRNA *func, + const bool as_function, const bool all_args, const int max_prop_length) { PointerRNA funcptr; @@ -5141,7 +5142,7 @@ char *RNA_function_as_string_keywords(bContext *C, FunctionRNA *func, PointerRNA RNA_struct_iterator_property(funcptr.type); - return RNA_pointer_as_string_keywords_ex(C, &funcptr, ptr_default, as_function, all_args, + return RNA_pointer_as_string_keywords_ex(C, &funcptr, as_function, all_args, max_prop_length, iterprop); } @@ -5160,7 +5161,7 @@ char *RNA_property_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop, in char *cstring; - /* see if we can coorce into a python type - PropertyType */ + /* see if we can coerce into a python type - PropertyType */ switch (type) { case PROP_BOOLEAN: if (len == 0) { @@ -5252,11 +5253,11 @@ char *RNA_property_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop, in RNA_property_enum_items(C, ptr, prop, &item, NULL, &free); if (item) { - short is_first = TRUE; + bool is_first = false; for (; item->identifier; item++) { if (item->identifier[0] && item->value & val) { BLI_dynstr_appendf(dynstr, is_first ? "'%s'" : ", '%s'", item->identifier); - is_first = FALSE; + is_first = false; } } @@ -5357,7 +5358,14 @@ PropertyRNA *RNA_function_get_parameter(PointerRNA *UNUSED(ptr), FunctionRNA *fu PropertyRNA *RNA_function_find_parameter(PointerRNA *UNUSED(ptr), FunctionRNA *func, const char *identifier) { - return BLI_findstring(&func->cont.properties, identifier, offsetof(PropertyRNA, identifier)); + PropertyRNA *parm; + + parm = func->cont.properties.first; + for (; parm; parm = parm->next) + if (strcmp(RNA_property_identifier(parm), identifier) == 0) + break; + + return parm; } const ListBase *RNA_function_defined_parameters(FunctionRNA *func) @@ -5529,10 +5537,19 @@ void RNA_parameter_get(ParameterList *parms, PropertyRNA *parm, void **value) if (iter.parm == parm) break; - if (iter.valid) - *value = iter.data; - else + if (iter.valid) { + if (parm->flag & PROP_DYNAMIC) { + /* for dynamic arrays and strings, data is a pointer to an array */ + ParameterDynAlloc *data_alloc = iter.data; + *value = data_alloc->array; + } + else { + *value = iter.data; + } + } + else { *value = NULL; + } RNA_parameter_list_end(&iter); } @@ -5560,8 +5577,35 @@ void RNA_parameter_set(ParameterList *parms, PropertyRNA *parm, const void *valu if (iter.parm == parm) break; - if (iter.valid) - memcpy(iter.data, value, iter.size); + if (iter.valid) { + if (parm->flag & PROP_DYNAMIC) { + /* for dynamic arrays and strings, data is a pointer to an array */ + ParameterDynAlloc *data_alloc = iter.data; + size_t size = 0; + switch (parm->type) { + case PROP_STRING: + size = sizeof(char); + break; + case PROP_INT: + case PROP_BOOLEAN: + size = sizeof(int); + break; + case PROP_FLOAT: + size = sizeof(float); + break; + default: + break; + } + size *= data_alloc->array_tot; + if (data_alloc->array) + MEM_freeN(data_alloc->array); + data_alloc->array = MEM_mallocN(size, AT); + memcpy(data_alloc->array, value, size); + } + else { + memcpy(iter.data, value, iter.size); + } + } RNA_parameter_list_end(&iter); } @@ -5579,7 +5623,7 @@ void RNA_parameter_set_lookup(ParameterList *parms, const char *identifier, cons RNA_parameter_set(parms, parm, value); } -int RNA_parameter_length_get(ParameterList *parms, PropertyRNA *parm) +int RNA_parameter_dynamic_length_get(ParameterList *parms, PropertyRNA *parm) { ParameterIterator iter; int len = 0; @@ -5591,14 +5635,14 @@ int RNA_parameter_length_get(ParameterList *parms, PropertyRNA *parm) break; if (iter.valid) - len = RNA_parameter_length_get_data(parms, parm, iter.data); + len = RNA_parameter_dynamic_length_get_data(parms, parm, iter.data); RNA_parameter_list_end(&iter); return len; } -void RNA_parameter_length_set(ParameterList *parms, PropertyRNA *parm, int length) +void RNA_parameter_dynamic_length_set(ParameterList *parms, PropertyRNA *parm, int length) { ParameterIterator iter; @@ -5609,19 +5653,24 @@ void RNA_parameter_length_set(ParameterList *parms, PropertyRNA *parm, int lengt break; if (iter.valid) - RNA_parameter_length_set_data(parms, parm, iter.data, length); + RNA_parameter_dynamic_length_set_data(parms, parm, iter.data, length); RNA_parameter_list_end(&iter); } -int RNA_parameter_length_get_data(ParameterList *UNUSED(parms), PropertyRNA *UNUSED(parm), void *data) +int RNA_parameter_dynamic_length_get_data(ParameterList *UNUSED(parms), PropertyRNA *parm, void *data) { - return *((int *)((char *)data)); + if (parm->flag & PROP_DYNAMIC) { + return (int)((ParameterDynAlloc *)data)->array_tot; + } + return 0; } -void RNA_parameter_length_set_data(ParameterList *UNUSED(parms), PropertyRNA *UNUSED(parm), void *data, int length) +void RNA_parameter_dynamic_length_set_data(ParameterList *UNUSED(parms), PropertyRNA *parm, void *data, int length) { - *((int *)data) = length; + if (parm->flag & PROP_DYNAMIC) { + ((ParameterDynAlloc *)data)->array_tot = (intptr_t)length; + } } int RNA_function_call(bContext *C, ReportList *reports, PointerRNA *ptr, FunctionRNA *func, ParameterList *parms) @@ -6269,14 +6318,20 @@ void _RNA_warning(const char *format, ...) #endif } -bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, bool is_strict) +bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNAEqualsMode mode) { int len, fromlen; - /* if not strict, uninitialized properties are assumed to match */ - if (!is_strict) - if (!(RNA_property_is_set(a, prop) && RNA_property_is_set(b, prop))) + if (mode == RNA_EQ_UNSET_MATCH_ANY) { + /* uninitialized properties are assumed to match anything */ + if (!RNA_property_is_set(a, prop) || !RNA_property_is_set(b, prop)) return true; + } + else if (mode == RNA_EQ_UNSET_MATCH_NONE) { + /* unset properties never match set properties */ + if (RNA_property_is_set(a, prop) != RNA_property_is_set(b, prop)) + return false; + } /* get the length of the array to work with */ len = RNA_property_array_length(a, prop); @@ -6390,7 +6445,7 @@ bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, bool i if (!STREQ(RNA_property_identifier(prop), "rna_type")) { PointerRNA propptr_a = RNA_property_pointer_get(a, prop); PointerRNA propptr_b = RNA_property_pointer_get(b, prop); - return RNA_struct_equals(&propptr_a, &propptr_b, is_strict); + return RNA_struct_equals(&propptr_a, &propptr_b, mode); } break; } @@ -6402,7 +6457,7 @@ bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, bool i return true; } -bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, bool is_strict) +bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNAEqualsMode mode) { CollectionPropertyIterator iter; // CollectionPropertyRNA *citerprop; /* UNUSED */ @@ -6423,7 +6478,7 @@ bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, bool is_strict) for (; iter.valid; RNA_property_collection_next(&iter)) { PropertyRNA *prop = iter.ptr.data; - if (!RNA_property_equals(a, b, prop, is_strict)) { + if (!RNA_property_equals(a, b, prop, mode)) { equals = false; break; } diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 44ce081f68f..c5b7c88d8fc 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -191,7 +191,8 @@ static void rna_Action_active_pose_marker_index_set(PointerRNA *ptr, int value) act->active_marker = value + 1; } -static void rna_Action_active_pose_marker_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_Action_active_pose_marker_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { bAction *act = (bAction *)ptr->data; @@ -490,7 +491,7 @@ static void rna_def_action_group(BlenderRNA *brna) prop = RNA_def_property(srna, "channels", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "channels", NULL); RNA_def_property_struct_type(prop, "FCurve"); - RNA_def_property_collection_funcs(prop, 0, "rna_ActionGroup_channels_next", NULL, NULL, NULL, NULL, NULL, NULL); + RNA_def_property_collection_funcs(prop, NULL, "rna_ActionGroup_channels_next", NULL, NULL, NULL, NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Channels", "F-Curves in this group"); prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index 134c5bcbee4..a07a000dacb 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -45,7 +45,7 @@ #include "WM_types.h" /* Always keep in alphabetical order */ -EnumPropertyItem actuator_type_items[] = { +static EnumPropertyItem actuator_type_items[] = { {ACT_ACTION, "ACTION", 0, "Action", ""}, {ACT_ARMATURE, "ARMATURE", 0, "Armature", ""}, {ACT_CAMERA, "CAMERA", 0, "Camera", ""}, @@ -593,6 +593,12 @@ static void rna_def_action_actuator(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_blend_items[] = { + {ACT_ACTION_BLEND, "BLEND", 0, "Blend", ""}, + {ACT_ACTION_ADD, "ADD", 0, "Add", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "ActionActuator", "Actuator"); RNA_def_struct_ui_text(srna, "Action Actuator", "Actuator to control the object movement"); RNA_def_struct_sdna_from(srna, "bActionActuator", "data"); @@ -656,7 +662,7 @@ static void rna_def_action_actuator(BlenderRNA *brna) prop = RNA_def_property(srna, "layer_weight", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_ui_text(prop, "Layer Weight", - "How much of the previous layer to blend into this one (0 = add mode)"); + "How much of the previous layer to blend into this one"); RNA_def_property_update(prop, NC_LOGIC, NULL); prop = RNA_def_property(srna, "frame_property", PROP_STRING, PROP_NONE); @@ -691,6 +697,12 @@ static void rna_def_action_actuator(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Child", "Update Action on all children Objects as well"); RNA_def_property_update(prop, NC_LOGIC, NULL); + prop = RNA_def_property(srna, "blend_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "blend_mode"); + RNA_def_property_enum_items(prop, prop_blend_items); + RNA_def_property_ui_text(prop, "Blend Mode", "How this layer is blended with previous layers"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + #ifdef __NLA_ACTION_BY_MOTION_ACTUATOR prop = RNA_def_property(srna, "stride_length", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "stridelength"); diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index 7bdaca3c847..31fdd19f169 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -408,7 +408,8 @@ static void rna_KeyingSet_active_ksPath_index_set(PointerRNA *ptr, int value) ks->active_path = value + 1; } -static void rna_KeyingSet_active_ksPath_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_KeyingSet_active_ksPath_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { KeyingSet *ks = (KeyingSet *)ptr->data; diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c index 9f8f30b00a7..ee107fdfe9f 100644 --- a/source/blender/makesrna/intern/rna_animviz.c +++ b/source/blender/makesrna/intern/rna_animviz.c @@ -26,8 +26,6 @@ #include <stdlib.h> -#include "RNA_define.h" - #include "DNA_anim_types.h" #include "DNA_action_types.h" #include "DNA_scene_types.h" @@ -36,6 +34,9 @@ #include "MEM_guardedalloc.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + #include "rna_internal.h" #include "WM_types.h" diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index a832a8cdf96..b9cbbdb32f7 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -921,7 +921,7 @@ static void rna_def_armature(BlenderRNA *brna) /* Collections */ prop = RNA_def_property(srna, "bones", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "bonebase", NULL); - RNA_def_property_collection_funcs(prop, 0, "rna_Armature_bones_next", NULL, NULL, NULL, NULL, NULL, NULL); + RNA_def_property_collection_funcs(prop, NULL, "rna_Armature_bones_next", NULL, NULL, NULL, NULL, NULL, NULL); RNA_def_property_struct_type(prop, "Bone"); RNA_def_property_ui_text(prop, "Bones", ""); rna_def_armature_bones(brna, prop); diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c index 9b2ce863108..6233649fb12 100644 --- a/source/blender/makesrna/intern/rna_boid.c +++ b/source/blender/makesrna/intern/rna_boid.c @@ -41,6 +41,7 @@ #include "BLI_utildefines.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -69,7 +70,8 @@ EnumPropertyItem boidrule_type_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem boidruleset_type_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem boidruleset_type_items[] = { {eBoidRulesetType_Fuzzy, "FUZZY", 0, "Fuzzy", "Rules are gone through top to bottom (only the first rule which effect is above " "fuzziness threshold is evaluated)"}, @@ -77,6 +79,7 @@ EnumPropertyItem boidruleset_type_items[] = { {eBoidRulesetType_Average, "AVERAGE", 0, "Average", "All rules are averaged"}, {0, NULL, 0, NULL, NULL} }; +#endif #ifdef RNA_RUNTIME @@ -161,7 +164,8 @@ static PointerRNA rna_BoidState_active_boid_rule_get(PointerRNA *ptr) } return rna_pointer_inherit_refine(ptr, &RNA_BoidRule, NULL); } -static void rna_BoidState_active_boid_rule_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_BoidState_active_boid_rule_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { BoidState *state = (BoidState *)ptr->data; *min = 0; @@ -227,7 +231,7 @@ static PointerRNA rna_BoidSettings_active_boid_state_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_BoidState, NULL); } static void rna_BoidSettings_active_boid_state_index_range(PointerRNA *ptr, int *min, int *max, - int *softmin, int *softmax) + int *UNUSED(softmin), int *UNUSED(softmax)) { BoidSettings *boids = (BoidSettings *)ptr->data; *min = 0; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 5d68a6905a3..405d38e9683 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -27,8 +27,6 @@ #include <stdlib.h> #include <assert.h> -#include "RNA_define.h" - #include "DNA_brush_types.h" #include "DNA_texture_types.h" #include "DNA_scene_types.h" @@ -36,6 +34,9 @@ #include "BLI_math.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + #include "rna_internal.h" #include "IMB_imbuf.h" diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index ebd06475c79..d848acd5971 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -110,7 +110,8 @@ static void rna_CurveMapping_white_level_set(PointerRNA *ptr, const float *value curvemapping_set_black_white(cumap, NULL, NULL); } -static void rna_CurveMapping_clipminx_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_CurveMapping_clipminx_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { CurveMapping *cumap = (CurveMapping *)ptr->data; @@ -118,7 +119,8 @@ static void rna_CurveMapping_clipminx_range(PointerRNA *ptr, float *min, float * *max = cumap->clipr.xmax; } -static void rna_CurveMapping_clipminy_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_CurveMapping_clipminy_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { CurveMapping *cumap = (CurveMapping *)ptr->data; @@ -126,7 +128,8 @@ static void rna_CurveMapping_clipminy_range(PointerRNA *ptr, float *min, float * *max = cumap->clipr.ymax; } -static void rna_CurveMapping_clipmaxx_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_CurveMapping_clipmaxx_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { CurveMapping *cumap = (CurveMapping *)ptr->data; @@ -134,7 +137,8 @@ static void rna_CurveMapping_clipmaxx_range(PointerRNA *ptr, float *min, float * *max = 100.0f; } -static void rna_CurveMapping_clipmaxy_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_CurveMapping_clipmaxy_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { CurveMapping *cumap = (CurveMapping *)ptr->data; @@ -407,8 +411,8 @@ static void rna_ColorManagedDisplaySettings_display_device_set(struct PointerRNA } } -static EnumPropertyItem *rna_ColorManagedDisplaySettings_display_device_itemf(bContext *UNUSED(C), PointerRNA *ptr, - PropertyRNA *UNUSED(prop), int *free) +static EnumPropertyItem *rna_ColorManagedDisplaySettings_display_device_itemf( + bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) { EnumPropertyItem *items = NULL; int totitem = 0; @@ -455,8 +459,8 @@ static void rna_ColorManagedViewSettings_view_transform_set(PointerRNA *ptr, int } } -static EnumPropertyItem *rna_ColorManagedViewSettings_view_transform_itemf(bContext *C, PointerRNA *ptr, - PropertyRNA *UNUSED(prop), int *free) +static EnumPropertyItem *rna_ColorManagedViewSettings_view_transform_itemf( + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) { Scene *scene = CTX_data_scene(C); EnumPropertyItem *items = NULL; @@ -470,6 +474,37 @@ static EnumPropertyItem *rna_ColorManagedViewSettings_view_transform_itemf(bCont return items; } +static int rna_ColorManagedViewSettings_look_get(PointerRNA *ptr) +{ + ColorManagedViewSettings *view = (ColorManagedViewSettings *) ptr->data; + + return IMB_colormanagement_look_get_named_index(view->look); +} + +static void rna_ColorManagedViewSettings_look_set(PointerRNA *ptr, int value) +{ + ColorManagedViewSettings *view = (ColorManagedViewSettings *) ptr->data; + + const char *name = IMB_colormanagement_look_get_indexed_name(value); + + if (name) { + BLI_strncpy(view->look, name, sizeof(view->look)); + } +} + +static EnumPropertyItem *rna_ColorManagedViewSettings_look_itemf( + bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) +{ + EnumPropertyItem *items = NULL; + int totitem = 0; + + IMB_colormanagement_look_items_add(&items, &totitem); + RNA_enum_item_end(&items, &totitem); + + *free = TRUE; + return items; +} + static void rna_ColorManagedViewSettings_use_curves_set(PointerRNA *ptr, int value) { ColorManagedViewSettings *view_settings = (ColorManagedViewSettings *) ptr->data; @@ -503,8 +538,8 @@ static void rna_ColorManagedColorspaceSettings_colorspace_set(struct PointerRNA } } -static EnumPropertyItem *rna_ColorManagedColorspaceSettings_colorspace_itemf(bContext *UNUSED(C), PointerRNA *ptr, - PropertyRNA *UNUSED(prop), int *free) +static EnumPropertyItem *rna_ColorManagedColorspaceSettings_colorspace_itemf( + bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) { EnumPropertyItem *items = NULL; int totitem = 0; @@ -584,16 +619,25 @@ static void rna_ColorManagement_update(Main *UNUSED(bmain), Scene *UNUSED(scene) return; if (GS(id->name) == ID_SCE) { + DAG_id_tag_update(id, 0); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL); } } /* this function only exists because #curvemap_evaluateF uses a 'const' qualifier */ -static float rna_CurveMap_evaluateF(struct CurveMap *cuma, float value) +static float rna_CurveMap_evaluateF(struct CurveMap *cuma, ReportList *reports, float value) { + if (!cuma->table) { + BKE_reportf(reports, RPT_ERROR, "CurveMap table not initialized, call initialize() on CurveMapping owner of the CurveMap"); + return 0.0f; + } return curvemap_evaluateF(cuma, value); } +static void rna_CurveMap_initialize(struct CurveMapping *cumap) +{ + curvemapping_initialize(cumap); +} #else static void rna_def_curvemappoint(BlenderRNA *brna) @@ -679,6 +723,7 @@ static void rna_def_curvemap(BlenderRNA *brna) rna_def_curvemap_points_api(brna, prop); func = RNA_def_function(srna, "evaluate", "rna_CurveMap_evaluateF"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Evaluate curve at given location"); parm = RNA_def_float(func, "position", 0.0f, -FLT_MAX, FLT_MAX, "Position", "Position to evaluate curve at", -FLT_MAX, FLT_MAX); RNA_def_property_flag(parm, PROP_REQUIRED); @@ -747,6 +792,9 @@ static void rna_def_curvemapping(BlenderRNA *brna) func = RNA_def_function(srna, "update", "curvemapping_changed_all"); RNA_def_function_ui_description(func, "Update curve mapping after making changes"); + + func = RNA_def_function(srna, "initialize", "rna_CurveMap_initialize"); + RNA_def_function_ui_description(func, "Initialize curve"); } static void rna_def_color_ramp_element(BlenderRNA *brna) @@ -946,6 +994,11 @@ static void rna_def_colormanage(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem look_items[] = { + {0, "NONE", 0, "None", "Do not modify image in an artistic manner"}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem view_transform_items[] = { {0, "NONE", 0, "None", "Do not perform any color transform on display, use old non-color managed technique for display"}, {0, NULL, 0, NULL, NULL} @@ -972,12 +1025,20 @@ static void rna_def_colormanage(BlenderRNA *brna) srna = RNA_def_struct(brna, "ColorManagedViewSettings", NULL); RNA_def_struct_ui_text(srna, "ColorManagedViewSettings", "Color management settings used for displaying images on the display"); + prop = RNA_def_property(srna, "look", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, look_items); + RNA_def_property_enum_funcs(prop, "rna_ColorManagedViewSettings_look_get", + "rna_ColorManagedViewSettings_look_set", + "rna_ColorManagedViewSettings_look_itemf"); + RNA_def_property_ui_text(prop, "Look", "Additional transform applied before view transform for an artistic needs"); + RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagement_update"); + prop = RNA_def_property(srna, "view_transform", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, view_transform_items); RNA_def_property_enum_funcs(prop, "rna_ColorManagedViewSettings_view_transform_get", "rna_ColorManagedViewSettings_view_transform_set", "rna_ColorManagedViewSettings_view_transform_itemf"); - RNA_def_property_ui_text(prop, "View Transform", "View used "); + RNA_def_property_ui_text(prop, "View Transform", "View used when converting image to a display space"); RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagement_update"); prop = RNA_def_property(srna, "exposure", PROP_FLOAT, PROP_FACTOR); diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 05d4c5a59d2..f8483d7b221 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -37,6 +37,7 @@ #include "DNA_scene_types.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -343,7 +344,8 @@ static EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSED(C), return space_object_items; } -static void rna_ActionConstraint_minmax_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_ActionConstraint_minmax_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { bConstraint *con = (bConstraint *)ptr->data; bActionConstraint *acon = (bActionConstraint *)con->data; @@ -464,7 +466,7 @@ static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, PointerRNA v #else -EnumPropertyItem constraint_distance_items[] = { +static EnumPropertyItem constraint_distance_items[] = { {LIMITDIST_INSIDE, "LIMITDIST_INSIDE", 0, "Inside", "The object is constrained inside a virtual sphere around the target object, " "with a radius defined by the limit distance"}, @@ -1083,7 +1085,8 @@ static void rna_def_constraint_minmax(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_range(prop, 0.0, 100.f); + RNA_def_property_range(prop, -1000.0, 1000.0f); + RNA_def_property_ui_range(prop, -100.0f, 100.0f, 1, -1); RNA_def_property_ui_text(prop, "Offset", "Offset of floor from object origin"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); } @@ -2024,20 +2027,23 @@ static void rna_def_constraint_shrinkwrap(BlenderRNA *brna) RNA_def_property_range(prop, 0.0, 100.f); RNA_def_property_ui_text(prop, "Distance", "Distance to Target"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); - - prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "projAxis", MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS); - RNA_def_property_ui_text(prop, "Axis X", "Projection over X Axis"); - RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); - - prop = RNA_def_property(srna, "use_y", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "projAxis", MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS); - RNA_def_property_ui_text(prop, "Axis Y", "Projection over Y Axis"); + + prop = RNA_def_property(srna, "project_axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "projAxis"); + RNA_def_property_enum_items(prop, object_axis_items); + RNA_def_property_ui_text(prop, "Project Axis", "Axis constrain to"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); - - prop = RNA_def_property(srna, "use_z", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "projAxis", MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS); - RNA_def_property_ui_text(prop, "Axis Z", "Projection over Z Axis"); + + prop = RNA_def_property(srna, "project_axis_space", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "projAxisSpace"); + RNA_def_property_enum_items(prop, owner_space_pchan_items); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Constraint_owner_space_itemf"); + RNA_def_property_ui_text(prop, "Axis Space", "Space for the projection axis"); + + prop = RNA_def_property(srna, "project_limit", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "projLimit"); + RNA_def_property_range(prop, 0.0, 100.f); + RNA_def_property_ui_text(prop, "Project Distance", "Limit the distance used for projection (zero disables)"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); } diff --git a/source/blender/makesrna/intern/rna_controller.c b/source/blender/makesrna/intern/rna_controller.c index 28a2ca7cb75..3b789b16f52 100644 --- a/source/blender/makesrna/intern/rna_controller.c +++ b/source/blender/makesrna/intern/rna_controller.c @@ -34,6 +34,7 @@ #include "BLF_translation.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index 21bf2ec6719..bd4b8dd76b1 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -46,13 +46,15 @@ #include "BKE_curve.h" #include "ED_curve.h" -EnumPropertyItem beztriple_handle_type_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem beztriple_handle_type_items[] = { {HD_FREE, "FREE", 0, "Free", ""}, {HD_VECT, "VECTOR", 0, "Vector", ""}, {HD_ALIGN, "ALIGNED", 0, "Aligned", ""}, {HD_AUTO, "AUTO", 0, "Auto", ""}, {0, NULL, 0, NULL, NULL} }; +#endif EnumPropertyItem keyframe_handle_type_items[] = { {HD_FREE, "FREE", 0, "Free", ""}, @@ -70,7 +72,8 @@ EnumPropertyItem beztriple_interpolation_mode_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem curve_type_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem curve_type_items[] = { {CU_POLY, "POLY", 0, "Poly", ""}, {CU_BEZIER, "BEZIER", 0, "Bezier", ""}, {CU_BSPLINE, "BSPLINE", 0, "BSpline", ""}, @@ -78,6 +81,7 @@ EnumPropertyItem curve_type_items[] = { {CU_NURBS, "NURBS", 0, "Ease", ""}, {0, NULL, 0, NULL, NULL} }; +#endif static const EnumPropertyItem curve3d_fill_mode_items[] = { {0, "FULL", 0, "Full", ""}, @@ -239,14 +243,16 @@ static void rna_Curve_texspace_size_set(PointerRNA *ptr, const float *values) copy_v3_v3(cu->size, values); } -static void rna_Curve_material_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_Curve_material_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { Curve *cu = (Curve *)ptr->id.data; *min = 0; *max = max_ii(0, cu->totcol - 1); } -static void rna_Curve_active_textbox_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_Curve_active_textbox_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { Curve *cu = (Curve *)ptr->id.data; *min = 0; @@ -568,6 +574,10 @@ static Nurb *rna_Curve_spline_new(Curve *cu, int type) nu->resolu = nu->resolv = 12; nu->flag = CU_SMOOTH; + if ((cu->flag & CU_3D) == 0) { + nu->flag |= CU_2D; + } + BLI_addtail(BKE_curve_nurbs_get(cu), nu); return nu; @@ -1484,7 +1494,7 @@ static void rna_def_curve(BlenderRNA *brna) RNA_def_property_struct_type(prop, "Material"); RNA_def_property_ui_text(prop, "Materials", ""); RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */ - RNA_def_property_collection_funcs(prop, 0, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int"); + RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int"); prop = RNA_def_property(srna, "bevel_factor_start", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "bevfac1"); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 723f158bb50..b153728050c 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -574,13 +574,13 @@ void RNA_define_free(BlenderRNA *UNUSED(brna)) DefRNA.error = 0; } -void RNA_define_verify_sdna(int verify) +void RNA_define_verify_sdna(bool verify) { DefRNA.verify = verify; } #ifndef RNA_RUNTIME -void RNA_define_animate_sdna(int animate) +void RNA_define_animate_sdna(bool animate) { DefRNA.animate = animate; } @@ -1321,6 +1321,26 @@ void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double { StructRNA *srna = DefRNA.laststruct; +#ifdef DEBUG + if (min > max) { + fprintf(stderr, "%s: \"%s.%s\", min > max.\n", + __func__, srna->identifier, prop->identifier); + DefRNA.error = 1; + } + + if (step < 0 || step > 100) { + fprintf(stderr, "%s: \"%s.%s\", step outside range.\n", + __func__, srna->identifier, prop->identifier); + DefRNA.error = 1; + } + + if (precision < -1 || precision > 10) { + fprintf(stderr, "%s: \"%s.%s\", step outside range.\n", + __func__, srna->identifier, prop->identifier); + DefRNA.error = 1; + } +#endif + switch (prop->type) { case PROP_INT: { @@ -1366,6 +1386,14 @@ void RNA_def_property_range(PropertyRNA *prop, double min, double max) { StructRNA *srna = DefRNA.laststruct; +#ifdef DEBUG + if (min > max) { + fprintf(stderr, "%s: \"%s.%s\", min > max.\n", + __func__, srna->identifier, prop->identifier); + DefRNA.error = 1; + } +#endif + switch (prop->type) { case PROP_INT: { @@ -2096,7 +2124,7 @@ void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *func) prop->update = (UpdateFunc)func; } -void RNA_def_property_update_runtime(PropertyRNA *prop, void *func) +void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func) { prop->update = func; } @@ -3207,9 +3235,8 @@ void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA * in the first place */ if (prop->identifier) { if (cont->prophash) { - BLI_ghash_remove(cont->prophash, (void *)prop->identifier, NULL, NULL); prop->identifier = BLI_strdup(prop->identifier); - BLI_ghash_insert(cont->prophash, (void *)prop->identifier, prop); + BLI_ghash_reinsert(cont->prophash, (void *)prop->identifier, prop, NULL, NULL); } else { prop->identifier = BLI_strdup(prop->identifier); diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c index c716c3263d1..e13ec1f09a4 100644 --- a/source/blender/makesrna/intern/rna_dynamicpaint.c +++ b/source/blender/makesrna/intern/rna_dynamicpaint.c @@ -39,6 +39,7 @@ #include "DNA_scene_types.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -95,12 +96,12 @@ static char *rna_DynamicPaintSurface_path(PointerRNA *ptr) * Surfaces */ -static void rna_DynamicPaint_redoModifier(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_DynamicPaint_redoModifier(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA); } -static void rna_DynamicPaintSurfaces_updateFrames(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_DynamicPaintSurfaces_updateFrames(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { dynamicPaint_cacheUpdateFrames((DynamicPaintSurface *)ptr->data); } @@ -134,7 +135,7 @@ static void rna_DynamicPaintSurface_changePreview(Main *bmain, Scene *scene, Poi rna_DynamicPaint_redoModifier(bmain, scene, ptr); } -static void rna_DynamicPaintSurface_uniqueName(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_DynamicPaintSurface_uniqueName(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { dynamicPaintSurface_setUniqueName((DynamicPaintSurface *)ptr->data, ((DynamicPaintSurface *)ptr->data)->name); } @@ -196,7 +197,8 @@ static void rna_Surface_active_point_index_set(struct PointerRNA *ptr, int value return; } -static void rna_Surface_active_point_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_Surface_active_point_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { DynamicPaintCanvasSettings *canvas = (DynamicPaintCanvasSettings *)ptr->data; @@ -243,8 +245,8 @@ static int rna_DynamicPaint_is_output_exists(DynamicPaintSurface *surface, Objec } -static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, PointerRNA *ptr, - PropertyRNA *UNUSED(prop), int *free) +static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf( + bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *free) { DynamicPaintSurface *surface = (DynamicPaintSurface *)ptr->data; diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 2ad8ded4656..4b50127d999 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -459,7 +459,8 @@ static void rna_FModifier_active_set(PointerRNA *ptr, int UNUSED(value)) fm->flag |= FMODIFIER_FLAG_ACTIVE; } -static void rna_FModifier_start_frame_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_FModifier_start_frame_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { FModifier *fcm = (FModifier *)ptr->data; @@ -467,7 +468,8 @@ static void rna_FModifier_start_frame_range(PointerRNA *ptr, float *min, float * *max = (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) ? fcm->efra : MAXFRAMEF; } -static void rna_FModifier_end_frame_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_FModifier_end_frame_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { FModifier *fcm = (FModifier *)ptr->data; @@ -475,7 +477,8 @@ static void rna_FModifier_end_frame_range(PointerRNA *ptr, float *min, float *ma *max = MAXFRAMEF; } -static void rna_FModifier_blending_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_FModifier_blending_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { FModifier *fcm = (FModifier *)ptr->data; @@ -524,7 +527,8 @@ static void rna_FModifierGenerator_coefficients_set(PointerRNA *ptr, const float memcpy(gen->coefficients, values, gen->arraysize * sizeof(float)); } -static void rna_FModifierLimits_minx_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_FModifierLimits_minx_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { FModifier *fcm = (FModifier *)ptr->data; FMod_Limits *data = fcm->data; @@ -533,7 +537,8 @@ static void rna_FModifierLimits_minx_range(PointerRNA *ptr, float *min, float *m *max = (data->flag & FCM_LIMIT_XMAX) ? data->rect.xmax : MAXFRAMEF; } -static void rna_FModifierLimits_maxx_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_FModifierLimits_maxx_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { FModifier *fcm = (FModifier *)ptr->data; FMod_Limits *data = fcm->data; @@ -542,7 +547,8 @@ static void rna_FModifierLimits_maxx_range(PointerRNA *ptr, float *min, float *m *max = MAXFRAMEF; } -static void rna_FModifierLimits_miny_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_FModifierLimits_miny_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { FModifier *fcm = (FModifier *)ptr->data; FMod_Limits *data = fcm->data; @@ -551,7 +557,8 @@ static void rna_FModifierLimits_miny_range(PointerRNA *ptr, float *min, float *m *max = (data->flag & FCM_LIMIT_YMAX) ? data->rect.ymax : FLT_MAX; } -static void rna_FModifierLimits_maxy_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_FModifierLimits_maxy_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { FModifier *fcm = (FModifier *)ptr->data; FMod_Limits *data = fcm->data; @@ -562,7 +569,7 @@ static void rna_FModifierLimits_maxy_range(PointerRNA *ptr, float *min, float *m static void rna_FModifierStepped_start_frame_range(PointerRNA *ptr, float *min, float *max, - float *softmin, float *softmax) + float *UNUSED(softmin), float *UNUSED(softmax)) { FModifier *fcm = (FModifier *)ptr->data; FMod_Stepped *data = fcm->data; @@ -572,7 +579,7 @@ static void rna_FModifierStepped_start_frame_range(PointerRNA *ptr, float *min, } static void rna_FModifierStepped_end_frame_range(PointerRNA *ptr, float *min, float *max, - float *softmin, float *softmax) + float *UNUSED(softmin), float *UNUSED(softmax)) { FModifier *fcm = (FModifier *)ptr->data; FMod_Stepped *data = fcm->data; diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 439bc51896f..6423763c49c 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -354,15 +354,15 @@ static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_srna(cprop, "GPencilStrokes"); srna = RNA_def_struct(brna, "GPencilStrokes", NULL); RNA_def_struct_sdna(srna, "bGPDframe"); - RNA_def_struct_ui_text(srna, "Grease Pencil Frames", "Collection of grease pencil frames"); + RNA_def_struct_ui_text(srna, "Grease Pencil Frames", "Collection of grease pencil stroke"); func = RNA_def_function(srna, "new", "rna_GPencil_stroke_new"); - RNA_def_function_ui_description(func, "Add a new grease pencil frame"); + RNA_def_function_ui_description(func, "Add a new grease pencil stroke"); parm = RNA_def_pointer(func, "stroke", "GPencilStroke", "", "The newly created stroke"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove", "rna_GPencil_stroke_remove"); - RNA_def_function_ui_description(func, "Remove a grease pencil frame"); + RNA_def_function_ui_description(func, "Remove a grease pencil stroke"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "stroke", "GPencilStroke", "Stroke", "The stroke to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); @@ -390,7 +390,8 @@ static void rna_def_gpencil_frame(BlenderRNA *brna) /* Frame Number */ prop = RNA_def_property(srna, "frame_number", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "framenum"); - RNA_def_property_range(prop, MINFRAME, MAXFRAME); /* XXX note: this cannot occur on the same frame as another sketch */ + /* XXX note: this cannot occur on the same frame as another sketch */ + RNA_def_property_range(prop, MINAFRAME, MAXFRAME); RNA_def_property_ui_text(prop, "Frame Number", "The frame on which this sketch appears"); /* Flags */ @@ -421,7 +422,8 @@ static void rna_def_gpencil_frames_api(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_GPencil_frame_new"); RNA_def_function_ui_description(func, "Add a new grease pencil frame"); RNA_def_function_flag(func, FUNC_USE_REPORTS); - parm = RNA_def_int(func, "frame_number", 1, MINFRAME, MAXFRAME, "Frame Number", "The frame on which this sketch appears", MINFRAME, MAXFRAME); + parm = RNA_def_int(func, "frame_number", 1, MINAFRAME, MAXFRAME, "Frame Number", + "The frame on which this sketch appears", MINAFRAME, MAXFRAME); RNA_def_property_flag(parm, PROP_REQUIRED); parm = RNA_def_pointer(func, "frame", "GPencilFrame", "", "The newly created frame"); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index c1769f02974..f0322bac756 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -87,7 +87,7 @@ static void rna_Image_save_render(Image *image, bContext *C, ReportList *reports else { ImBuf *write_ibuf; - write_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, TRUE, TRUE, &scene->view_settings, + write_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &scene->view_settings, &scene->display_settings, &scene->r.im_format); write_ibuf->planes = scene->r.im_format.planes; diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 72985f7b6e6..7950ed424ee 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -124,8 +124,9 @@ typedef struct BlenderDefRNA { extern BlenderDefRNA DefRNA; /* Define functions for all types */ - +#ifndef __RNA_ACCESS_H__ extern BlenderRNA BLENDER_RNA; +#endif void RNA_def_ID(struct BlenderRNA *brna); void RNA_def_action(struct BlenderRNA *brna); @@ -278,6 +279,7 @@ void RNA_api_scene_render(struct StructRNA *srna); void RNA_api_sequence_strip(StructRNA *srna); void RNA_api_text(struct StructRNA *srna); 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_sensor(struct StructRNA *srna); void RNA_api_controller(struct StructRNA *srna); @@ -331,8 +333,10 @@ extern CollectionPropertyRNA rna_PropertyGroupItem_idp_array; extern FloatPropertyRNA rna_PropertyGroupItem_double; extern FloatPropertyRNA rna_PropertyGroupItem_double_array; +#ifndef __RNA_ACCESS_H__ extern StructRNA RNA_PropertyGroupItem; extern StructRNA RNA_PropertyGroup; +#endif struct IDProperty *rna_idproperty_check(struct PropertyRNA **prop, struct PointerRNA *ptr); @@ -420,4 +424,10 @@ int rna_IDMaterials_assign_int(struct PointerRNA *ptr, int key, const struct Poi void rna_RenderLayer_rect_set(PointerRNA *ptr, const float *values); void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values); +#ifdef RNA_RUNTIME +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wredundant-decls" +# endif +#endif + #endif /* __RNA_INTERNAL_H__ */ diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index 49d760adb32..a20cb73b3aa 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -39,6 +39,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -98,7 +99,8 @@ static void rna_ShapeKey_value_set(PointerRNA *ptr, float value) data->curval = value; } -static void rna_ShapeKey_value_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_ShapeKey_value_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { KeyBlock *data = (KeyBlock *)ptr->data; @@ -109,7 +111,8 @@ static void rna_ShapeKey_value_range(PointerRNA *ptr, float *min, float *max, fl /* epsilon for how close one end of shapekey range can get to the other */ #define SHAPEKEY_SLIDER_TOL 0.001f -static void rna_ShapeKey_slider_min_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_ShapeKey_slider_min_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { KeyBlock *data = (KeyBlock *)ptr->data; @@ -127,7 +130,8 @@ static void rna_ShapeKey_slider_min_set(PointerRNA *ptr, float value) data->slidermin = value; } -static void rna_ShapeKey_slider_max_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_ShapeKey_slider_max_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { KeyBlock *data = (KeyBlock *)ptr->data; diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c index ffc9ac0e52e..63fc5dbdbbd 100644 --- a/source/blender/makesrna/intern/rna_lamp.c +++ b/source/blender/makesrna/intern/rna_lamp.c @@ -26,6 +26,7 @@ #include <stdlib.h> +#include "BLI_sys_types.h" #include "BLI_math_base.h" #include "BLI_math_rotation.h" @@ -131,7 +132,7 @@ static StructRNA *rna_Lamp_refine(struct PointerRNA *ptr) } } -static void rna_Lamp_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) +static void rna_Lamp_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Lamp *la = ptr->id.data; diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c index 660ef57dbfe..03319a9ccf8 100644 --- a/source/blender/makesrna/intern/rna_linestyle.c +++ b/source/blender/makesrna/intern/rna_linestyle.c @@ -254,7 +254,7 @@ static void rna_LineStyleGeometryModifier_name_set(PointerRNA *ptr, const char * #include "BLI_math.h" static void rna_def_modifier_type_common(StructRNA *srna, EnumPropertyItem *modifier_type_items, - char *set_name_func, int blend, int color) + const char *set_name_func, const bool blend, const bool color) { PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index fd931262904..dffe392e6f1 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -361,8 +361,13 @@ Mesh *rna_Main_meshes_new_from_object( BKE_mesh_from_metaball(&disp, tmpmesh); BKE_displist_free(&disp); } - else - BKE_mesh_from_metaball(&ob->disp, tmpmesh); + else { + ListBase disp = {NULL, NULL}; + if (ob->curve_cache) { + disp = ob->curve_cache->disp; + } + BKE_mesh_from_metaball(&disp, tmpmesh); + } BKE_mesh_texspace_copy_from_object(tmpmesh, ob); @@ -827,7 +832,7 @@ static Mask *rna_Main_mask_new(Main *bmain, const char *name) { Mask *mask; - mask = BKE_mask_new(bmain, "Mask"); + mask = BKE_mask_new(bmain, name); return mask; } diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c index 65e6b15d676..77d593b67b6 100644 --- a/source/blender/makesrna/intern/rna_mask.c +++ b/source/blender/makesrna/intern/rna_mask.c @@ -84,21 +84,33 @@ static void rna_Mask_update_parent(Main *bmain, Scene *scene, PointerRNA *ptr) MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, parent->parent); if (object) { - MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, object, parent->sub_parent); + int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra); - if (track) { - int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra); - MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_framenr); - float marker_pos_ofs[2], parmask_pos[2]; - MovieClipUser user = {0}; + if (parent->type == MASK_PARENT_POINT_TRACK) { + MovieTrackingTrack *track = BKE_tracking_track_get_named(tracking, object, parent->sub_parent); - BKE_movieclip_user_set_frame(&user, scene->r.cfra); + if (track) { + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_framenr); + float marker_pos_ofs[2], parmask_pos[2]; + MovieClipUser user = {0}; - add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset); + BKE_movieclip_user_set_frame(&user, scene->r.cfra); - BKE_mask_coord_from_movieclip(clip, &user, parmask_pos, marker_pos_ofs); + add_v2_v2v2(marker_pos_ofs, marker->pos, track->offset); - copy_v2_v2(parent->parent_orig, parmask_pos); + BKE_mask_coord_from_movieclip(clip, &user, parmask_pos, marker_pos_ofs); + + copy_v2_v2(parent->parent_orig, parmask_pos); + } + } + else /* if (parent->type == MASK_PARENT_PLANE_TRACK) */ { + MovieTrackingPlaneTrack *plane_track = BKE_tracking_plane_track_get_named(tracking, object, parent->sub_parent); + if (plane_track) { + MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, clip_framenr); + + memcpy(parent->parent_corners_orig, plane_marker->corners, sizeof(parent->parent_corners_orig)); + zero_v2(parent->parent_orig); + } } } } @@ -504,7 +516,7 @@ static void rna_MaskSpline_point_remove(ID *id, MaskSpline *spline, ReportList * } #else - void rna_def_maskParent(BlenderRNA *brna) +static void rna_def_maskParent(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; @@ -513,6 +525,11 @@ static void rna_MaskSpline_point_remove(ID *id, MaskSpline *spline, ReportList * {ID_MC, "MOVIECLIP", ICON_SEQUENCE, "Movie Clip", ""}, {0, NULL, 0, NULL, NULL}}; + static EnumPropertyItem parent_type_items[] = { + {MASK_PARENT_POINT_TRACK, "POINT_TRACK", 0, "Point Track", ""}, + {MASK_PARENT_PLANE_TRACK, "PLANE_TRACK", 0, "Plane Track", ""}, + {0, NULL, 0, NULL, NULL}}; + srna = RNA_def_struct(brna, "MaskParent", NULL); RNA_def_struct_ui_text(srna, "Mask Parent", "Parenting settings for masking element"); @@ -535,6 +552,12 @@ static void rna_MaskSpline_point_remove(ID *id, MaskSpline *spline, ReportList * RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used"); RNA_def_property_update(prop, 0, "rna_Mask_update_parent"); + /* type */ + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, parent_type_items); + RNA_def_property_ui_text(prop, "Parent Type", "Parent Type"); + RNA_def_property_update(prop, 0, "rna_Mask_update_parent"); + /* parent */ prop = RNA_def_property(srna, "parent", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Parent", "Name of parent object in specified data block to which parenting happens"); @@ -804,7 +827,7 @@ static void rna_def_mask_layer(BlenderRNA *brna) /* splines */ prop = RNA_def_property(srna, "splines", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_funcs(prop, "rna_MaskLayer_splines_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", 0, 0, 0, 0); + RNA_def_property_collection_funcs(prop, "rna_MaskLayer_splines_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", NULL, NULL, NULL, NULL); RNA_def_property_struct_type(prop, "MaskSpline"); RNA_def_property_ui_text(prop, "Splines", "Collection of splines which defines this layer"); RNA_def_property_srna(prop, "MaskSplines"); @@ -914,7 +937,7 @@ static void rna_def_mask(BlenderRNA *brna) /* mask layers */ prop = RNA_def_property(srna, "layers", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_funcs(prop, "rna_Mask_layers_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", 0, 0, 0, 0); + RNA_def_property_collection_funcs(prop, "rna_Mask_layers_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", NULL, NULL, NULL, NULL); RNA_def_property_struct_type(prop, "MaskLayer"); RNA_def_property_ui_text(prop, "Layers", "Collection of layers which defines this mask"); rna_def_masklayers(brna, prop); diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index b30bdaf9009..e9f506b6f0b 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -31,6 +31,7 @@ #include "DNA_texture_types.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -92,7 +93,7 @@ EnumPropertyItem ramp_blend_items[] = { #include "ED_node.h" -static void rna_Material_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) +static void rna_Material_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Material *ma = ptr->id.data; @@ -100,7 +101,7 @@ static void rna_Material_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *p WM_main_add_notifier(NC_MATERIAL | ND_SHADING, ma); } -static void rna_Material_update_previews(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_Material_update_previews(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Material *ma = ptr->id.data; @@ -110,7 +111,7 @@ static void rna_Material_update_previews(Main *bmain, Scene *scene, PointerRNA * WM_main_add_notifier(NC_MATERIAL | ND_SHADING_PREVIEW, ma); } -static void rna_Material_draw_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) +static void rna_Material_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Material *ma = ptr->id.data; @@ -201,7 +202,8 @@ static void rna_Material_active_node_material_set(PointerRNA *ptr, PointerRNA va nodeSetActiveID(ma->nodetree, ID_MA, &ma_act->id); } -static void rna_MaterialStrand_start_size_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_MaterialStrand_start_size_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { Material *ma = (Material *)ptr->id.data; @@ -215,7 +217,8 @@ static void rna_MaterialStrand_start_size_range(PointerRNA *ptr, float *min, flo } } -static void rna_MaterialStrand_end_size_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_MaterialStrand_end_size_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { Material *ma = (Material *)ptr->id.data; diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 35d8a0fb433..fe6f33abc8c 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -184,18 +184,22 @@ static void rna_MeshEdgeLayer_name_set(PointerRNA *ptr, const char *value) rna_cd_layer_name_set(rna_mesh_edata(ptr), (CustomDataLayer *)ptr->data, value); } #endif +#if 0 static void rna_MeshPolyLayer_name_set(PointerRNA *ptr, const char *value) { rna_cd_layer_name_set(rna_mesh_pdata(ptr), (CustomDataLayer *)ptr->data, value); } +#endif static void rna_MeshLoopLayer_name_set(PointerRNA *ptr, const char *value) { rna_cd_layer_name_set(rna_mesh_ldata(ptr), (CustomDataLayer *)ptr->data, value); } +#if 0 static void rna_MeshTessfaceLayer_name_set(PointerRNA *ptr, const char *value) { rna_cd_layer_name_set(rna_mesh_fdata(ptr), (CustomDataLayer *)ptr->data, value); } +#endif /* only for layers shared between types */ static void rna_MeshAnyLayer_name_set(PointerRNA *ptr, const char *value) { @@ -207,7 +211,7 @@ static void rna_MeshAnyLayer_name_set(PointerRNA *ptr, const char *value) /* -------------------------------------------------------------------- */ /* Update Callbacks */ -static void rna_Mesh_update_data(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_Mesh_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { ID *id = ptr->id.data; @@ -227,7 +231,7 @@ static void rna_Mesh_update_data_edit_color(Main *bmain, Scene *scene, PointerRN } } -static void rna_Mesh_update_select(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_Mesh_update_select(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { ID *id = ptr->id.data; /* cheating way for importers to avoid slow updates */ @@ -236,7 +240,7 @@ static void rna_Mesh_update_select(Main *bmain, Scene *scene, PointerRNA *ptr) } } -void rna_Mesh_update_draw(Main *bmain, Scene *scene, PointerRNA *ptr) +void rna_Mesh_update_draw(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { ID *id = ptr->id.data; /* cheating way for importers to avoid slow updates */ @@ -320,6 +324,20 @@ static void rna_MEdge_crease_set(PointerRNA *ptr, float value) medge->crease = (char)(CLAMPIS(value * 255.0f, 0, 255)); } +static void rna_MeshLoop_normal_get(PointerRNA *ptr, float *values) +{ + Mesh *me = rna_mesh(ptr); + MLoop *ml = (MLoop *)ptr->data; + const float (*vec)[3] = CustomData_get(&me->ldata, (int)(ml - me->mloop), CD_NORMAL); + + if (!vec) { + zero_v3(values); + } + else { + copy_v3_v3(values, (const float *)vec); + } +} + static void rna_MeshPolygon_normal_get(PointerRNA *ptr, float *values) { Mesh *me = rna_mesh(ptr); @@ -575,8 +593,9 @@ static void rna_Mesh_texspace_size_get(PointerRNA *ptr, float values[3]) { Mesh *me = (Mesh *)ptr->data; - if (!me->bb) + if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { BKE_mesh_texspace_calc(me); + } copy_v3_v3(values, me->size); } @@ -585,8 +604,9 @@ static void rna_Mesh_texspace_loc_get(PointerRNA *ptr, float values[3]) { Mesh *me = (Mesh *)ptr->data; - if (!me->bb) + if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) { BKE_mesh_texspace_calc(me); + } copy_v3_v3(values, me->loc); } @@ -630,7 +650,7 @@ static int rna_CustomDataLayer_active_get(PointerRNA *ptr, CustomData *data, int else return (n == CustomData_get_active_layer_index(data, type)); } -static int rna_CustomDataLayer_clone_get(PointerRNA *ptr, CustomData *data, int type, int render) +static int rna_CustomDataLayer_clone_get(PointerRNA *ptr, CustomData *data, int type) { int n = ((CustomDataLayer *)ptr->data) - data->layers; @@ -658,7 +678,7 @@ static void rna_CustomDataLayer_active_set(PointerRNA *ptr, CustomData *data, in BKE_mesh_update_customdata_pointers(me, true); } -static void rna_CustomDataLayer_clone_set(PointerRNA *ptr, CustomData *data, int value, int type, int render) +static void rna_CustomDataLayer_clone_set(PointerRNA *ptr, CustomData *data, int value, int type) { int n = ((CustomDataLayer *)ptr->data) - data->layers; @@ -668,6 +688,14 @@ static void rna_CustomDataLayer_clone_set(PointerRNA *ptr, CustomData *data, int CustomData_set_layer_clone_index(data, type, n); } +/* Generic UV rename! */ +static void rna_MeshUVLayer_name_set(PointerRNA *ptr, const char *name) +{ + char buf[MAX_CUSTOMDATA_LAYER_NAME]; + BLI_strncpy_utf8(buf, name, MAX_CUSTOMDATA_LAYER_NAME); + BKE_mesh_uv_cdlayer_rename(rna_mesh(ptr), ((CustomDataLayer *)ptr->data)->name, buf, true); +} + /* uv_layers */ DEFINE_CUSTOMDATA_LAYER_COLLECTION(uv_layer, ldata, CD_MLOOPUV) @@ -732,7 +760,7 @@ static int rna_MeshTextureFaceLayer_active_get(PointerRNA *ptr) static int rna_MeshTextureFaceLayer_clone_get(PointerRNA *ptr) { - return rna_CustomDataLayer_clone_get(ptr, rna_mesh_fdata(ptr), CD_MTFACE, 0); + return rna_CustomDataLayer_clone_get(ptr, rna_mesh_fdata(ptr), CD_MTFACE); } static void rna_MeshTextureFaceLayer_active_render_set(PointerRNA *ptr, int value) @@ -747,7 +775,7 @@ static void rna_MeshTextureFaceLayer_active_set(PointerRNA *ptr, int value) static void rna_MeshTextureFaceLayer_clone_set(PointerRNA *ptr, int value) { - rna_CustomDataLayer_clone_set(ptr, rna_mesh_fdata(ptr), value, CD_MTFACE, 0); + rna_CustomDataLayer_clone_set(ptr, rna_mesh_fdata(ptr), value, CD_MTFACE); } /* poly uv_textures */ @@ -783,7 +811,7 @@ static int rna_MeshTexturePolyLayer_active_get(PointerRNA *ptr) static int rna_MeshTexturePolyLayer_clone_get(PointerRNA *ptr) { - return rna_CustomDataLayer_clone_get(ptr, rna_mesh_pdata(ptr), CD_MTEXPOLY, 0); + return rna_CustomDataLayer_clone_get(ptr, rna_mesh_pdata(ptr), CD_MTEXPOLY); } static void rna_MeshTexturePolyLayer_active_render_set(PointerRNA *ptr, int value) @@ -798,7 +826,7 @@ static void rna_MeshTexturePolyLayer_active_set(PointerRNA *ptr, int value) static void rna_MeshTexturePolyLayer_clone_set(PointerRNA *ptr, int value) { - rna_CustomDataLayer_clone_set(ptr, rna_mesh_pdata(ptr), value, CD_MTEXPOLY, 0); + rna_CustomDataLayer_clone_set(ptr, rna_mesh_pdata(ptr), value, CD_MTEXPOLY); } /* vertex_color_layers */ @@ -890,7 +918,7 @@ static int rna_MeshFloatPropertyLayer_data_length(PointerRNA *ptr) return me->totpoly; } -static int rna_float_layer_check(CollectionPropertyIterator *iter, void *data) +static int rna_float_layer_check(CollectionPropertyIterator *UNUSED(iter), void *data) { CustomDataLayer *layer = (CustomDataLayer *)data; return (layer->type != CD_PROP_FLT); @@ -908,7 +936,7 @@ static int rna_Mesh_polygon_float_layers_length(PointerRNA *ptr) return CustomData_number_of_layers(rna_mesh_pdata(ptr), CD_PROP_FLT); } -static int rna_int_layer_check(CollectionPropertyIterator *iter, void *data) +static int rna_int_layer_check(CollectionPropertyIterator *UNUSED(iter), void *data) { CustomDataLayer *layer = (CustomDataLayer *)data; return (layer->type != CD_PROP_INT); @@ -939,7 +967,7 @@ static int rna_Mesh_polygon_int_layers_length(PointerRNA *ptr) return CustomData_number_of_layers(rna_mesh_pdata(ptr), CD_PROP_INT); } -static int rna_string_layer_check(CollectionPropertyIterator *iter, void *data) +static int rna_string_layer_check(CollectionPropertyIterator *UNUSED(iter), void *data) { CustomDataLayer *layer = (CustomDataLayer *)data; return (layer->type != CD_PROP_STR); @@ -981,7 +1009,7 @@ static char *rna_MeshSkinVertexLayer_path(PointerRNA *ptr) return BLI_sprintfN("skin_vertices[\"%s\"]", name_esc); } -static char *rna_VertCustomData_data_path(PointerRNA *ptr, char *collection, int type); +static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collection, int type); static char *rna_MeshSkinVertex_path(PointerRNA *ptr) { return rna_VertCustomData_data_path(ptr, "skin_vertices", CD_MVERT_SKIN); @@ -1106,12 +1134,15 @@ static void rna_MeshPoly_vertices_set(PointerRNA *ptr, const int *values) } } +/* disabling, some importers don't know the total material count when assigning materials */ +#if 0 static void rna_MeshPoly_material_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) { Mesh *me = rna_mesh(ptr); *min = 0; *max = max_ii(0, me->totcol - 1); } +#endif static int rna_MeshVertex_index_get(PointerRNA *ptr) { @@ -1207,7 +1238,7 @@ static char *rna_MeshTexturePolyLayer_path(PointerRNA *ptr) return BLI_sprintfN("uv_textures[\"%s\"]", name_esc); } -static char *rna_VertCustomData_data_path(PointerRNA *ptr, char *collection, int type) +static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collection, int type) { CustomDataLayer *cdl; Mesh *me = rna_mesh(ptr); @@ -1228,7 +1259,7 @@ static char *rna_VertCustomData_data_path(PointerRNA *ptr, char *collection, int return NULL; } -static char *rna_PolyCustomData_data_path(PointerRNA *ptr, char *collection, int type) +static char *rna_PolyCustomData_data_path(PointerRNA *ptr, const char *collection, int type) { CustomDataLayer *cdl; Mesh *me = rna_mesh(ptr); @@ -1249,7 +1280,7 @@ static char *rna_PolyCustomData_data_path(PointerRNA *ptr, char *collection, int return NULL; } -static char *rna_LoopCustomData_data_path(PointerRNA *ptr, char *collection, int type) +static char *rna_LoopCustomData_data_path(PointerRNA *ptr, const char *collection, int type) { CustomDataLayer *cdl; Mesh *me = rna_mesh(ptr); @@ -1270,7 +1301,7 @@ static char *rna_LoopCustomData_data_path(PointerRNA *ptr, char *collection, int return NULL; } -static char *rna_FaceCustomData_data_path(PointerRNA *ptr, char *collection, int type) +static char *rna_FaceCustomData_data_path(PointerRNA *ptr, const char *collection, int type) { CustomDataLayer *cdl; Mesh *me = rna_mesh(ptr); @@ -1456,7 +1487,7 @@ static PointerRNA rna_Mesh_tessface_vertex_color_new(struct Mesh *me, ReportList return ptr; } -static PointerRNA rna_Mesh_polygon_int_property_new(struct Mesh *me, struct bContext *C, const char *name) +static PointerRNA rna_Mesh_polygon_int_property_new(struct Mesh *me, const char *name) { PointerRNA ptr; CustomDataLayer *cdl = NULL; @@ -1471,7 +1502,7 @@ static PointerRNA rna_Mesh_polygon_int_property_new(struct Mesh *me, struct bCon return ptr; } -static PointerRNA rna_Mesh_polygon_float_property_new(struct Mesh *me, struct bContext *C, const char *name) +static PointerRNA rna_Mesh_polygon_float_property_new(struct Mesh *me, const char *name) { PointerRNA ptr; CustomDataLayer *cdl = NULL; @@ -1486,7 +1517,7 @@ static PointerRNA rna_Mesh_polygon_float_property_new(struct Mesh *me, struct bC return ptr; } -static PointerRNA rna_Mesh_polygon_string_property_new(struct Mesh *me, struct bContext *C, const char *name) +static PointerRNA rna_Mesh_polygon_string_property_new(struct Mesh *me, const char *name) { PointerRNA ptr; CustomDataLayer *cdl = NULL; @@ -1675,7 +1706,7 @@ static void rna_def_mvert(BlenderRNA *brna) prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_int_funcs(prop, "rna_MeshVertex_index_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Index", "Index number of the vertex"); + RNA_def_property_ui_text(prop, "Index", "Index of this vertex"); prop = RNA_def_property(srna, "undeformed_co", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_array(prop, 3); @@ -1740,7 +1771,7 @@ static void rna_def_medge(BlenderRNA *brna) prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_int_funcs(prop, "rna_MeshEdge_index_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Index", "Index number of the vertex"); + RNA_def_property_ui_text(prop, "Index", "Index of this edge"); } static void rna_def_mface(BlenderRNA *brna) @@ -1771,7 +1802,9 @@ static void rna_def_mface(BlenderRNA *brna) prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "mat_nr"); RNA_def_property_ui_text(prop, "Material Index", ""); +#if 0 RNA_def_property_int_funcs(prop, NULL, NULL, "rna_MeshPoly_material_index_range"); /* reuse for tessface is ok */ +#endif RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); @@ -1794,17 +1827,17 @@ static void rna_def_mface(BlenderRNA *brna) RNA_def_property_range(prop, -1.0f, 1.0f); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_float_funcs(prop, "rna_MeshTessFace_normal_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Face normal", "Local space unit length normal vector for this face"); + RNA_def_property_ui_text(prop, "Face Normal", "Local space unit length normal vector for this face"); prop = RNA_def_property(srna, "area", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_float_funcs(prop, "rna_MeshTessFace_area_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Face area", "Read only area of the face"); + RNA_def_property_ui_text(prop, "Face Area", "Read only area of this face"); prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_int_funcs(prop, "rna_MeshTessFace_index_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Index", "Index number of the vertex"); + RNA_def_property_ui_text(prop, "Index", "Index of this face"); } @@ -1830,7 +1863,17 @@ static void rna_def_mloop(BlenderRNA *brna) prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_int_funcs(prop, "rna_MeshLoop_index_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Index", "Index number of the loop"); + RNA_def_property_ui_text(prop, "Index", "Index of this loop"); + + prop = RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION); + RNA_def_property_array(prop, 3); + RNA_def_property_range(prop, -1.0f, 1.0f); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_float_funcs(prop, "rna_MeshLoop_normal_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Loop Normal", + "Local space unit length split normal vector of this vertex for this polygon " + "(only computed on demand!)"); + } static void rna_def_mpolygon(BlenderRNA *brna) @@ -1859,16 +1902,18 @@ static void rna_def_mpolygon(BlenderRNA *brna) /* these are both very low level access */ prop = RNA_def_property(srna, "loop_start", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "loopstart"); - RNA_def_property_ui_text(prop, "Loop Start", ""); + RNA_def_property_ui_text(prop, "Loop Start", "Index of the first loop of this polygon"); /* also low level */ prop = RNA_def_property(srna, "loop_total", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "totloop"); - RNA_def_property_ui_text(prop, "Loop Total", ""); + RNA_def_property_ui_text(prop, "Loop Total", "Number of loops used by this polygon"); prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "mat_nr"); RNA_def_property_ui_text(prop, "Material Index", ""); +#if 0 RNA_def_property_int_funcs(prop, NULL, NULL, "rna_MeshPoly_material_index_range"); +#endif RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); @@ -1891,23 +1936,23 @@ static void rna_def_mpolygon(BlenderRNA *brna) RNA_def_property_range(prop, -1.0f, 1.0f); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_float_funcs(prop, "rna_MeshPolygon_normal_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Face normal", "Local space unit length normal vector for this polygon"); + RNA_def_property_ui_text(prop, "Polygon Normal", "Local space unit length normal vector for this polygon"); prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE); RNA_def_property_array(prop, 3); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_float_funcs(prop, "rna_MeshPolygon_center_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Face center", "Center of the polygon"); + RNA_def_property_ui_text(prop, "Polygon Center", "Center of this polygon"); prop = RNA_def_property(srna, "area", PROP_FLOAT, PROP_UNSIGNED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_float_funcs(prop, "rna_MeshPolygon_area_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Face area", "Read only area of the face"); + RNA_def_property_ui_text(prop, "Polygon Area", "Read only area of this polygon"); prop = RNA_def_property(srna, "index", PROP_INT, PROP_UNSIGNED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_int_funcs(prop, "rna_MeshPolygon_index_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Index", "Index number of the vertex"); + RNA_def_property_ui_text(prop, "Index", "Index of this polygon"); } /* mesh.loop_uvs */ @@ -1928,7 +1973,7 @@ static void rna_def_mloopuv(BlenderRNA *brna) prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_struct_name_property(srna, prop); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshLoopLayer_name_set"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshUVLayer_name_set"); RNA_def_property_ui_text(prop, "Name", "Name of UV map"); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); @@ -1966,7 +2011,7 @@ static void rna_def_mtface(BlenderRNA *brna) prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_struct_name_property(srna, prop); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshTessfaceLayer_name_set"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshUVLayer_name_set"); RNA_def_property_ui_text(prop, "Name", "Name of UV map"); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); @@ -2058,7 +2103,7 @@ static void rna_def_mtface(BlenderRNA *brna) prop = RNA_def_property(srna, "uv_raw", PROP_FLOAT, PROP_NONE); RNA_def_property_multi_array(prop, 2, uv_dim); RNA_def_property_float_sdna(prop, NULL, "uv"); - RNA_def_property_ui_text(prop, "UV", "Fixed size UV coordinates array"); + RNA_def_property_ui_text(prop, "UV Raw", "Fixed size UV coordinates array"); } @@ -2078,7 +2123,7 @@ static void rna_def_mtexpoly(BlenderRNA *brna) prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_struct_name_property(srna, prop); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshPolyLayer_name_set"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshUVLayer_name_set"); RNA_def_property_ui_text(prop, "Name", "Name of UV map"); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); @@ -2397,7 +2442,7 @@ void rna_def_texmat_common(StructRNA *srna, const char *texspace_editable) RNA_def_property_struct_type(prop, "Material"); RNA_def_property_ui_text(prop, "Materials", ""); RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */ - RNA_def_property_collection_funcs(prop, 0, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int"); + RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int"); } @@ -2644,7 +2689,6 @@ static void rna_def_polygon_int_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_struct_ui_text(srna, "Int Properties", "Collection of int properties"); func = RNA_def_function(srna, "new", "rna_Mesh_polygon_int_property_new"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); RNA_def_function_ui_description(func, "Add a integer property layer to Mesh"); RNA_def_string(func, "name", "Int Prop", 0, "", "Int property name"); parm = RNA_def_pointer(func, "layer", "MeshIntPropertyLayer", "", "The newly created layer"); @@ -2666,7 +2710,6 @@ static void rna_def_polygon_float_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_struct_ui_text(srna, "Float Properties", "Collection of float properties"); func = RNA_def_function(srna, "new", "rna_Mesh_polygon_float_property_new"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); RNA_def_function_ui_description(func, "Add a float property layer to Mesh"); RNA_def_string(func, "name", "Float Prop", 0, "", "Float property name"); parm = RNA_def_pointer(func, "layer", "MeshFloatPropertyLayer", "", "The newly created layer"); @@ -2688,7 +2731,6 @@ static void rna_def_polygon_string_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_struct_ui_text(srna, "String Properties", "Collection of string properties"); func = RNA_def_function(srna, "new", "rna_Mesh_polygon_string_property_new"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); RNA_def_function_ui_description(func, "Add a string property layer to Mesh"); RNA_def_string(func, "name", "String Prop", 0, "", "String property name"); parm = RNA_def_pointer(func, "layer", "MeshStringPropertyLayer", "", "The newly created layer"); @@ -2848,7 +2890,7 @@ static void rna_def_mesh(BlenderRNA *brna) prop = RNA_def_property(srna, "tessfaces", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "mface", "totface"); RNA_def_property_struct_type(prop, "MeshTessFace"); - RNA_def_property_ui_text(prop, "TessFaces", "Tessellation faces of the mesh (derived from polygons)"); + RNA_def_property_ui_text(prop, "TessFaces", "Tessellated faces of the mesh (derived from polygons)"); rna_def_mesh_tessfaces(brna, prop); prop = RNA_def_property(srna, "loops", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index ad9977fef50..a25f56f2259 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -37,6 +37,7 @@ #include "BLI_sys_types.h" #include "BLI_utildefines.h" +#include "BLI_math.h" #include "BKE_mesh.h" #include "ED_mesh.h" @@ -47,7 +48,7 @@ #include "DNA_mesh_types.h" -static const char *rna_Mesh_unit_test_compare(struct Mesh *mesh, bContext *C, struct Mesh *mesh2) +static const char *rna_Mesh_unit_test_compare(struct Mesh *mesh, struct Mesh *mesh2) { const char *ret = BKE_mesh_cmp(mesh, mesh2, FLT_EPSILON * 60); @@ -57,14 +58,56 @@ static const char *rna_Mesh_unit_test_compare(struct Mesh *mesh, bContext *C, st return ret; } -void rna_Mesh_calc_smooth_groups(struct Mesh *mesh, int *r_poly_group_len, int **r_poly_group, int *r_group_total) +static void rna_Mesh_calc_normals_split(Mesh *mesh, float min_angle) +{ + float (*r_loopnors)[3]; + float (*polynors)[3]; + bool free_polynors = false; + + if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { + r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); + memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop); + } + else { + r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop); + CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); + } + + if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { + /* This assume that layer is always up to date, not sure this is the case (esp. in Edit mode?)... */ + polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL); + free_polynors = false; + } + else { + polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__); + BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, + polynors, false); + free_polynors = true; + } + + BKE_mesh_normals_loop_split(mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge, + mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, polynors, mesh->totpoly, + min_angle); + + if (free_polynors) { + MEM_freeN(polynors); + } +} + +static void rna_Mesh_free_normals_split(Mesh *mesh) +{ + CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop); +} + +static void rna_Mesh_calc_smooth_groups(Mesh *mesh, int use_bitflags, int *r_poly_group_len, + int **r_poly_group, int *r_group_total) { *r_poly_group_len = mesh->totpoly; *r_poly_group = BKE_mesh_calc_smoothgroups( mesh->medge, mesh->totedge, mesh->mpoly, mesh->totpoly, mesh->mloop, mesh->totloop, - r_group_total); + r_group_total, use_bitflags); } #else @@ -82,11 +125,22 @@ void RNA_api_mesh(StructRNA *srna) func = RNA_def_function(srna, "calc_normals", "BKE_mesh_calc_normals"); RNA_def_function_ui_description(func, "Calculate vertex normals"); + func = RNA_def_function(srna, "calc_normals_split", "rna_Mesh_calc_normals_split"); + RNA_def_function_ui_description(func, "Calculate split vertex normals, which preserve sharp edges"); + parm = RNA_def_float(func, "split_angle", M_PI, 0.0f, M_PI, "", + "Angle between polys' normals above which an edge is always sharp (180° to disable)", + 0.0f, M_PI); + RNA_def_property_subtype(parm, (PropertySubType)PROP_UNIT_ROTATION); + + func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split"); + RNA_def_function_ui_description(func, "Free split vertex normals"); + func = RNA_def_function(srna, "calc_tessface", "ED_mesh_calc_tessface"); RNA_def_function_ui_description(func, "Calculate face tessellation (supports editmode too)"); func = RNA_def_function(srna, "calc_smooth_groups", "rna_Mesh_calc_smooth_groups"); RNA_def_function_ui_description(func, "Calculate smooth groups from sharp edges"); + RNA_def_boolean(func, "use_bitflags", false, "", "Produce bitflags groups instead of simple numeric values"); /* return values */ parm = RNA_def_int_array(func, "poly_groups", 1, NULL, 0, 0, "", "Smooth Groups", 0, 0); RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT); @@ -101,7 +155,6 @@ void RNA_api_mesh(StructRNA *srna) func = RNA_def_function(srna, "unit_test_compare", "rna_Mesh_unit_test_compare"); RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to compare to"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); /* return value */ parm = RNA_def_string(func, "result", "nothing", 64, "Return value", "String description of result of comparison"); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_mesh_utils.h b/source/blender/makesrna/intern/rna_mesh_utils.h index dfe36da033b..c0ea1a153ff 100644 --- a/source/blender/makesrna/intern/rna_mesh_utils.h +++ b/source/blender/makesrna/intern/rna_mesh_utils.h @@ -32,7 +32,8 @@ /* Define the accessors for a basic CustomDataLayer collection */ #define DEFINE_CUSTOMDATA_LAYER_COLLECTION(collection_name, customdata_type, layer_type) \ /* check */ \ - static int rna_##collection_name##_check(CollectionPropertyIterator *iter, void *data) \ + static int rna_##collection_name##_check( \ + CollectionPropertyIterator *UNUSED(iter), void *data) \ { \ CustomDataLayer *layer = (CustomDataLayer *)data; \ return (layer->type != layer_type); \ @@ -59,8 +60,9 @@ return data ? CustomData_number_of_layers(data, layer_type) : 0; \ } \ /* index range */ \ - static void rna_Mesh_##collection_name##_index_range(PointerRNA *ptr, int *min, int *max, \ - int *softmin, int *softmax) \ + static void rna_Mesh_##collection_name##_index_range( \ + PointerRNA *ptr, int *min, int *max, \ + int *UNUSED(softmin), int *UNUSED(softmax)) \ { \ CustomData *data = rna_mesh_##customdata_type(ptr); \ *min = 0; \ diff --git a/source/blender/makesrna/intern/rna_meta.c b/source/blender/makesrna/intern/rna_meta.c index 11f0e48012b..6bf7c8926e8 100644 --- a/source/blender/makesrna/intern/rna_meta.c +++ b/source/blender/makesrna/intern/rna_meta.c @@ -320,13 +320,15 @@ static void rna_def_metaball(BlenderRNA *brna) /* number values */ prop = RNA_def_property(srna, "resolution", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "wiresize"); - RNA_def_property_range(prop, 0.050f, 1.0f); + RNA_def_property_range(prop, 0.005f, 10000.0f); + RNA_def_property_ui_range(prop, 0.05f, 1000.0f, 2.5f, 3); RNA_def_property_ui_text(prop, "Wire Size", "Polygonization resolution in the 3D viewport"); RNA_def_property_update(prop, 0, "rna_MetaBall_update_data"); prop = RNA_def_property(srna, "render_resolution", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "rendersize"); - RNA_def_property_range(prop, 0.050f, 1.0f); + RNA_def_property_range(prop, 0.005f, 10000.0f); + RNA_def_property_ui_range(prop, 0.025f, 1000.0f, 2.5f, 3); RNA_def_property_ui_text(prop, "Render Size", "Polygonization resolution in rendering"); RNA_def_property_update(prop, 0, "rna_MetaBall_update_data"); @@ -371,7 +373,7 @@ static void rna_def_metaball(BlenderRNA *brna) RNA_def_property_struct_type(prop, "Material"); RNA_def_property_ui_text(prop, "Materials", ""); RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */ - RNA_def_property_collection_funcs(prop, 0, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int"); + RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int"); prop = RNA_def_property(srna, "is_editmode", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_Meta_is_editmode_get", NULL); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index ebaec5c7c09..744d41b198e 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -495,7 +495,8 @@ static void rna_MultiresModifier_type_set(PointerRNA *ptr, int value) mmd->simple = value; } -static void rna_MultiresModifier_level_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_MultiresModifier_level_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { MultiresModifierData *mmd = (MultiresModifierData *)ptr->data; @@ -670,8 +671,8 @@ static void rna_UVProjectModifier_num_projectors_set(PointerRNA *ptr, int value) UVProjectModifierData *md = (UVProjectModifierData *)ptr->data; int a; - md->num_projectors = CLAMPIS(value, 1, MOD_UVPROJECT_MAX); - for (a = md->num_projectors; a < MOD_UVPROJECT_MAX; a++) + md->num_projectors = CLAMPIS(value, 1, MOD_UVPROJECT_MAXPROJECTORS); + for (a = md->num_projectors; a < MOD_UVPROJECT_MAXPROJECTORS; a++) md->projectors[a] = NULL; } @@ -1729,7 +1730,7 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "num_projectors"); RNA_def_property_ui_text(prop, "Number of Projectors", "Number of projectors to use"); RNA_def_property_int_funcs(prop, NULL, "rna_UVProjectModifier_num_projectors_set", NULL); - RNA_def_property_range(prop, 1, MOD_UVPROJECT_MAX); + RNA_def_property_range(prop, 1, MOD_UVPROJECT_MAXPROJECTORS); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "projectors", PROP_COLLECTION, PROP_NONE); @@ -2790,7 +2791,7 @@ static void rna_def_modifier_screw(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_ui_range(prop, 0, -M_PI * 2, M_PI * 2, 2); + RNA_def_property_ui_range(prop, -M_PI * 2, M_PI * 2, 2, -1); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_ui_text(prop, "Angle", "Angle of revolution"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c index 399131bbd61..d905e6a014a 100644 --- a/source/blender/makesrna/intern/rna_nla.c +++ b/source/blender/makesrna/intern/rna_nla.c @@ -36,6 +36,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -97,7 +98,7 @@ static char *rna_NlaStrip_path(PointerRNA *ptr) } /* no path */ - return ""; + return BLI_strdup(""); } static void rna_NlaStrip_transform_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) @@ -415,7 +416,9 @@ EnumPropertyItem nla_mode_blend_items[] = { "Weighted result of strip is removed from the accumulated results"}, {NLASTRIP_MODE_MULTIPLY, "MULITPLY", 0, "Multiply", "Weighted result of strip is multiplied with the accumulated results"}, - {0, NULL, 0, NULL, NULL}}; + {0, NULL, 0, NULL, NULL} +}; + EnumPropertyItem nla_mode_extend_items[] = { {NLASTRIP_EXTEND_NOTHING, "NOTHING", 0, "Nothing", "Strip has no influence past its extents"}, {NLASTRIP_EXTEND_HOLD, "HOLD", 0, "Hold", diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 535c279c02f..8ad19735517 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -70,7 +70,8 @@ EnumPropertyItem node_socket_in_out_items[] = { { 0, NULL, 0, NULL, NULL } }; -EnumPropertyItem node_socket_type_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem node_socket_type_items[] = { {SOCK_CUSTOM, "CUSTOM", 0, "Custom", ""}, {SOCK_FLOAT, "VALUE", 0, "Value", ""}, {SOCK_INT, "INT", 0, "Int", ""}, @@ -82,14 +83,14 @@ EnumPropertyItem node_socket_type_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem node_quality_items[] = { +static EnumPropertyItem node_quality_items[] = { {NTREE_QUALITY_HIGH, "HIGH", 0, "High", "High quality"}, {NTREE_QUALITY_MEDIUM, "MEDIUM", 0, "Medium", "Medium quality"}, {NTREE_QUALITY_LOW, "LOW", 0, "Low", "Low quality"}, {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem node_chunksize_items[] = { +static EnumPropertyItem node_chunksize_items[] = { {NTREE_CHUNCKSIZE_32, "32", 0, "32x32", "Chunksize of 32x32"}, {NTREE_CHUNCKSIZE_64, "64", 0, "64x64", "Chunksize of 64x64"}, {NTREE_CHUNCKSIZE_128, "128", 0, "128x128", "Chunksize of 128x128"}, @@ -98,6 +99,7 @@ EnumPropertyItem node_chunksize_items[] = { {NTREE_CHUNCKSIZE_1024, "1024", 0, "1024x1024", "Chunksize of 1024x1024"}, {0, NULL, 0, NULL, NULL} }; +#endif #define DEF_ICON_BLANK_SKIP #define DEF_ICON(name) {ICON_##name, (#name), 0, (#name), ""}, @@ -152,39 +154,13 @@ EnumPropertyItem node_filter_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem node_sampler_type_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem node_sampler_type_items[] = { {0, "NEAREST", 0, "Nearest", ""}, {1, "BILINEAR", 0, "Bilinear", ""}, {2, "BICUBIC", 0, "Bicubic", ""}, {0, NULL, 0, NULL, NULL} }; - - -EnumPropertyItem prop_noise_basis_items[] = { - {SHD_NOISE_PERLIN, "PERLIN", 0, "Perlin", ""}, - {SHD_NOISE_VORONOI_F1, "VORONOI_F1", 0, "Voronoi F1", ""}, - {SHD_NOISE_VORONOI_F2, "VORONOI_F2", 0, "Voronoi F2", ""}, - {SHD_NOISE_VORONOI_F3, "VORONOI_F3", 0, "Voronoi F3", ""}, - {SHD_NOISE_VORONOI_F4, "VORONOI_F4", 0, "Voronoi F4", ""}, - {SHD_NOISE_VORONOI_F2_F1, "VORONOI_F2_F1", 0, "Voronoi F2-F1", ""}, - {SHD_NOISE_VORONOI_CRACKLE, "VORONOI_CRACKLE", 0, "Voronoi Crackle", ""}, - {SHD_NOISE_CELL_NOISE, "CELL_NOISE", 0, "Cell Noise", ""}, - {0, NULL, 0, NULL, NULL} -}; - -EnumPropertyItem prop_noise_type_items[] = { - {SHD_NOISE_SOFT, "SOFT", 0, "Soft", ""}, - {SHD_NOISE_HARD, "HARD", 0, "Hard", ""}, - {0, NULL, 0, NULL, NULL} -}; - -#if 0 -EnumPropertyItem prop_wave_items[] = { - {SHD_WAVE_SINE, "SINE", 0, "Sine", "Use a sine wave to produce bands"}, - {SHD_WAVE_SAW, "SAW", 0, "Saw", "Use a saw wave to produce bands"}, - {SHD_WAVE_TRI, "TRI", 0, "Tri", "Use a triangle wave to produce bands"}, - {0, NULL, 0, NULL, NULL} -}; #endif #ifdef RNA_RUNTIME @@ -214,26 +190,30 @@ EnumPropertyItem prop_wave_items[] = { int rna_node_tree_type_to_enum(bNodeTreeType *typeinfo) { int i = 0, result = -1; - NODE_TREE_TYPES_BEGIN(nt) + NODE_TREE_TYPES_BEGIN (nt) + { if (nt == typeinfo) { result = i; break; } ++i; - NODE_TREE_TYPES_END + } + NODE_TREE_TYPES_END; return result; } int rna_node_tree_idname_to_enum(const char *idname) { int i = 0, result = -1; - NODE_TREE_TYPES_BEGIN(nt) + NODE_TREE_TYPES_BEGIN (nt) + { if (STREQ(nt->idname, idname)) { result = i; break; } ++i; - NODE_TREE_TYPES_END + } + NODE_TREE_TYPES_END; return result; } @@ -241,13 +221,15 @@ bNodeTreeType *rna_node_tree_type_from_enum(int value) { int i = 0; bNodeTreeType *result = NULL; - NODE_TREE_TYPES_BEGIN(nt) + NODE_TREE_TYPES_BEGIN (nt) + { if (i == value) { result = nt; break; } ++i; - NODE_TREE_TYPES_END + } + NODE_TREE_TYPES_END; return result; } @@ -257,7 +239,8 @@ EnumPropertyItem *rna_node_tree_type_itemf(void *data, int (*poll)(void *data, b EnumPropertyItem *item = NULL; int totitem = 0, i = 0; - NODE_TREE_TYPES_BEGIN(nt) + NODE_TREE_TYPES_BEGIN (nt) + { if (poll && !poll(data, nt)) { ++i; continue; @@ -272,7 +255,8 @@ EnumPropertyItem *rna_node_tree_type_itemf(void *data, int (*poll)(void *data, b RNA_enum_item_add(&item, &totitem, &tmp); ++i; - NODE_TREE_TYPES_END + } + NODE_TREE_TYPES_END; RNA_enum_item_end(&item, &totitem); *free = 1; @@ -600,8 +584,9 @@ static void rna_NodeTree_unregister(Main *UNUSED(bmain), StructRNA *type) WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); } -static StructRNA *rna_NodeTree_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_NodeTree_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeTreeType *nt, dummynt; bNodeTree dummyntree; @@ -668,7 +653,7 @@ static bool rna_NodeTree_check(bNodeTree *ntree, ReportList *reports) return true; } -static void rna_NodeTree_update(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_NodeTree_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->id.data; @@ -931,22 +916,6 @@ static void rna_NodeTree_active_output_set(PointerRNA *ptr, int value) } } -static int rna_NodeTree_inputs_lookupstring(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) -{ - bNodeTree *ntree = (bNodeTree *)ptr->data; - bNodeSocket *sock = ntreeFindSocketInterface(ntree, SOCK_IN, key); - RNA_pointer_create(ptr->id.data, &RNA_NodeSocketInterface, sock, r_ptr); - return (sock != NULL); -} - -static int rna_NodeTree_outputs_lookupstring(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) -{ - bNodeTree *ntree = (bNodeTree *)ptr->data; - bNodeSocket *sock = ntreeFindSocketInterface(ntree, SOCK_OUT, key); - RNA_pointer_create(ptr->id.data, &RNA_NodeSocketInterface, sock, r_ptr); - return (sock != NULL); -} - static bNodeSocket *rna_NodeTree_inputs_new(bNodeTree *ntree, ReportList *reports, const char *type, const char *name) { bNodeSocket *sock; @@ -1422,9 +1391,10 @@ static bNodeType *rna_Node_register_base(Main *bmain, ReportList *reports, Struc return nt; } -static StructRNA *rna_Node_register(Main *bmain, ReportList *reports, - void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_Node_register( + Main *bmain, ReportList *reports, + void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base(bmain, reports, &RNA_Node, data, identifier, validate, call, free); if (!nt) @@ -1438,9 +1408,10 @@ static StructRNA *rna_Node_register(Main *bmain, ReportList *reports, return nt->ext.srna; } -static StructRNA *rna_ShaderNode_register(Main *bmain, ReportList *reports, - void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_ShaderNode_register( + Main *bmain, ReportList *reports, + void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base(bmain, reports, &RNA_ShaderNode, data, identifier, validate, call, free); if (!nt) @@ -1454,9 +1425,10 @@ static StructRNA *rna_ShaderNode_register(Main *bmain, ReportList *reports, return nt->ext.srna; } -static StructRNA *rna_CompositorNode_register(Main *bmain, ReportList *reports, - void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_CompositorNode_register( + Main *bmain, ReportList *reports, + void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base(bmain, reports, &RNA_CompositorNode, data, identifier, validate, call, free); if (!nt) @@ -1470,9 +1442,10 @@ static StructRNA *rna_CompositorNode_register(Main *bmain, ReportList *reports, return nt->ext.srna; } -static StructRNA *rna_TextureNode_register(Main *bmain, ReportList *reports, - void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_TextureNode_register( + Main *bmain, ReportList *reports, + void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base(bmain, reports, &RNA_TextureNode, data, identifier, validate, call, free); if (!nt) @@ -1573,22 +1546,6 @@ static void rna_Node_name_set(PointerRNA *ptr, const char *value) BKE_all_animdata_fix_paths_rename(NULL, "nodes", oldname, node->name); } -static int rna_Node_inputs_lookupstring(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) -{ - bNode *node = (bNode *)ptr->data; - bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, key); - RNA_pointer_create(ptr->id.data, &RNA_NodeSocket, sock, r_ptr); - return (sock != NULL); -} - -static int rna_Node_outputs_lookupstring(PointerRNA *ptr, const char *key, PointerRNA *r_ptr) -{ - bNode *node = (bNode *)ptr->data; - bNodeSocket *sock = nodeFindSocket(node, SOCK_OUT, key); - RNA_pointer_create(ptr->id.data, &RNA_NodeSocket, sock, r_ptr); - return (sock != NULL); -} - static bNodeSocket *rna_Node_inputs_new(ID *id, bNode *node, ReportList *reports, const char *type, const char *name, const char *identifier) { bNodeTree *ntree = (bNodeTree *)id; @@ -1810,8 +1767,9 @@ static void rna_NodeSocket_unregister(Main *UNUSED(bmain), StructRNA *type) WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); } -static StructRNA *rna_NodeSocket_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_NodeSocket_register( + Main *UNUSED(bmain), ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeSocketType *st, dummyst; bNodeSocket dummysock; @@ -2081,8 +2039,9 @@ static void rna_NodeSocketInterface_unregister(Main *UNUSED(bmain), StructRNA *t WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); } -static StructRNA *rna_NodeSocketInterface_register(Main *bmain, ReportList *reports, void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_NodeSocketInterface_register( + Main *UNUSED(bmain), ReportList *UNUSED(reports), void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeSocketType *st, dummyst; bNodeSocket dummysock; @@ -2398,9 +2357,10 @@ static void rna_NodeInternal_draw_buttons_ext(ID *id, bNode *node, struct bConte } } -static StructRNA *rna_NodeCustomGroup_register(Main *bmain, ReportList *reports, - void *data, const char *identifier, - StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +static StructRNA *rna_NodeCustomGroup_register( + Main *bmain, ReportList *reports, + void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { bNodeType *nt = rna_Node_register_base(bmain, reports, &RNA_NodeCustomGroup, data, identifier, validate, call, free); if (!nt) @@ -2782,6 +2742,23 @@ static void rna_NodeOutputFileSlotLayer_name_set(PointerRNA *ptr, const char *va } } +static bNodeSocket *rna_NodeOutputFile_slots_new(ID *id, bNode *node, bContext *C, ReportList *UNUSED(reports), const char *name) +{ + bNodeTree *ntree = (bNodeTree *)id; + Scene *scene = CTX_data_scene(C); + ImageFormatData *im_format = NULL; + bNodeSocket *sock; + if (scene) + im_format = &scene->r.im_format; + + sock = ntreeCompositOutputFileAddSocket(ntree, node, name, im_format); + + ntreeUpdateTree(CTX_data_main(C), ntree); + WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); + + return sock; +} + static void rna_ShaderNodeScript_mode_set(PointerRNA *ptr, int value) { bNode *node = (bNode *)ptr->data; @@ -2861,6 +2838,24 @@ static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *p ED_node_tag_update_nodetree(bmain, ntree); } +static void rna_ShaderNodeSubsurface_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + bNodeTree *ntree = (bNodeTree *)ptr->id.data; + bNode *node = (bNode *)ptr->data; + + nodeUpdate(ntree, node); + rna_Node_update(bmain, scene, ptr); +} + +static void rna_CompositorNodeScale_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + bNodeTree *ntree = (bNodeTree *)ptr->id.data; + bNode *node = (bNode *)ptr->data; + + nodeUpdate(ntree, node); + rna_Node_update(bmain, scene, ptr); +} + #else static EnumPropertyItem prop_image_layer_items[] = { @@ -2907,6 +2902,12 @@ static EnumPropertyItem node_toon_items[] = { {0, NULL, 0, NULL, NULL} }; +static EnumPropertyItem node_hair_items[] = { + {SHD_HAIR_REFLECTION, "Reflection", 0, "Reflection", ""}, + {SHD_HAIR_TRANSMISSION, "Transmission", 0, "Transmission", ""}, + {0, NULL, 0, NULL, NULL} +}; + static EnumPropertyItem node_script_mode_items[] = { {NODE_SCRIPT_INTERNAL, "INTERNAL", 0, "Internal", "Use internal text datablock"}, {NODE_SCRIPT_EXTERNAL, "EXTERNAL", 0, "External", "Use external .osl or .oso file"}, @@ -3143,10 +3144,24 @@ static void def_sh_material(StructRNA *srna) static void def_sh_mapping(StructRNA *srna) { + static EnumPropertyItem prop_vect_type_items[] = { + {TEXMAP_TYPE_TEXTURE, "TEXTURE", 0, "Texture", "Transform a texture by inverse mapping the texture coordinate"}, + {TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transform a point"}, + {TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"}, + {TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"}, + {0, NULL, 0, NULL, NULL} + }; + PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "TexMapping", "storage"); + prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, prop_vect_type_items); + RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms"); + RNA_def_property_update(prop, 0, "rna_Mapping_Node_update"); + prop = RNA_def_property(srna, "translation", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_float_sdna(prop, NULL, "loc"); RNA_def_property_ui_text(prop, "Location", ""); @@ -3230,19 +3245,37 @@ static void def_sh_tex(StructRNA *srna) static void def_sh_tex_sky(StructRNA *srna) { + static EnumPropertyItem prop_sky_type[] = { + {SHD_SKY_OLD, "PREETHAM", 0, "Preetham", ""}, + {SHD_SKY_NEW, "HOSEK_WILKIE", 0, "Hosek / Wilkie", ""}, + {0, NULL, 0, NULL, NULL} + }; + PropertyRNA *prop; RNA_def_struct_sdna_from(srna, "NodeTexSky", "storage"); def_sh_tex(srna); + + prop = RNA_def_property(srna, "sky_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "sky_model"); + RNA_def_property_enum_items(prop, prop_sky_type); + RNA_def_property_ui_text(prop, "Sky Type", ""); + RNA_def_property_update(prop, 0, "rna_Node_update"); prop = RNA_def_property(srna, "sun_direction", PROP_FLOAT, PROP_DIRECTION); RNA_def_property_ui_text(prop, "Sun Direction", "Direction from where the sun is shining"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "turbidity", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 1.0f, 30.0f); + RNA_def_property_range(prop, 1.0f, 10.0f); + RNA_def_property_ui_range(prop, 1.0f, 10.0f, 10, 3); RNA_def_property_ui_text(prop, "Turbidity", "Atmospheric turbidity"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "ground_albedo", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Ground Albedo", "Ground color that is subtly reflected in the sky"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_sh_tex_environment(StructRNA *srna) @@ -3512,9 +3545,9 @@ static void def_sh_tex_coord(StructRNA *srna) static void def_sh_vect_transform(StructRNA *srna) { static EnumPropertyItem prop_vect_type_items[] = { - {SHD_VECT_TRANSFORM_TYPE_VECTOR, "VECTOR", 0, "Vector", ""}, - {SHD_VECT_TRANSFORM_TYPE_POINT, "POINT", 0, "Point", ""}, - {SHD_VECT_TRANSFORM_TYPE_NORMAL, "NORMAL", 0, "Normal", ""}, + {SHD_VECT_TRANSFORM_TYPE_POINT, "POINT", 0, "Point", "Transform a point"}, + {SHD_VECT_TRANSFORM_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"}, + {SHD_VECT_TRANSFORM_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"}, {0, NULL, 0, NULL, NULL} }; @@ -3529,7 +3562,8 @@ static void def_sh_vect_transform(StructRNA *srna) RNA_def_struct_sdna_from(srna, "NodeShaderVectTransform", "storage"); - prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); RNA_def_property_enum_items(prop, prop_vect_type_items); RNA_def_property_ui_text(prop, "Type", ""); RNA_def_property_update(prop, 0, "rna_Node_update"); @@ -3587,6 +3621,17 @@ static void def_sh_bump(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_hair(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "component", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, node_hair_items); + RNA_def_property_ui_text(prop, "Component", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_sh_normal_map(StructRNA *srna) { static EnumPropertyItem prop_space_items[] = { @@ -3650,6 +3695,24 @@ static void def_sh_tangent(StructRNA *srna) RNA_def_struct_sdna_from(srna, "bNode", NULL); } + +static void def_sh_subsurface(StructRNA *srna) +{ + static EnumPropertyItem prop_subsurface_falloff_items[] = { + {SHD_SUBSURFACE_CUBIC, "CUBIC", 0, "Cubic", "Simple cubic falloff function"}, + {SHD_SUBSURFACE_GAUSSIAN, "GAUSSIAN", 0, "Gaussian", "Normal distribution, multiple can be combined to fit more complex profiles"}, + {0, NULL, 0, NULL, NULL} + }; + + PropertyRNA *prop; + + prop = RNA_def_property(srna, "falloff", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, prop_subsurface_falloff_items); + RNA_def_property_ui_text(prop, "Falloff", "Function to determine how much light nearby points contribute based on their distance to the shading point"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodeSubsurface_update"); +} + static void def_sh_script(StructRNA *srna) { PropertyRNA *prop; @@ -4121,7 +4184,49 @@ static void rna_def_cmp_output_file_slot_layer(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Name", "OpenEXR layer name used for this slot"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL); } -static void def_cmp_output_file(StructRNA *srna) +static void rna_def_cmp_output_file_slots_api(BlenderRNA *brna, PropertyRNA *cprop, const char *struct_name) +{ + StructRNA *srna; + PropertyRNA *parm; + FunctionRNA *func; + + RNA_def_property_srna(cprop, struct_name); + srna = RNA_def_struct(brna, struct_name, NULL); + RNA_def_struct_sdna(srna, "bNode"); + RNA_def_struct_ui_text(srna, "File Output Slots", "Collection of File Output node slots"); + + func = RNA_def_function(srna, "new", "rna_NodeOutputFile_slots_new"); + RNA_def_function_ui_description(func, "Add a file slot to this node"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS | FUNC_USE_CONTEXT); + parm = RNA_def_string(func, "name", "", MAX_NAME, "Name", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + /* return value */ + parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "New socket"); + RNA_def_function_return(func, parm); + + /* NB: methods below can use the standard node socket API functions, + * included here for completeness. + */ + + func = RNA_def_function(srna, "remove", "rna_Node_socket_remove"); + RNA_def_function_ui_description(func, "Remove a file slot from this node"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "The socket to remove"); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func = RNA_def_function(srna, "clear", "rna_Node_inputs_clear"); + RNA_def_function_ui_description(func, "Remove all file slots from this node"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + + func = RNA_def_function(srna, "move", "rna_Node_inputs_move"); + RNA_def_function_ui_description(func, "Move a file slot to another position"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + parm = RNA_def_int(func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_int(func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000); + RNA_def_property_flag(parm, PROP_REQUIRED); +} +static void def_cmp_output_file(BlenderRNA *brna, StructRNA *srna) { PropertyRNA *prop; @@ -4149,12 +4254,14 @@ static void def_cmp_output_file(StructRNA *srna) "rna_NodeOutputFile_slot_file_get", NULL, NULL, NULL, NULL); RNA_def_property_struct_type(prop, "NodeOutputFileSlotFile"); RNA_def_property_ui_text(prop, "File Slots", ""); + rna_def_cmp_output_file_slots_api(brna, prop, "CompositorNodeOutputFileFileSlots"); prop = RNA_def_property(srna, "layer_slots", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_funcs(prop, "rna_NodeOutputFile_slots_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_NodeOutputFile_slot_layer_get", NULL, NULL, NULL, NULL); RNA_def_property_struct_type(prop, "NodeOutputFileSlotLayer"); RNA_def_property_ui_text(prop, "EXR Layer Slots", ""); + rna_def_cmp_output_file_slots_api(brna, prop, "CompositorNodeOutputFileLayerSlots"); } static void def_cmp_dilate_erode(StructRNA *srna) @@ -4261,7 +4368,7 @@ static void def_cmp_scale(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, space_items); RNA_def_property_ui_text(prop, "Space", "Coordinate space to scale relative to"); - RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_CompositorNodeScale_update"); /* expose 2 flags as a enum of 3 items */ prop = RNA_def_property(srna, "frame_method", PROP_ENUM, PROP_NONE); @@ -5336,7 +5443,7 @@ static void dev_cmd_transform(StructRNA *srna) /* -- Compositor Nodes ------------------------------------------------------ */ -EnumPropertyItem node_masktype_items[] = { +static EnumPropertyItem node_masktype_items[] = { {0, "ADD", 0, "Add", ""}, {1, "SUBTRACT", 0, "Subtract", ""}, {2, "MULTIPLY", 0, "Multiply", ""}, @@ -5919,6 +6026,29 @@ static void def_cmp_translate(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_cmp_planetrackdeform(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "id"); + RNA_def_property_struct_type(prop, "MovieClip"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Movie Clip", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + RNA_def_struct_sdna_from(srna, "NodePlaneTrackDeformData", "storage"); + + prop = RNA_def_property(srna, "tracking_object", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "tracking_object"); + RNA_def_property_ui_text(prop, "Tracking Object", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "plane_track_name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "plane_track_name"); + RNA_def_property_ui_text(prop, "Plane Track", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} /* -- Texture Nodes --------------------------------------------------------- */ @@ -6809,16 +6939,12 @@ static void rna_def_node(BlenderRNA *brna) prop = RNA_def_property(srna, "inputs", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "inputs", NULL); - RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, - "rna_Node_inputs_lookupstring", NULL); RNA_def_property_struct_type(prop, "NodeSocket"); RNA_def_property_ui_text(prop, "Inputs", ""); rna_def_node_sockets_api(brna, prop, SOCK_IN); prop = RNA_def_property(srna, "outputs", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "outputs", NULL); - RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, - "rna_Node_outputs_lookupstring", NULL); RNA_def_property_struct_type(prop, "NodeSocket"); RNA_def_property_ui_text(prop, "Outputs", ""); rna_def_node_sockets_api(brna, prop, SOCK_OUT); @@ -7234,8 +7360,6 @@ static void rna_def_nodetree(BlenderRNA *brna) prop = RNA_def_property(srna, "inputs", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "inputs", NULL); - RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, - "rna_NodeTree_inputs_lookupstring", NULL); RNA_def_property_struct_type(prop, "NodeSocketInterface"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Inputs", "Node tree inputs"); @@ -7248,8 +7372,6 @@ static void rna_def_nodetree(BlenderRNA *brna) prop = RNA_def_property(srna, "outputs", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "outputs", NULL); - RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, - "rna_NodeTree_outputs_lookupstring", NULL); RNA_def_property_struct_type(prop, "NodeSocketInterface"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Outputs", "Node tree outputs"); @@ -7381,8 +7503,8 @@ static void rna_def_texture_nodetree(BlenderRNA *brna) RNA_def_struct_ui_icon(srna, ICON_TEXTURE); } -static void define_specific_node(BlenderRNA *brna, const char *struct_name, const char *base_name, - const char *ui_name, const char *ui_desc, void (*def_func)(StructRNA *)) +static StructRNA *define_specific_node(BlenderRNA *brna, const char *struct_name, const char *base_name, + const char *ui_name, const char *ui_desc, void (*def_func)(StructRNA *)) { StructRNA *srna; FunctionRNA *func; @@ -7429,6 +7551,8 @@ static void define_specific_node(BlenderRNA *brna, const char *struct_name, cons if (def_func) def_func(srna); + + return srna; } static void rna_def_node_instance_hash(BlenderRNA *brna) @@ -7446,6 +7570,8 @@ static void rna_def_node_instance_hash(BlenderRNA *brna) void RNA_def_nodetree(BlenderRNA *brna) { + StructRNA *srna; + rna_def_node_socket(brna); rna_def_node_socket_interface(brna); @@ -7466,7 +7592,13 @@ void RNA_def_nodetree(BlenderRNA *brna) rna_def_texture_nodetree(brna); #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \ - define_specific_node(brna, #Category #StructName, #Category, UIName, UIDesc, DefFunc); + { \ + srna = define_specific_node(brna, #Category #StructName, #Category, UIName, UIDesc, DefFunc); \ + if (ID == CMP_NODE_OUTPUT_FILE) { \ + /* needs brna argument, can't use NOD_static_types.h */ \ + def_cmp_output_file(brna, srna); \ + } \ + } /* hack, don't want to add include path to RNA just for this, since in the future RNA types * for nodes should be defined locally at runtime anyway ... diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index e71d1d22c4b..dffdc988ca6 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -465,7 +465,7 @@ static EnumPropertyItem *rna_Object_parent_type_itemf(bContext *UNUSED(C), Point RNA_enum_items_add_value(&item, &totitem, parent_type_items, PARBONE); } - if (ELEM4(par->type, OB_MESH, OB_CURVE, OB_SURF, OB_LATTICE)) { + if (OB_TYPE_SUPPORT_PARVERT(par->type)) { RNA_enum_items_add_value(&item, &totitem, parent_type_items, PARVERT1); RNA_enum_items_add_value(&item, &totitem, parent_type_items, PARVERT3); } @@ -556,7 +556,8 @@ static void rna_Object_active_vertex_group_index_set(PointerRNA *ptr, int value) ob->actdef = value + 1; } -static void rna_Object_active_vertex_group_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_Object_active_vertex_group_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { Object *ob = (Object *)ptr->id.data; @@ -667,7 +668,8 @@ static void rna_Object_active_material_index_set(PointerRNA *ptr, int value) } } -static void rna_Object_active_material_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_Object_active_material_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { Object *ob = (Object *)ptr->id.data; *min = 0; @@ -693,7 +695,7 @@ static void rna_Object_active_material_set(PointerRNA *ptr, PointerRNA value) } static void rna_Object_active_particle_system_index_range(PointerRNA *ptr, int *min, int *max, - int *softmin, int *softmax) + int *UNUSED(softmin), int *UNUSED(softmax)) { Object *ob = (Object *)ptr->id.data; *min = 0; @@ -903,6 +905,16 @@ static void rna_MaterialSlot_update(Main *bmain, Scene *scene, PointerRNA *ptr) { rna_Object_internal_update(bmain, scene, ptr); WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, ptr->id.data); + WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, NULL); +} + +static char *rna_MaterialSlot_path(PointerRNA *ptr) +{ + Object *ob = (Object *)ptr->id.data; + int index = (Material **)ptr->data - ob->mat; + + /* from armature... */ + return BLI_sprintfN("material_slots[%d]", index); } /* why does this have to be so complicated?, can't all this crap be @@ -1183,7 +1195,8 @@ static void rna_GameObjectSettings_col_mask_set(PointerRNA *ptr, const int *valu } -static void rna_Object_active_shape_key_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_Object_active_shape_key_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { Object *ob = (Object *)ptr->id.data; Key *key = BKE_key_from_object(ob); @@ -1549,6 +1562,8 @@ static void rna_def_material_slot(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Name", "Material slot name"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_struct_name_property(srna, prop); + + RNA_def_struct_path_func(srna, "rna_MaterialSlot_path"); } static void rna_def_object_game_settings(BlenderRNA *brna) @@ -2349,7 +2364,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "Constraint"); RNA_def_property_ui_text(prop, "Constraints", "Constraints affecting the transformation of the object"); -/* RNA_def_property_collection_funcs(prop, 0, 0, 0, 0, 0, 0, 0, "constraints__add", "constraints__remove"); */ +/* RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "constraints__add", "constraints__remove"); */ rna_def_object_constraints(brna, prop); /* game engine */ @@ -2762,11 +2777,14 @@ static void rna_def_object_base(BlenderRNA *brna) void RNA_def_object(BlenderRNA *brna) { rna_def_object(brna); + + RNA_define_animate_sdna(false); rna_def_object_game_settings(brna); rna_def_object_base(brna); rna_def_vertex_group(brna); rna_def_material_slot(brna); rna_def_dupli_object(brna); + RNA_define_animate_sdna(true); } #endif diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 1d2aa08e7cd..146ba6e4b7d 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -228,7 +228,8 @@ static void rna_Cache_list_begin(CollectionPropertyIterator *iter, PointerRNA *p rna_iterator_listbase_begin(iter, &lb, NULL); } -static void rna_Cache_active_point_cache_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_Cache_active_point_cache_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { Object *ob = ptr->id.data; PointCache *cache = ptr->data; @@ -291,7 +292,8 @@ static void rna_Cache_active_point_cache_index_set(struct PointerRNA *ptr, int v BLI_freelistN(&pidlist); } -static void rna_PointCache_frame_step_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_PointCache_frame_step_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { Object *ob = ptr->id.data; PointCache *cache = ptr->data; @@ -861,7 +863,9 @@ static void rna_def_pointcache(BlenderRNA *brna) prop = RNA_def_property(srna, "use_library_path", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", PTCACHE_IGNORE_LIBPATH); - RNA_def_property_ui_text(prop, "Library Path", "Use this files path when library linked into another file"); + RNA_def_property_ui_text(prop, "Library Path", + "Use this file's path for the disk cache when library linked into another file " + "(for local bakes per scene file, disable this option)"); RNA_def_property_update(prop, NC_OBJECT, "rna_Cache_idname_change"); prop = RNA_def_property(srna, "point_caches", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_packedfile.c b/source/blender/makesrna/intern/rna_packedfile.c index a72188591a1..365ad5fdb9a 100644 --- a/source/blender/makesrna/intern/rna_packedfile.c +++ b/source/blender/makesrna/intern/rna_packedfile.c @@ -31,6 +31,7 @@ #include "DNA_packedFile_types.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index b966a7d7f2c..8dafe54e678 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -52,34 +52,40 @@ #include "WM_types.h" #include "WM_api.h" -EnumPropertyItem part_from_items[] = { +#ifdef RNA_RUNTIME +static EnumPropertyItem part_from_items[] = { {PART_FROM_VERT, "VERT", 0, "Verts", ""}, {PART_FROM_FACE, "FACE", 0, "Faces", ""}, {PART_FROM_VOLUME, "VOLUME", 0, "Volume", ""}, {0, NULL, 0, NULL, NULL} }; +#endif -EnumPropertyItem part_reactor_from_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem part_reactor_from_items[] = { {PART_FROM_VERT, "VERT", 0, "Verts", ""}, {PART_FROM_FACE, "FACE", 0, "Faces", ""}, {PART_FROM_VOLUME, "VOLUME", 0, "Volume", ""}, {0, NULL, 0, NULL, NULL} }; +#endif -EnumPropertyItem part_dist_items[] = { +static EnumPropertyItem part_dist_items[] = { {PART_DISTR_JIT, "JIT", 0, "Jittered", ""}, {PART_DISTR_RAND, "RAND", 0, "Random", ""}, {PART_DISTR_GRID, "GRID", 0, "Grid", ""}, {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem part_hair_dist_items[] = { +#ifdef RNA_RUNTIME +static EnumPropertyItem part_hair_dist_items[] = { {PART_DISTR_JIT, "JIT", 0, "Jittered", ""}, {PART_DISTR_RAND, "RAND", 0, "Random", ""}, {0, NULL, 0, NULL, NULL} }; +#endif -EnumPropertyItem part_draw_as_items[] = { +static EnumPropertyItem part_draw_as_items[] = { {PART_DRAW_NOT, "NONE", 0, "None", ""}, {PART_DRAW_REND, "RENDER", 0, "Rendered", ""}, {PART_DRAW_DOT, "DOT", 0, "Point", ""}, @@ -89,14 +95,16 @@ EnumPropertyItem part_draw_as_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem part_hair_draw_as_items[] = { +#ifdef RNA_RUNTIME +static EnumPropertyItem part_hair_draw_as_items[] = { {PART_DRAW_NOT, "NONE", 0, "None", ""}, {PART_DRAW_REND, "RENDER", 0, "Rendered", ""}, {PART_DRAW_PATH, "PATH", 0, "Path", ""}, {0, NULL, 0, NULL, NULL} }; +#endif -EnumPropertyItem part_ren_as_items[] = { +static EnumPropertyItem part_ren_as_items[] = { {PART_DRAW_NOT, "NONE", 0, "None", ""}, {PART_DRAW_HALO, "HALO", 0, "Halo", ""}, {PART_DRAW_LINE, "LINE", 0, "Line", ""}, @@ -107,13 +115,15 @@ EnumPropertyItem part_ren_as_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem part_hair_ren_as_items[] = { +#ifdef RNA_RUNTIME +static EnumPropertyItem part_hair_ren_as_items[] = { {PART_DRAW_NOT, "NONE", 0, "None", ""}, {PART_DRAW_PATH, "PATH", 0, "Path", ""}, {PART_DRAW_OB, "OBJECT", 0, "Object", ""}, {PART_DRAW_GR, "GROUP", 0, "Group", ""}, {0, NULL, 0, NULL, NULL} }; +#endif #ifdef RNA_RUNTIME @@ -261,7 +271,8 @@ static void rna_ParticleHairKey_co_object(HairKey *hairkey, Object *object, Part } } -static void rna_Particle_uv_on_emitter(ParticleData *particle, ParticleSystemModifierData *modifier, float n_uv[2]) +static void rna_Particle_uv_on_emitter(ParticleData *particle, ReportList *reports, + ParticleSystemModifierData *modifier, float r_uv[2]) { /*psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, nor, 0, 0, sd.orco, 0);*/ @@ -269,28 +280,39 @@ static void rna_Particle_uv_on_emitter(ParticleData *particle, ParticleSystemMod int num = particle->num_dmcache; int from = modifier->psys->part->from; + if (!CustomData_has_layer(&modifier->dm->loopData, CD_MLOOPUV)) { + BKE_report(reports, RPT_ERROR, "Mesh has no UV data"); + return; + } + DM_ensure_tessface(modifier->dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */ + if (num == DMCACHE_NOTFOUND) if (particle->num < modifier->dm->getNumTessFaces(modifier->dm)) num = particle->num; /* get uvco */ - if (n_uv && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (r_uv && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { if (num != DMCACHE_NOTFOUND) { - MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); - MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0); - mtface += num; - - psys_interpolate_uvs(mtface, mface->v4, particle->fuv, n_uv); - } - else { - n_uv[0] = 0.0f; - n_uv[1] = 0.0f; + MFace *mface; + MTFace *mtface; + + mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); + mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0); + + if (mface && mtface) { + mtface += num; + psys_interpolate_uvs(mtface, mface->v4, particle->fuv, r_uv); + return; + } } } + + r_uv[0] = 0.0f; + r_uv[1] = 0.0f; } -static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *object, ParticleSystemModifierData *modifier, +static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *object, int particle_no, int step, float n_co[3]) { ParticleSettings *part = 0; @@ -368,14 +390,22 @@ static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *o } -static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, ParticleSystemModifierData *modifier, ParticleData *particle, int particle_no, int uv_no, - float n_uv[2]) +static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, ReportList *reports, + ParticleSystemModifierData *modifier, ParticleData *particle, + int particle_no, int uv_no, + float r_uv[2]) { ParticleSettings *part = 0; int totpart; int totchild = 0; int num; + if (!CustomData_has_layer(&modifier->dm->loopData, CD_MLOOPUV)) { + BKE_report(reports, RPT_ERROR, "Mesh has no UV data"); + return; + } + DM_ensure_tessface(modifier->dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */ + /* 1. check that everything is ok & updated */ if (particlesystem == NULL) return; @@ -409,17 +439,17 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, Par if (particle->num < modifier->dm->getNumTessFaces(modifier->dm)) num = particle->num; - if (n_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (r_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { if (num != DMCACHE_NOTFOUND) { MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, uv_no); mtface += num; - psys_interpolate_uvs(mtface, mface->v4, particle->fuv, n_uv); + psys_interpolate_uvs(mtface, mface->v4, particle->fuv, r_uv); } else { - n_uv[0] = 0.0f; - n_uv[1] = 0.0f; + r_uv[0] = 0.0f; + r_uv[1] = 0.0f; } } } @@ -430,17 +460,17 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, Par /* get uvco & mcol */ if (part->childtype == PART_CHILD_FACES) { - if (n_uv && ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (r_uv && ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) { if (cpa->num != DMCACHE_NOTFOUND) { MFace *mface = modifier->dm->getTessFaceData(modifier->dm, cpa->num, CD_MFACE); MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, uv_no); mtface += cpa->num; - psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, n_uv); + psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, r_uv); } else { - n_uv[0] = 0.0f; - n_uv[1] = 0.0f; + r_uv[0] = 0.0f; + r_uv[1] = 0.0f; } } } @@ -452,17 +482,17 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, Par if (parent->num < modifier->dm->getNumTessFaces(modifier->dm)) num = parent->num; - if (n_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (r_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { if (num != DMCACHE_NOTFOUND) { MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, uv_no); mtface += num; - psys_interpolate_uvs(mtface, mface->v4, parent->fuv, n_uv); + psys_interpolate_uvs(mtface, mface->v4, parent->fuv, r_uv); } else { - n_uv[0] = 0.0f; - n_uv[1] = 0.0f; + r_uv[0] = 0.0f; + r_uv[1] = 0.0f; } } } @@ -832,7 +862,8 @@ static float rna_PartSetting_linelentail_get(struct PointerRNA *ptr) ParticleSettings *settings = (ParticleSettings *)ptr->data; return settings->draw_line[0]; } -static void rna_PartSetting_pathstartend_range(PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +static void rna_PartSetting_pathstartend_range(PointerRNA *ptr, float *min, float *max, + float *UNUSED(softmin), float *UNUSED(softmax)) { ParticleSettings *settings = (ParticleSettings *)ptr->data; @@ -889,7 +920,7 @@ static PointerRNA rna_ParticleSystem_active_particle_target_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_ParticleTarget, NULL); } static void rna_ParticleSystem_active_particle_target_index_range(PointerRNA *ptr, int *min, int *max, - int *softmin, int *softmax) + int *UNUSED(softmin), int *UNUSED(softmax)) { ParticleSystem *psys = (ParticleSystem *)ptr->data; *min = 0; @@ -1011,7 +1042,8 @@ static PointerRNA rna_ParticleDupliWeight_active_get(PointerRNA *ptr) } return rna_pointer_inherit_refine(ptr, &RNA_ParticleTarget, NULL); } -static void rna_ParticleDupliWeight_active_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_ParticleDupliWeight_active_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { ParticleSettings *part = (ParticleSettings *)ptr->id.data; *min = 0; @@ -1284,8 +1316,11 @@ static void rna_def_particle_hair_key(BlenderRNA *brna) RNA_def_function_ui_description(func, "Obtain hairkey location with particle and modifier data"); prop = RNA_def_pointer(func, "object", "Object", "", "Object"); + RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); prop = RNA_def_pointer(func, "particle", "Particle", "", "hair particle"); + RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); prop = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co", "Exported hairkey location", -1e4, 1e4); @@ -1451,7 +1486,9 @@ static void rna_def_particle(BlenderRNA *brna) /* UVs */ func = RNA_def_function(srna, "uv_on_emitter", "rna_Particle_uv_on_emitter"); RNA_def_function_ui_description(func, "Obtain uv for particle on derived mesh"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS); RNA_def_property_array(prop, 2); RNA_def_property_flag(prop, PROP_THICK_WRAP); @@ -3378,7 +3415,7 @@ static void rna_def_particle_system(BlenderRNA *brna) RNA_def_function_ui_description(func, "Obtain cache hair data"); prop = RNA_def_pointer(func, "object", "Object", "", "Object"); - prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX); prop = RNA_def_int(func, "step", 0, INT_MIN, INT_MAX, "step no", "", INT_MIN, INT_MAX); @@ -3390,8 +3427,11 @@ static void rna_def_particle_system(BlenderRNA *brna) /* extract hair UVs */ func = RNA_def_function(srna, "uv_on_emitter", "rna_ParticleSystem_uv_on_emitter"); RNA_def_function_ui_description(func, "Obtain uv for all particles"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); prop = RNA_def_pointer(func, "particle", "Particle", "", "Particle"); + RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX); prop = RNA_def_int(func, "uv_no", 0, INT_MIN, INT_MAX, "UV no", "", INT_MIN, INT_MAX); prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS); @@ -3403,7 +3443,9 @@ static void rna_def_particle_system(BlenderRNA *brna) func = RNA_def_function(srna, "mcol_on_emitter", "rna_ParticleSystem_mcol_on_emitter"); RNA_def_function_ui_description(func, "Obtain mcol for all particles"); prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); prop = RNA_def_pointer(func, "particle", "Particle", "", "Particle"); + RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX); prop = RNA_def_int(func, "vcol_no", 0, INT_MIN, INT_MAX, "vcol no", "", INT_MIN, INT_MAX); prop = RNA_def_property(func, "mcol", PROP_FLOAT, PROP_COLOR); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 8c73aacc724..58217206add 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -261,7 +261,7 @@ static int rna_PoseChannel_has_ik_get(PointerRNA *ptr) Object *ob = (Object *)ptr->id.data; bPoseChannel *pchan = (bPoseChannel *)ptr->data; - return ED_pose_channel_in_IK_chain(ob, pchan); + return BKE_pose_channel_in_IK_chain(ob, pchan); } static StructRNA *rna_IKParam_refine(PointerRNA *ptr) @@ -382,7 +382,8 @@ static void rna_PoseChannel_bone_group_index_set(PointerRNA *ptr, int value) pchan->agrp_index = value + 1; } -static void rna_PoseChannel_bone_group_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_PoseChannel_bone_group_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { Object *ob = (Object *)ptr->id.data; bPose *pose = (ob) ? ob->pose : NULL; @@ -415,7 +416,8 @@ static void rna_Pose_active_bone_group_index_set(PointerRNA *ptr, int value) pose->active_group = value + 1; } -static void rna_Pose_active_bone_group_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_Pose_active_bone_group_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { bPose *pose = (bPose *)ptr->data; diff --git a/source/blender/makesrna/intern/rna_property.c b/source/blender/makesrna/intern/rna_property.c index fc3697633a4..c6b8e89c282 100644 --- a/source/blender/makesrna/intern/rna_property.c +++ b/source/blender/makesrna/intern/rna_property.c @@ -27,11 +27,13 @@ #include <stdlib.h> +#include "DNA_property_types.h" + #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" -#include "DNA_property_types.h" #include "WM_types.h" diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 82cdfcdd631..5b809a51705 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -49,6 +49,9 @@ #include "BKE_context.h" #include "BKE_report.h" +#include "IMB_colormanagement.h" +#include "GPU_extensions.h" + /* RenderEngine Callbacks */ static void engine_tag_redraw(RenderEngine *engine) @@ -61,6 +64,23 @@ static void engine_tag_update(RenderEngine *engine) engine->flag |= RE_ENGINE_DO_UPDATE; } +static int engine_support_display_space_shader(RenderEngine *UNUSED(engine), Scene *scene) +{ + return IMB_colormanagement_support_glsl_draw(&scene->view_settings, true); +} + +static void engine_bind_display_space_shader(RenderEngine *UNUSED(engine), Scene *scene) +{ + IMB_colormanagement_setup_glsl_draw(&scene->view_settings, + &scene->display_settings, + false, true); +} + +static void engine_unbind_display_space_shader(RenderEngine *UNUSED(engine)) +{ + IMB_colormanagement_finish_glsl_draw(); +} + static void engine_update(RenderEngine *engine, Main *bmain, Scene *scene) { extern FunctionRNA rna_RenderEngine_update_func; @@ -342,14 +362,15 @@ static void rna_def_render_engine(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_RNAPTR); /* tag for redraw */ - RNA_def_function(srna, "tag_redraw", "engine_tag_redraw"); + func = RNA_def_function(srna, "tag_redraw", "engine_tag_redraw"); RNA_def_function_ui_description(func, "Request redraw for viewport rendering"); /* tag for update */ - RNA_def_function(srna, "tag_update", "engine_tag_update"); + func = RNA_def_function(srna, "tag_update", "engine_tag_update"); RNA_def_function_ui_description(func, "Request update call for viewport rendering"); func = RNA_def_function(srna, "begin_result", "RE_engine_begin_result"); + RNA_def_function_ui_description(func, "Create render result to write linear floating point render layers and passes"); prop = RNA_def_int(func, "x", 0, 0, INT_MAX, "X", "", 0, INT_MAX); RNA_def_property_flag(prop, PROP_REQUIRED); prop = RNA_def_int(func, "y", 0, 0, INT_MAX, "Y", "", 0, INT_MAX); @@ -363,39 +384,61 @@ static void rna_def_render_engine(BlenderRNA *brna) RNA_def_function_return(func, prop); func = RNA_def_function(srna, "update_result", "RE_engine_update_result"); + RNA_def_function_ui_description(func, "Signal that pixels have been updated and can be redrawn in the user interface"); prop = RNA_def_pointer(func, "result", "RenderResult", "Result", ""); RNA_def_property_flag(prop, PROP_REQUIRED); func = RNA_def_function(srna, "end_result", "RE_engine_end_result"); + RNA_def_function_ui_description(func, "All pixels in the render result have been set and are final"); prop = RNA_def_pointer(func, "result", "RenderResult", "Result", ""); RNA_def_property_flag(prop, PROP_REQUIRED); RNA_def_boolean(func, "cancel", 0, "Cancel", "Don't merge back results"); func = RNA_def_function(srna, "test_break", "RE_engine_test_break"); + RNA_def_function_ui_description(func, "Test if the render operation should been cancelled, this is a fast call that should be used regularly for responsiveness"); prop = RNA_def_boolean(func, "do_break", 0, "Break", ""); RNA_def_function_return(func, prop); func = RNA_def_function(srna, "update_stats", "RE_engine_update_stats"); + RNA_def_function_ui_description(func, "Update and signal to redraw render status text"); prop = RNA_def_string(func, "stats", "", 0, "Stats", ""); RNA_def_property_flag(prop, PROP_REQUIRED); prop = RNA_def_string(func, "info", "", 0, "Info", ""); RNA_def_property_flag(prop, PROP_REQUIRED); func = RNA_def_function(srna, "update_progress", "RE_engine_update_progress"); + RNA_def_function_ui_description(func, "Update progress percentage of render"); prop = RNA_def_float(func, "progress", 0, 0.0f, 1.0f, "", "Percentage of render that's done", 0.0f, 1.0f); RNA_def_property_flag(prop, PROP_REQUIRED); func = RNA_def_function(srna, "update_memory_stats", "RE_engine_update_memory_stats"); + RNA_def_function_ui_description(func, "Update memory usage statistics"); RNA_def_float(func, "memory_used", 0, 0.0f, FLT_MAX, "", "Current memory usage in megabytes", 0.0f, FLT_MAX); RNA_def_float(func, "memory_peak", 0, 0.0f, FLT_MAX, "", "Peak memory usage in megabytes", 0.0f, FLT_MAX); RNA_def_property_flag(prop, PROP_REQUIRED); func = RNA_def_function(srna, "report", "RE_engine_report"); + RNA_def_function_ui_description(func, "Report info, warning or error messages"); prop = RNA_def_enum_flag(func, "type", wm_report_items, 0, "Type", ""); RNA_def_property_flag(prop, PROP_REQUIRED); prop = RNA_def_string(func, "message", "", 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", "", ""); + RNA_def_property_flag(prop, PROP_REQUIRED); + + func = RNA_def_function(srna, "unbind_display_space_shader", "engine_unbind_display_space_shader"); + RNA_def_function_ui_description(func, "Unbind GLSL display space shader, must always be called after binding the shader"); + + func = RNA_def_function(srna, "support_display_space_shader", "engine_support_display_space_shader"); + RNA_def_function_ui_description(func, "Test if GLSL display space shader is supported for the combination of graphics card and scene settings"); + prop = RNA_def_pointer(func, "scene", "Scene", "", ""); + RNA_def_property_flag(prop, PROP_REQUIRED); + prop = RNA_def_boolean(func, "supported", 0, "Supported", ""); + RNA_def_function_return(func, prop); + RNA_define_verify_sdna(0); prop = RNA_def_property(srna, "is_animation", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index a4e02d6e835..cc14e60f45a 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -29,6 +29,7 @@ #include <string.h> #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -95,14 +96,14 @@ EnumPropertyItem rigidbody_constraint_type_items[] = { /* ******************************** */ -static void rna_RigidBodyWorld_reset(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_RigidBodyWorld_reset(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { RigidBodyWorld *rbw = (RigidBodyWorld *)ptr->data; BKE_rigidbody_cache_reset(rbw); } -static char *rna_RigidBodyWorld_path(PointerRNA *ptr) +static char *rna_RigidBodyWorld_path(PointerRNA *UNUSED(ptr)) { return BLI_sprintfN("rigidbody_world"); } @@ -135,14 +136,14 @@ static void rna_RigidBodyWorld_split_impulse_set(PointerRNA *ptr, int value) /* ******************************** */ -static void rna_RigidBodyOb_reset(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_RigidBodyOb_reset(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) { RigidBodyWorld *rbw = scene->rigidbody_world; BKE_rigidbody_cache_reset(rbw); } -static void rna_RigidBodyOb_shape_reset(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_RigidBodyOb_shape_reset(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) { RigidBodyWorld *rbw = scene->rigidbody_world; RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; @@ -152,7 +153,7 @@ static void rna_RigidBodyOb_shape_reset(Main *bmain, Scene *scene, PointerRNA *p rbo->flag |= RBO_FLAG_NEEDS_RESHAPE; } -static char *rna_RigidBodyOb_path(PointerRNA *ptr) +static char *rna_RigidBodyOb_path(PointerRNA *UNUSED(ptr)) { /* NOTE: this hardcoded path should work as long as only Objects have this */ return BLI_sprintfN("rigid_body"); @@ -166,6 +167,14 @@ static void rna_RigidBodyOb_type_set(PointerRNA *ptr, int value) rbo->flag |= RBO_FLAG_NEEDS_VALIDATE; } +static void rna_RigidBodyOb_shape_set(PointerRNA *ptr, int value) +{ + RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; + + rbo->shape = value; + rbo->flag |= RBO_FLAG_NEEDS_VALIDATE; +} + static void rna_RigidBodyOb_disabled_set(PointerRNA *ptr, int value) { RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; @@ -334,7 +343,7 @@ static void rna_RigidBodyOb_angular_damping_set(PointerRNA *ptr, float value) #endif } -static char *rna_RigidBodyCon_path(PointerRNA *ptr) +static char *rna_RigidBodyCon_path(PointerRNA *UNUSED(ptr)) { /* NOTE: this hardcoded path should work as long as only Objects have this */ return BLI_sprintfN("rigid_body_constraint"); @@ -595,13 +604,17 @@ static void rna_RigidBodyCon_motor_ang_target_velocity_set(PointerRNA *ptr, floa } /* Sweep test */ -static void rna_RigidBodyWorld_convex_sweep_test(RigidBodyWorld *rbw, ReportList *reports, Object *object, float ray_start[3], float ray_end[3], float r_location[3], float r_hitpoint[3], float r_normal[3], int *r_hit) +static void rna_RigidBodyWorld_convex_sweep_test( + RigidBodyWorld *rbw, ReportList *reports, + Object *object, float ray_start[3], float ray_end[3], + float r_location[3], float r_hitpoint[3], float r_normal[3], int *r_hit) { #ifdef WITH_BULLET RigidBodyOb *rob = object->rigidbody_object; if (rbw->physics_world != NULL && rob->physics_object != NULL) { - RB_world_convex_sweep_test(rbw->physics_world, rob->physics_object, ray_start, ray_end, r_location, r_hitpoint, r_normal, r_hit); + RB_world_convex_sweep_test(rbw->physics_world, rob->physics_object, ray_start, ray_end, + r_location, r_hitpoint, r_normal, r_hit); if (*r_hit == -2) { BKE_report(reports, RPT_ERROR, "A non convex collision shape was passed to the function, use only convex collision shapes"); @@ -611,6 +624,9 @@ static void rna_RigidBodyWorld_convex_sweep_test(RigidBodyWorld *rbw, ReportList *r_hit = -1; 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; #endif } @@ -763,6 +779,7 @@ static void rna_def_rigidbody_object(BlenderRNA *brna) prop = RNA_def_property(srna, "collision_shape", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "shape"); RNA_def_property_enum_items(prop, rigidbody_object_shape_items); + RNA_def_property_enum_funcs(prop, NULL, "rna_RigidBodyOb_shape_set", NULL); RNA_def_property_ui_text(prop, "Collision Shape", "Collision Shape of object in Rigid Body Simulations"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 67fc3056485..380bde90ff9 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -566,6 +566,12 @@ static int rna_Property_is_required_get(PointerRNA *ptr) return prop->flag & PROP_REQUIRED ? 1 : 0; } +static int rna_Property_is_argument_optional_get(PointerRNA *ptr) +{ + PropertyRNA *prop = (PropertyRNA *)ptr->data; + return prop->flag & PROP_PYFUNC_OPTIONAL ? 1 : 0; +} + static int rna_Property_is_never_none_get(PointerRNA *ptr) { PropertyRNA *prop = (PropertyRNA *)ptr->data; @@ -1171,6 +1177,12 @@ static void rna_def_property(BlenderRNA *brna) RNA_def_property_boolean_funcs(prop, "rna_Property_is_required_get", NULL); RNA_def_property_ui_text(prop, "Required", "False when this property is an optional argument in an RNA function"); + prop = RNA_def_property(srna, "is_argument_optional", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_funcs(prop, "rna_Property_is_argument_optional_get", NULL); + RNA_def_property_ui_text(prop, "Optional Argument", + "True when the property is optional in a Python function implementing an RNA function"); + prop = RNA_def_property(srna, "is_never_none", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_boolean_funcs(prop, "rna_Property_is_never_none_get", NULL); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 83dbd79024e..0cfb399c470 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -487,7 +487,11 @@ static void rna_Scene_view3d_update(Main *bmain, Scene *UNUSED(scene_unused), Po static void rna_Scene_layer_update(Main *bmain, Scene *scene, PointerRNA *ptr) { rna_Scene_view3d_update(bmain, scene, ptr); - DAG_on_visible_update(bmain, FALSE); + /* XXX We would need do_time=true here, else we can have update issues like [#36289]... + * However, this has too much drawbacks (like slower layer switch, undesired updates...). + * That's TODO for future DAG updates. + */ + DAG_on_visible_update(bmain, false); } static void rna_Scene_fps_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) @@ -777,7 +781,7 @@ static void rna_ImageFormatSettings_file_format_set(PointerRNA *ptr, int value) } } -static EnumPropertyItem *rna_ImageFormatSettings_file_format_itemf(bContext *C, PointerRNA *ptr, +static EnumPropertyItem *rna_ImageFormatSettings_file_format_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *UNUSED(free)) { ID *id = ptr->id.data; @@ -789,7 +793,7 @@ static EnumPropertyItem *rna_ImageFormatSettings_file_format_itemf(bContext *C, } } -static EnumPropertyItem *rna_ImageFormatSettings_color_mode_itemf(bContext *C, PointerRNA *ptr, +static EnumPropertyItem *rna_ImageFormatSettings_color_mode_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *free) { ImageFormatData *imf = (ImageFormatData *)ptr->data; @@ -834,7 +838,7 @@ static EnumPropertyItem *rna_ImageFormatSettings_color_mode_itemf(bContext *C, P } } -static EnumPropertyItem *rna_ImageFormatSettings_color_depth_itemf(bContext *C, PointerRNA *ptr, +static EnumPropertyItem *rna_ImageFormatSettings_color_depth_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *free) { ImageFormatData *imf = (ImageFormatData *)ptr->data; @@ -1028,7 +1032,8 @@ static void rna_RenderSettings_active_layer_index_set(PointerRNA *ptr, int value rd->actlay = value; } -static void rna_RenderSettings_active_layer_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_RenderSettings_active_layer_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { RenderData *rd = (RenderData *)ptr->data; @@ -1309,7 +1314,7 @@ static void rna_Scene_simplify_update(Main *bmain, Scene *UNUSED(scene), Pointer rna_Scene_use_simplify_update(bmain, sce, ptr); } -static void rna_Scene_use_persistent_data_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Scene_use_persistent_data_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *sce = ptr->id.data; @@ -1458,13 +1463,13 @@ static void rna_UnifiedPaintSettings_unprojected_radius_set(PointerRNA *ptr, flo ups->unprojected_radius = value; } -static void rna_UnifiedPaintSettings_radius_update(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_UnifiedPaintSettings_radius_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { /* changing the unified size should invalidate */ BKE_paint_invalidate_overlay_all(); } -static char *rna_UnifiedPaintSettings_path(PointerRNA *ptr) +static char *rna_UnifiedPaintSettings_path(PointerRNA *UNUSED(ptr)) { return BLI_strdup("tool_settings.unified_paint_settings"); } @@ -1486,7 +1491,7 @@ static void rna_EditMesh_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *U } } -static char *rna_MeshStatVis_path(PointerRNA *ptr) +static char *rna_MeshStatVis_path(PointerRNA *UNUSED(ptr)) { return BLI_strdup("tool_settings.statvis"); } @@ -1520,7 +1525,7 @@ static void rna_SceneSequencer_update(Main *UNUSED(bmain), Scene *UNUSED(scene), BKE_sequencer_preprocessed_cache_cleanup(); } -static char *rna_ToolSettings_path(PointerRNA *ptr) +static char *rna_ToolSettings_path(PointerRNA *UNUSED(ptr)) { return BLI_strdup("tool_settings"); } @@ -1536,7 +1541,8 @@ static void rna_FreestyleLineSet_linestyle_set(PointerRNA *ptr, PointerRNA value { FreestyleLineSet *lineset = (FreestyleLineSet *)ptr->data; - lineset->linestyle->id.us--; + if (lineset->linestyle) + lineset->linestyle->id.us--; lineset->linestyle = (FreestyleLineStyle *)value.data; lineset->linestyle->id.us++; } @@ -1549,7 +1555,7 @@ static PointerRNA rna_FreestyleSettings_active_lineset_get(PointerRNA *ptr) } static void rna_FreestyleSettings_active_lineset_index_range(PointerRNA *ptr, int *min, int *max, - int *softmin, int *softmax) + int *UNUSED(softmin), int *UNUSED(softmax)) { FreestyleConfig *config = (FreestyleConfig *)ptr->data; @@ -2067,8 +2073,8 @@ static void rna_def_statvis(BlenderRNA *brna) {SCE_STATVIS_OVERHANG, "OVERHANG", 0, "Overhang", ""}, {SCE_STATVIS_THICKNESS, "THICKNESS", 0, "Thickness", ""}, {SCE_STATVIS_INTERSECT, "INTERSECT", 0, "Intersect", ""}, - {SCE_STATVIS_DISTORT, "DISTORT", 0, "Distort", ""}, - {SCE_STATVIS_SHARP, "SHARP", 0, "Sharp", ""}, + {SCE_STATVIS_DISTORT, "DISTORT", 0, "Distortion", ""}, + {SCE_STATVIS_SHARP, "SHARP", 0, "Sharp", ""}, {0, NULL, 0, NULL, NULL}}; srna = RNA_def_struct(brna, "MeshStatVis", NULL); @@ -2690,202 +2696,202 @@ static void rna_def_freestyle_settings(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, "rna_FreestyleLineSet_linestyle_get", "rna_FreestyleLineSet_linestyle_set", NULL, NULL); RNA_def_property_ui_text(prop, "Line Style", "Line style settings"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "name"); RNA_def_property_ui_text(prop, "Line Set Name", "Line set name"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); RNA_def_struct_name_property(srna, prop); prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_LINESET_ENABLED); RNA_def_property_ui_text(prop, "Render", "Enable or disable this line set during stroke rendering"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_by_visibility", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_VISIBILITY); RNA_def_property_ui_text(prop, "Selection by Visibility", "Select feature edges based on visibility"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_by_edge_types", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_EDGE_TYPES); RNA_def_property_ui_text(prop, "Selection by Edge Types", "Select feature edges based on edge types"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_by_group", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_GROUP); RNA_def_property_ui_text(prop, "Selection by Group", "Select feature edges based on a group of objects"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_by_image_border", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_IMAGE_BORDER); RNA_def_property_ui_text(prop, "Selection by Image Border", "Select feature edges by image border (less memory consumption)"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_by_face_marks", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_FACE_MARK); RNA_def_property_ui_text(prop, "Selection by Face Marks", "Select feature edges by face marks"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "edge_type_negation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags"); RNA_def_property_enum_items(prop, edge_type_negation_items); RNA_def_property_ui_text(prop, "Edge Type Negation", "Set the negation operation for conditions on feature edge types"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "edge_type_combination", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags"); RNA_def_property_enum_items(prop, edge_type_combination_items); RNA_def_property_ui_text(prop, "Edge Type Combination", "Set the combination operation for conditions on feature edge types"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "group", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "group"); RNA_def_property_struct_type(prop, "Group"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Group", "A group of objects based on which feature edges are selected"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "group_negation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags"); RNA_def_property_enum_items(prop, group_negation_items); RNA_def_property_ui_text(prop, "Group Negation", "Set the negation operation for conditions on feature edge types"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "face_mark_negation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags"); RNA_def_property_enum_items(prop, face_mark_negation_items); RNA_def_property_ui_text(prop, "Face Mark Negation", "Set the negation operation for the condition on face marks"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "face_mark_condition", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags"); RNA_def_property_enum_items(prop, face_mark_condition_items); RNA_def_property_ui_text(prop, "Face Mark Condition", "Set a feature edge selection condition on face marks"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_silhouette", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_SILHOUETTE); RNA_def_property_ui_text(prop, "Silhouette", "Select silhouette edges"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_border", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_BORDER); RNA_def_property_ui_text(prop, "Border", "Select border edges"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_crease", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_CREASE); RNA_def_property_ui_text(prop, "Crease", "Select crease edges"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_ridge_valley", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_RIDGE_VALLEY); RNA_def_property_ui_text(prop, "Ridge & Valley", "Select ridges and valleys"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_suggestive_contour", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_SUGGESTIVE_CONTOUR); RNA_def_property_ui_text(prop, "Suggestive Contour", "Select suggestive contours"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_material_boundary", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_MATERIAL_BOUNDARY); RNA_def_property_ui_text(prop, "Material Boundary", "Select edges at material boundaries"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_contour", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_CONTOUR); RNA_def_property_ui_text(prop, "Contour", "Select contours"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_external_contour", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_EXTERNAL_CONTOUR); RNA_def_property_ui_text(prop, "External Contour", "Select external contours"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "select_edge_mark", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_EDGE_MARK); RNA_def_property_ui_text(prop, "Edge Mark", "Select edge marks"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "exclude_silhouette", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_SILHOUETTE); RNA_def_property_ui_text(prop, "Silhouette", "Exclude silhouette edges"); RNA_def_property_ui_icon(prop, ICON_X, 0); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "exclude_border", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_BORDER); RNA_def_property_ui_text(prop, "Border", "Exclude border edges"); RNA_def_property_ui_icon(prop, ICON_X, 0); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "exclude_crease", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_CREASE); RNA_def_property_ui_text(prop, "Crease", "Exclude crease edges"); RNA_def_property_ui_icon(prop, ICON_X, 0); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "exclude_ridge_valley", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_RIDGE_VALLEY); RNA_def_property_ui_text(prop, "Ridge & Valley", "Exclude ridges and valleys"); RNA_def_property_ui_icon(prop, ICON_X, 0); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "exclude_suggestive_contour", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_SUGGESTIVE_CONTOUR); RNA_def_property_ui_text(prop, "Suggestive Contour", "Exclude suggestive contours"); RNA_def_property_ui_icon(prop, ICON_X, 0); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "exclude_material_boundary", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_MATERIAL_BOUNDARY); RNA_def_property_ui_text(prop, "Material Boundary", "Exclude edges at material boundaries"); RNA_def_property_ui_icon(prop, ICON_X, 0); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "exclude_contour", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_CONTOUR); RNA_def_property_ui_text(prop, "Contour", "Exclude contours"); RNA_def_property_ui_icon(prop, ICON_X, 0); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "exclude_external_contour", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_EXTERNAL_CONTOUR); RNA_def_property_ui_text(prop, "External Contour", "Exclude external contours"); RNA_def_property_ui_icon(prop, ICON_X, 0); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "exclude_edge_mark", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_EDGE_MARK); RNA_def_property_ui_text(prop, "Edge Mark", "Exclude edge marks"); RNA_def_property_ui_icon(prop, ICON_X, 0); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "visibility", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "qi"); RNA_def_property_enum_items(prop, visibility_items); RNA_def_property_ui_text(prop, "Visibility", "Determine how to use visibility for feature edge selection"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "qi_start", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "qi_start"); RNA_def_property_range(prop, 0, INT_MAX); RNA_def_property_ui_text(prop, "Start", "First QI value of the QI range"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "qi_end", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "qi_end"); RNA_def_property_range(prop, 0, INT_MAX); RNA_def_property_ui_text(prop, "End", "Last QI value of the QI range"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); /* FreestyleModuleSettings */ @@ -2897,12 +2903,12 @@ static void rna_def_freestyle_settings(BlenderRNA *brna) RNA_def_property_struct_type(prop, "Text"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Style Module", "Python script to define a style module"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "is_displayed", 1); RNA_def_property_ui_text(prop, "Use", "Enable or disable this style module during stroke rendering"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); /* FreestyleSettings */ @@ -2920,62 +2926,62 @@ static void rna_def_freestyle_settings(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, freestyle_ui_mode_items); RNA_def_property_ui_text(prop, "Control Mode", "Select the Freestyle control mode"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "raycasting_algorithm", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "raycasting_algorithm"); RNA_def_property_enum_items(prop, freestyle_raycasting_algorithm_items); RNA_def_property_ui_text(prop, "Raycasting Algorithm", "Select the Freestyle raycasting algorithm"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_culling", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_CULLING); RNA_def_property_ui_text(prop, "Culling", "If enabled, out-of-view edges are ignored"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_suggestive_contours", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_SUGGESTIVE_CONTOURS_FLAG); RNA_def_property_ui_text(prop, "Suggestive Contours", "Enable suggestive contours"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_ridges_and_valleys", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_RIDGES_AND_VALLEYS_FLAG); RNA_def_property_ui_text(prop, "Ridges and Valleys", "Enable ridges and valleys"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_material_boundaries", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_MATERIAL_BOUNDARIES_FLAG); RNA_def_property_ui_text(prop, "Material Boundaries", "Enable material boundaries"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_smoothness", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_FACE_SMOOTHNESS_FLAG); RNA_def_property_ui_text(prop, "Face Smoothness", "Take face smoothness into account in view map calculation"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_advanced_options", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_ADVANCED_OPTIONS_FLAG); RNA_def_property_ui_text(prop, "Advanced Options", "Enable advanced edge detection options (sphere radius and Kr derivative epsilon)"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "sphere_radius", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "sphere_radius"); RNA_def_property_range(prop, 0.0, 1000.0); RNA_def_property_ui_text(prop, "Sphere Radius", "Sphere radius for computing curvatures"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "kr_derivative_epsilon", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "dkr_epsilon"); RNA_def_property_range(prop, -1000.0, 1000.0); RNA_def_property_ui_text(prop, "Kr Derivative Epsilon", "Kr derivative epsilon for computing suggestive contours"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "crease_angle", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "crease_angle"); RNA_def_property_range(prop, 0.0, DEG2RAD(180.0)); RNA_def_property_ui_text(prop, "Crease Angle", "Angular threshold for detecting crease edges"); - RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "linesets", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "linesets", NULL); @@ -4190,12 +4196,14 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "tile_x", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "tilex"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 8, 65536); RNA_def_property_ui_text(prop, "Tile X", "Horizontal tile size to use while rendering"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "tile_y", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "tiley"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 8, 65536); RNA_def_property_ui_text(prop, "Tile Y", "Vertical tile size to use while rendering"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 375b31e0586..ae6c5e71e6e 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -142,12 +142,12 @@ static void rna_Scene_collada_export( int use_object_instantiation, int sort_by_name, int export_transformation_type, - int second_life) + int open_sim) { collada_export(scene, filepath, apply_modifiers, export_mesh_type, selected, include_children, include_armatures, include_shapekeys, deform_bones_only, active_uv_only, include_uv_textures, include_material_textures, - use_texture_copies, use_ngons, use_object_instantiation, sort_by_name, export_transformation_type, second_life); + use_texture_copies, use_ngons, use_object_instantiation, sort_by_name, export_transformation_type, open_sim); } #endif @@ -218,7 +218,7 @@ void RNA_api_scene(StructRNA *srna) parm = RNA_def_boolean(func, "use_ngons", 1, "Use NGons", "Keep NGons in Export"); parm = RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances", "Instantiate multiple Objects from same Data"); parm = RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name", "Sort exported data by Object name"); - parm = RNA_def_boolean(func, "second_life", 0, "Export for Second Life", "Compatibility mode for Second Life"); + parm = RNA_def_boolean(func, "open_sim", 0, "Export for SL/OpenSim", "Compatibility mode for SL, OpenSim and similar online worlds"); parm = RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX, "Transformation", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX); diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index f9171887bfb..b8269c428a1 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -94,7 +94,7 @@ static void rna_Screen_redraw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), } -static int rna_Screen_is_animation_playing_get(PointerRNA *ptr) +static int rna_Screen_is_animation_playing_get(PointerRNA *UNUSED(ptr)) { return (ED_screen_animation_playing(G.main->wm.first) != NULL); } @@ -213,6 +213,7 @@ static void rna_def_area(BlenderRNA *brna) prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "spacetype"); RNA_def_property_enum_items(prop, space_type_items); + RNA_def_property_enum_default(prop, SPACE_VIEW3D); RNA_def_property_enum_funcs(prop, NULL, "rna_Area_type_set", "rna_Area_type_itemf"); RNA_def_property_ui_text(prop, "Editor Type", "Current editor type for this area"); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 11b3f94a446..89714e49ebf 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -190,7 +190,7 @@ static int rna_ParticleEdit_hair_get(PointerRNA *ptr) return 0; } -static char *rna_ParticleEdit_path(PointerRNA *ptr) +static char *rna_ParticleEdit_path(PointerRNA *UNUSED(ptr)) { return BLI_strdup("tool_settings.particle_edit"); } @@ -247,7 +247,7 @@ static void rna_Sculpt_ShowDiffuseColor_update(Main *UNUSED(bmain), Scene *scene } } -static char *rna_Sculpt_path(PointerRNA *ptr) +static char *rna_Sculpt_path(PointerRNA *UNUSED(ptr)) { return BLI_strdup("tool_settings.sculpt"); } @@ -264,17 +264,17 @@ static char *rna_VertexPaint_path(PointerRNA *ptr) } } -static char *rna_ImagePaintSettings_path(PointerRNA *ptr) +static char *rna_ImagePaintSettings_path(PointerRNA *UNUSED(ptr)) { return BLI_strdup("tool_settings.image_paint"); } -static char *rna_UvSculpt_path(PointerRNA *ptr) +static char *rna_UvSculpt_path(PointerRNA *UNUSED(ptr)) { return BLI_strdup("tool_settings.uv_sculpt"); } -static char *rna_ParticleBrush_path(PointerRNA *ptr) +static char *rna_ParticleBrush_path(PointerRNA *UNUSED(ptr)) { return BLI_strdup("tool_settings.particle_edit.brush"); } diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c index 278dc074c50..71546c7fad4 100644 --- a/source/blender/makesrna/intern/rna_sensor.c +++ b/source/blender/makesrna/intern/rna_sensor.c @@ -43,7 +43,7 @@ #include "WM_types.h" /* Always keep in alphabetical order */ -EnumPropertyItem sensor_type_items[] = { +static EnumPropertyItem sensor_type_items[] = { {SENS_ACTUATOR, "ACTUATOR", 0, "Actuator", ""}, {SENS_ALWAYS, "ALWAYS", 0, "Always", ""}, {SENS_ARMATURE, "ARMATURE", 0, "Armature", ""}, @@ -58,7 +58,6 @@ EnumPropertyItem sensor_type_items[] = { {SENS_RADAR, "RADAR", 0, "Radar", ""}, {SENS_RANDOM, "RANDOM", 0, "Random", ""}, {SENS_RAY, "RAY", 0, "Ray", ""}, - {SENS_TOUCH, "TOUCH", 0, "Touch", ""}, {0, NULL, 0, NULL, NULL} }; @@ -74,8 +73,6 @@ static StructRNA *rna_Sensor_refine(struct PointerRNA *ptr) switch (sensor->type) { case SENS_ALWAYS: return &RNA_AlwaysSensor; - case SENS_TOUCH: - return &RNA_TouchSensor; case SENS_NEAR: return &RNA_NearSensor; case SENS_KEYBOARD: @@ -267,15 +264,6 @@ static void rna_Sensor_Armature_update(Main *UNUSED(bmain), Scene *UNUSED(scene) posechannel[0] = 0; constraint[0] = 0; } - -/* note: the following set functions exists only to avoid id refcounting */ -static void rna_Sensor_touch_material_set(PointerRNA *ptr, PointerRNA value) -{ - bSensor *sens = (bSensor *)ptr->data; - bTouchSensor *ts = (bTouchSensor *) sens->data; - - ts->ma = value.data; -} #else static void rna_def_sensor(BlenderRNA *brna) @@ -427,25 +415,6 @@ static void rna_def_mouse_sensor(BlenderRNA *brna) RNA_def_property_update(prop, NC_LOGIC, NULL); } -static void rna_def_touch_sensor(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "TouchSensor", "Sensor"); - RNA_def_struct_ui_text(srna, "Touch Sensor", "Sensor to detect objects colliding with the current object"); - RNA_def_struct_sdna_from(srna, "bTouchSensor", "data"); - - prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "Material"); - RNA_def_property_pointer_sdna(prop, NULL, "ma"); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)"); - /* note: custom set function is ONLY to avoid rna setting a user for this. */ - RNA_def_property_pointer_funcs(prop, NULL, "rna_Sensor_touch_material_set", NULL, NULL); - RNA_def_property_update(prop, NC_LOGIC, NULL); -} - static void rna_def_keyboard_sensor(BlenderRNA *brna) { StructRNA *srna; @@ -917,7 +886,6 @@ void RNA_def_sensor(BlenderRNA *brna) rna_def_always_sensor(brna); rna_def_near_sensor(brna); rna_def_mouse_sensor(brna); - rna_def_touch_sensor(brna); rna_def_keyboard_sensor(brna); rna_def_property_sensor(brna); rna_def_armature_sensor(brna); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 650453ebc69..342d94c7667 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -93,6 +93,23 @@ static void meta_tmp_ref(Sequence *seq_par, Sequence *seq) } } +static void rna_SequenceElement_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + Scene *scene = (Scene *) ptr->id.data; + Editing *ed = BKE_sequencer_editing_get(scene, FALSE); + + if (ed) { + StripElem *se = (StripElem *)ptr->data; + Sequence *seq; + + /* slow but we can't avoid! */ + seq = BKE_sequencer_from_elem(&ed->seqbase, se); + if (seq) { + BKE_sequence_invalidate_cache(scene, seq); + } + } +} + static void rna_Sequence_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *) ptr->id.data; @@ -703,7 +720,7 @@ static Sequence *sequence_get_by_proxy(Editing *ed, StripProxy *proxy) return data.seq; } -static void rna_Sequence_tcindex_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Sequence_tcindex_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *) ptr->id.data; Editing *ed = BKE_sequencer_editing_get(scene, FALSE); @@ -1063,7 +1080,7 @@ static void rna_def_strip_element(BlenderRNA *brna) prop = RNA_def_property(srna, "filename", PROP_STRING, PROP_FILENAME); RNA_def_property_string_sdna(prop, NULL, "name"); RNA_def_property_ui_text(prop, "Filename", ""); - RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceElement_update"); prop = RNA_def_property(srna, "orig_width", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "orig_width"); @@ -1281,7 +1298,7 @@ static void rna_def_strip_color_balance(BlenderRNA *brna) RNA_def_struct_sdna(srna, "StripColorBalance"); } -EnumPropertyItem blend_mode_items[] = { +static EnumPropertyItem blend_mode_items[] = { {SEQ_BLEND_REPLACE, "REPLACE", 0, "Replace", ""}, {SEQ_TYPE_CROSS, "CROSS", 0, "Cross", ""}, {SEQ_TYPE_ADD, "ADD", 0, "Add", ""}, diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index 8b01a785f1e..ba90e3b1e4a 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -65,7 +65,7 @@ static void rna_Smoke_dependency_update(Main *bmain, Scene *scene, PointerRNA *p DAG_relations_tag_update(bmain); } -static void rna_Smoke_resetCache(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_Smoke_resetCache(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data; if (settings->smd && settings->smd->domain) diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index f7a0d865274..d494d6ae1cb 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -109,13 +109,15 @@ static EnumPropertyItem transform_orientation_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem autosnap_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem autosnap_items[] = { {SACTSNAP_OFF, "NONE", 0, "No Auto-Snap", ""}, {SACTSNAP_STEP, "STEP", 0, "Time Step", "Snap to 1.0 frame/second intervals"}, {SACTSNAP_FRAME, "FRAME", 0, "Nearest Frame", "Snap to actual frames/seconds (nla-action time)"}, {SACTSNAP_MARKER, "MARKER", 0, "Nearest Marker", "Snap to nearest marker"}, {0, NULL, 0, NULL, NULL} }; +#endif EnumPropertyItem viewport_shade_items[] = { {OB_BOUNDBOX, "BOUNDBOX", ICON_BBOX, "Bounding Box", "Display the object's local bounding boxes only"}, @@ -172,6 +174,7 @@ static EnumPropertyItem buttons_texture_context_items[] = { #include "DNA_mask_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_userdef_types.h" #include "BLI_math.h" @@ -197,6 +200,9 @@ static EnumPropertyItem buttons_texture_context_items[] = { #include "IMB_imbuf_types.h" +#include "UI_interface.h" +#include "UI_view2d.h" + static StructRNA *rna_Space_refine(struct PointerRNA *ptr) { SpaceLink *space = (SpaceLink *)ptr->data; @@ -400,23 +406,12 @@ static void rna_SpaceView3D_layer_update(Main *bmain, Scene *UNUSED(scene), Poin DAG_on_visible_update(bmain, FALSE); } -static void rna_SpaceView3D_viewport_shade_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_SpaceView3D_viewport_shade_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { View3D *v3d = (View3D *)(ptr->data); ScrArea *sa = rna_area_from_space(ptr); - if (v3d->drawtype != OB_RENDER) { - ARegion *ar; - - for (ar = sa->regionbase.first; ar; ar = ar->next) { - RegionView3D *rv3d = ar->regiondata; - - if (rv3d && rv3d->render_engine) { - RE_engine_free(rv3d->render_engine); - rv3d->render_engine = NULL; - } - } - } + ED_view3d_shade_update(bmain, v3d, sa); } static void rna_SpaceView3D_matcap_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) @@ -622,7 +617,7 @@ static PointerRNA rna_SpaceImageEditor_uvedit_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_SpaceUVEditor, ptr->data); } -static void rna_SpaceImageEditor_mode_update(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_SpaceImageEditor_mode_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) { ED_space_image_paint_update(bmain->wm.first, scene->toolsettings); } @@ -850,8 +845,8 @@ static void rna_SpaceProperties_context_set(PointerRNA *ptr, int value) sbuts->mainbuser = value; } -static EnumPropertyItem *rna_SpaceProperties_context_itemf(bContext *C, PointerRNA *ptr, - PropertyRNA *UNUSED(prop), int *free) +static EnumPropertyItem *rna_SpaceProperties_context_itemf(bContext *UNUSED(C), PointerRNA *ptr, + PropertyRNA *UNUSED(prop), int *free) { SpaceButs *sbuts = (SpaceButs *)(ptr->data); EnumPropertyItem *item = NULL; @@ -959,6 +954,14 @@ static EnumPropertyItem *rna_SpaceProperties_texture_context_itemf(bContext *C, return item; } +static void rna_SpaceProperties_texture_context_set(PointerRNA *ptr, int value) +{ + SpaceButs *sbuts = (SpaceButs *)(ptr->data); + + /* User action, no need to keep "better" value in prev here! */ + sbuts->texture_context = sbuts->texture_context_prev = value; +} + /* Space Console */ static void rna_ConsoleLine_body_get(PointerRNA *ptr, char *value) { @@ -989,7 +992,8 @@ static void rna_ConsoleLine_body_set(PointerRNA *ptr, const char *value) ci->cursor = len; } -static void rna_ConsoleLine_cursor_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_ConsoleLine_cursor_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { ConsoleLine *ci = (ConsoleLine *)ptr->data; @@ -1255,6 +1259,15 @@ static void rna_SpaceNodeEditor_show_backdrop_update(Main *UNUSED(bmain), Scene WM_main_add_notifier(NC_SCENE | ND_NODES, NULL); } +static void rna_SpaceNodeEditor_cursor_location_from_region(SpaceNode *snode, bContext *C, int x, int y) +{ + ARegion *ar = CTX_wm_region(C); + + UI_view2d_region_to_view(&ar->v2d, x, y, &snode->cursor[0], &snode->cursor[1]); + snode->cursor[0] /= UI_DPI_FAC; + snode->cursor[1] /= UI_DPI_FAC; +} + static void rna_SpaceClipEditor_clip_set(PointerRNA *ptr, PointerRNA value) { SpaceClip *sc = (SpaceClip *)(ptr->data); @@ -2194,7 +2207,8 @@ static void rna_def_space_buttons(BlenderRNA *brna) prop = RNA_def_property(srna, "texture_context", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, buttons_texture_context_items); - RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceProperties_texture_context_itemf"); + RNA_def_property_enum_funcs(prop, NULL, "rna_SpaceProperties_texture_context_set", + "rna_SpaceProperties_texture_context_itemf"); RNA_def_property_ui_text(prop, "Texture Context", "Type of texture data to display and edit"); RNA_def_property_update(prop, NC_TEXTURE, NULL); @@ -2573,6 +2587,16 @@ static void rna_def_space_text(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Margin Column", "Column number to show right margin at"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL); + prop = RNA_def_property(srna, "top", PROP_INT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_int_sdna(prop, NULL, "top"); + RNA_def_property_ui_text(prop, "Top Line", "Top line visible"); + + prop = RNA_def_property(srna, "visible_lines", PROP_INT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_int_sdna(prop, NULL, "viewlines"); + RNA_def_property_ui_text(prop, "Top Line", "Amount of lines that can be visible in current editor"); + /* functionality options */ prop = RNA_def_property(srna, "use_overwrite", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overwrite", 1); @@ -3292,7 +3316,8 @@ static void rna_def_space_node_path_api(BlenderRNA *brna, PropertyRNA *cprop) static void rna_def_space_node(BlenderRNA *brna) { StructRNA *srna; - PropertyRNA *prop; + PropertyRNA *prop, *parm; + FunctionRNA *func; static EnumPropertyItem texture_type_items[] = { {SNODE_TEX_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Edit texture nodes from Object"}, @@ -3433,6 +3458,14 @@ static void rna_def_space_node(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "cursor"); RNA_def_property_ui_text(prop, "Cursor Location", "Location for adding new nodes"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL); + + func = RNA_def_function(srna, "cursor_location_from_region", "rna_SpaceNodeEditor_cursor_location_from_region"); + RNA_def_function_ui_description(func, "Set the cursor location using region coordinates"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "x", "Region x coordinate", -10000, 10000); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "y", "Region y coordinate", -10000, 10000); + RNA_def_property_flag(parm, PROP_REQUIRED); } static void rna_def_space_logic(BlenderRNA *brna) @@ -3525,6 +3558,7 @@ static void rna_def_space_clip(BlenderRNA *brna) static EnumPropertyItem pivot_items[] = { {V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", "Pivot around bounding box center of selected object(s)"}, + {V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", "Pivot around the 2D cursor"}, {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, "Individual Origins", "Pivot around each object's own origin"}, {V3D_CENTROID, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point", diff --git a/source/blender/makesrna/intern/rna_test.c b/source/blender/makesrna/intern/rna_test.c index 22b6f323647..cf0dc5e332d 100644 --- a/source/blender/makesrna/intern/rna_test.c +++ b/source/blender/makesrna/intern/rna_test.c @@ -34,6 +34,8 @@ #include "rna_internal.h" +#ifdef RNA_RUNTIME + #define ARRAY_SIZE 3 #define DYNAMIC_ARRAY_SIZE 64 #define MARRAY_DIM [3][4][5] @@ -43,8 +45,6 @@ #define DYNAMIC_MARRAY_DIM [3][4][5] #define DYNAMIC_MARRAY_SIZE(type) (sizeof(type DYNAMIC_MARRAY_DIM) / sizeof(type)) -#ifdef RNA_RUNTIME - #ifdef UNIT_TEST #define DEF_VARS(type, prefix) \ @@ -185,7 +185,8 @@ void RNA_def_test(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_DYNAMIC); RNA_def_property_dynamic_array_funcs(prop, "rna_Test_bdmarr_get_length", "rna_Test_bdmarr_set_length"); RNA_def_property_boolean_funcs(prop, "rna_Test_bdmarr_get", "rna_Test_bdmarr_set"); - +#else + (void)brna; #endif } diff --git a/source/blender/makesrna/intern/rna_text.c b/source/blender/makesrna/intern/rna_text.c index df6181af4b2..24695928679 100644 --- a/source/blender/makesrna/intern/rna_text.c +++ b/source/blender/makesrna/intern/rna_text.c @@ -81,6 +81,12 @@ static int rna_Text_modified_get(PointerRNA *ptr) return text_file_modified(text); } +static int rna_Text_current_line_index_get(PointerRNA *ptr) +{ + Text *text = (Text *)ptr->data; + return BLI_findindex(&text->lines, text->curl); +} + static void rna_TextLine_body_get(PointerRNA *ptr, char *value) { TextLine *line = (TextLine *)ptr->data; @@ -141,6 +147,11 @@ static void rna_def_text(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Text", "Text datablock referencing an external or packed text file"); RNA_def_struct_ui_icon(srna, ICON_TEXT); RNA_def_struct_clear_flag(srna, STRUCT_ID_REFCOUNT); + + prop = RNA_def_property(srna, "current_line_index", PROP_INT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_int_funcs(prop, "rna_Text_current_line_index_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Current Line Index", "Index of current TextLine in TextLine collection"); prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_NONE); RNA_def_property_string_funcs(prop, "rna_Text_filename_get", "rna_Text_filename_length", "rna_Text_filename_set"); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index be6defa11d7..a26272b34ce 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -51,13 +51,15 @@ #include "WM_api.h" #include "WM_types.h" -EnumPropertyItem texture_filter_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem texture_filter_items[] = { {TXF_BOX, "BOX", 0, "Box", ""}, {TXF_EWA, "EWA", 0, "EWA", ""}, {TXF_FELINE, "FELINE", 0, "FELINE", ""}, {TXF_AREA, "AREA", 0, "Area", ""}, {0, NULL, 0, NULL, NULL} }; +#endif EnumPropertyItem texture_type_items[] = { {0, "NONE", 0, "None", ""}, @@ -82,7 +84,8 @@ EnumPropertyItem texture_type_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem blend_type_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem blend_type_items[] = { {MTEX_BLEND, "MIX", 0, "Mix", ""}, {MTEX_ADD, "ADD", 0, "Add", ""}, {MTEX_SUB, "SUBTRACT", 0, "Subtract", ""}, @@ -101,6 +104,7 @@ EnumPropertyItem blend_type_items[] = { {MTEX_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""}, {0, NULL, 0, NULL, NULL} }; +#endif #ifdef RNA_RUNTIME @@ -180,7 +184,7 @@ static void rna_Texture_mapping_update(Main *bmain, Scene *scene, PointerRNA *pt rna_Texture_update(bmain, scene, ptr); } -static void rna_Color_mapping_update(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_Color_mapping_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { /* nothing to do */ } @@ -362,7 +366,7 @@ static int rna_TextureSlot_output_node_get(PointerRNA *ptr) } -static EnumPropertyItem *rna_TextureSlot_output_node_itemf(bContext *C, PointerRNA *ptr, +static EnumPropertyItem *rna_TextureSlot_output_node_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), int *free) { MTex *mtex = ptr->data; @@ -474,7 +478,7 @@ static char *rna_VoxelData_path(PointerRNA *UNUSED(ptr)) return BLI_sprintfN("voxel_data"); } -static char *rna_OceanTex_path(PointerRNA *ptr) +static char *rna_OceanTex_path(PointerRNA *UNUSED(ptr)) { return BLI_sprintfN("ocean"); } @@ -491,6 +495,14 @@ static void rna_def_texmapping(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_vect_type_items[] = { + {TEXMAP_TYPE_TEXTURE, "TEXTURE", 0, "Texture", "Transform a texture by inverse mapping the texture coordinate"}, + {TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transform a point"}, + {TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"}, + {TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem prop_xyz_mapping_items[] = { {0, "NONE", 0, "None", ""}, {1, "X", 0, "X", ""}, @@ -505,6 +517,12 @@ static void rna_def_texmapping(BlenderRNA *brna) srna = RNA_def_struct(brna, "TexMapping", NULL); RNA_def_struct_ui_text(srna, "Texture Mapping", "Texture coordinate mapping settings"); + prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, prop_vect_type_items); + RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms"); + RNA_def_property_update(prop, 0, "rna_Texture_mapping_update"); + prop = RNA_def_property(srna, "translation", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_float_sdna(prop, NULL, "loc"); RNA_def_property_ui_text(prop, "Location", ""); diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index 4c47bbf93a6..2b3cf58d452 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -95,6 +95,13 @@ static void rna_trackingTracks_begin(CollectionPropertyIterator *iter, PointerRN rna_iterator_listbase_begin(iter, &clip->tracking.tracks, NULL); } +static void rna_trackingPlaneTracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + MovieClip *clip = (MovieClip *)ptr->id.data; + + rna_iterator_listbase_begin(iter, &clip->tracking.plane_tracks, NULL); +} + static void rna_trackingObjects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { MovieClip *clip = (MovieClip *)ptr->id.data; @@ -117,7 +124,8 @@ static void rna_tracking_active_object_index_set(PointerRNA *ptr, int value) BKE_tracking_dopesheet_tag_update(&clip->tracking); } -static void rna_tracking_active_object_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_tracking_active_object_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { MovieClip *clip = (MovieClip *)ptr->id.data; @@ -146,6 +154,27 @@ static void rna_tracking_active_track_set(PointerRNA *ptr, PointerRNA value) clip->tracking.act_track = NULL; } +static PointerRNA rna_tracking_active_plane_track_get(PointerRNA *ptr) +{ + MovieClip *clip = (MovieClip *)ptr->id.data; + MovieTrackingPlaneTrack *act_plane_track = BKE_tracking_plane_track_get_active(&clip->tracking); + + return rna_pointer_inherit_refine(ptr, &RNA_MovieTrackingPlaneTrack, act_plane_track); +} + +static void rna_tracking_active_plane_track_set(PointerRNA *ptr, PointerRNA value) +{ + MovieClip *clip = (MovieClip *)ptr->id.data; + MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *) value.data; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); + int index = BLI_findindex(plane_tracks_base, plane_track); + + if (index >= 0) + clip->tracking.act_plane_track = plane_track; + else + clip->tracking.act_plane_track = NULL; +} + static void rna_trackingTrack_name_set(PointerRNA *ptr, const char *value) { MovieClip *clip = (MovieClip *)ptr->id.data; @@ -197,6 +226,81 @@ static void rna_trackingTrack_select_set(PointerRNA *ptr, int value) } } +static void rna_trackingPlaneMarker_frame_set(PointerRNA *ptr, int value) +{ + MovieClip *clip = (MovieClip *) ptr->id.data; + MovieTracking *tracking = &clip->tracking; + MovieTrackingPlaneMarker *plane_marker = (MovieTrackingPlaneMarker *) ptr->data; + MovieTrackingObject *tracking_object; + bool found = false; + MovieTrackingPlaneTrack *plane_track = NULL; + + for (tracking_object = tracking->objects.first; + tracking_object; + tracking_object = tracking_object->next) + { + ListBase *tracksbase = BKE_tracking_object_get_plane_tracks(tracking, tracking_object); + + for (plane_track = tracksbase->first; + plane_track; + plane_track = plane_track->next) + { + if (plane_marker >= plane_track->markers && plane_marker < plane_track->markers + plane_track->markersnr) { + found = true; + break; + } + } + + if (found) { + break; + } + } + + if (found) { + MovieTrackingPlaneMarker new_plane_marker = *plane_marker; + new_plane_marker.framenr = value; + + BKE_tracking_plane_marker_delete(plane_track, plane_marker->framenr); + BKE_tracking_plane_marker_insert(plane_track, &new_plane_marker); + } +} + +static char *rna_trackingPlaneTrack_path(PointerRNA *ptr) +{ + MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data; + char name_esc[sizeof(plane_track->name) * 2]; + BLI_strescape(name_esc, plane_track->name, sizeof(name_esc)); + return BLI_sprintfN("tracking.plane_tracks[\"%s\"]", name_esc); +} + +static void rna_trackingPlaneTrack_name_set(PointerRNA *ptr, const char *value) +{ + MovieClip *clip = (MovieClip *)ptr->id.data; + MovieTracking *tracking = &clip->tracking; + MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data; + ListBase *plane_tracks_base = &tracking->plane_tracks; + + BLI_strncpy(plane_track->name, value, sizeof(plane_track->name)); + + /* TODO: it's a bit difficult to find list track came from knowing just + * movie clip ID and MovieTracking structure, so keep this naive + * search for a while */ + if (BLI_findindex(plane_tracks_base, plane_track) < 0) { + MovieTrackingObject *object = tracking->objects.first; + + while (object) { + if (BLI_findindex(&object->plane_tracks, plane_track)) { + plane_tracks_base = &object->plane_tracks; + break; + } + + object = object->next; + } + } + + BKE_tracking_plane_track_unique_name(plane_tracks_base, plane_track); +} + static char *rna_trackingCamera_path(PointerRNA *UNUSED(ptr)) { return BLI_sprintfN("tracking.camera"); @@ -259,7 +363,8 @@ static void rna_tracking_stabTracks_active_index_set(PointerRNA *ptr, int value) clip->tracking.stabilization.act_track = value; } -static void rna_tracking_stabTracks_active_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +static void rna_tracking_stabTracks_active_index_range(PointerRNA *ptr, int *min, int *max, + int *UNUSED(softmin), int *UNUSED(softmax)) { MovieClip *clip = (MovieClip *)ptr->id.data; @@ -294,6 +399,20 @@ static void rna_trackingObject_tracks_begin(CollectionPropertyIterator *iter, Po } } +static void rna_trackingObject_plane_tracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + MovieTrackingObject *object = (MovieTrackingObject *)ptr->data; + + if (object->flag & TRACKING_OBJECT_CAMERA) { + MovieClip *clip = (MovieClip *)ptr->id.data; + + rna_iterator_listbase_begin(iter, &clip->tracking.plane_tracks, NULL); + } + else { + rna_iterator_listbase_begin(iter, &object->plane_tracks, NULL); + } +} + static PointerRNA rna_trackingObject_reconstruction_get(PointerRNA *ptr) { MovieTrackingObject *object = (MovieTrackingObject *)ptr->data; @@ -348,19 +467,33 @@ static void rna_trackingMarker_frame_set(PointerRNA *ptr, int value) { MovieClip *clip = (MovieClip *) ptr->id.data; MovieTracking *tracking = &clip->tracking; - MovieTrackingTrack *track; MovieTrackingMarker *marker = (MovieTrackingMarker *) ptr->data; + MovieTrackingObject *tracking_object; + bool found = false; + MovieTrackingTrack *track = NULL; + + for (tracking_object = tracking->objects.first; + tracking_object; + tracking_object = tracking_object->next) + { + ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object); + + for (track = tracksbase->first; + track; + track = track->next) + { + if (marker >= track->markers && marker < track->markers + track->markersnr) { + found = true; + break; + } + } - track = tracking->tracks.first; - while (track) { - if (marker >= track->markers && marker < track->markers + track->markersnr) { + if (found) { break; } - - track = track->next; } - if (track) { + if (found) { MovieTrackingMarker new_marker = *marker; new_marker.framenr = value; @@ -394,7 +527,7 @@ static void rna_tracking_markerPattern_boundbox_get(PointerRNA *ptr, float *valu copy_v2_v2(values + 2, max); } -static void rna_trackingDopesheet_tagUpdate(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) +static void rna_trackingDopesheet_tagUpdate(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { MovieClip *clip = (MovieClip *)ptr->id.data; MovieTrackingDopesheet *dopesheet = &clip->tracking.dopesheet; @@ -404,7 +537,8 @@ static void rna_trackingDopesheet_tagUpdate(Main *UNUSED(bmain), Scene *scene, P /* API */ -static MovieTrackingTrack *add_track_to_base(MovieClip *clip, MovieTracking *tracking, ListBase *tracksbase, const char *name, int frame) +static MovieTrackingTrack *add_track_to_base(MovieClip *clip, MovieTracking *tracking, ListBase *tracksbase, + const char *name, int frame) { int width, height; MovieClipUser user = {0}; @@ -515,6 +649,44 @@ static void rna_trackingMarkers_delete_frame(MovieTrackingTrack *track, int fram WM_main_add_notifier(NC_MOVIECLIP | NA_EDITED, NULL); } +static MovieTrackingPlaneMarker *rna_trackingPlaneMarkers_find_frame(MovieTrackingPlaneTrack *plane_track, int framenr, int exact) +{ + if (exact) + return BKE_tracking_plane_marker_get_exact(plane_track, framenr); + else + return BKE_tracking_plane_marker_get(plane_track, framenr); +} + +static MovieTrackingPlaneMarker *rna_trackingPlaneMarkers_insert_frame(MovieTrackingPlaneTrack *plane_track, int framenr) +{ + MovieTrackingPlaneMarker plane_marker, *new_plane_marker; + + memset(&plane_marker, 0, sizeof(plane_marker)); + plane_marker.framenr = framenr; + + /* a bit arbitrary, but better than creating zero markers */ + copy_v2_v2(plane_marker.corners[0], plane_track->markers[0].corners[0]); + copy_v2_v2(plane_marker.corners[1], plane_track->markers[0].corners[1]); + copy_v2_v2(plane_marker.corners[2], plane_track->markers[0].corners[2]); + copy_v2_v2(plane_marker.corners[3], plane_track->markers[0].corners[3]); + + new_plane_marker = BKE_tracking_plane_marker_insert(plane_track, &plane_marker); + + WM_main_add_notifier(NC_MOVIECLIP | NA_EDITED, NULL); + + return new_plane_marker; +} + +static void rna_trackingPlaneMarkers_delete_frame(MovieTrackingPlaneTrack *plane_track, int framenr) +{ + if (plane_track->markersnr == 1) + return; + + BKE_tracking_plane_marker_delete(plane_track, framenr); + + WM_main_add_notifier(NC_MOVIECLIP | NA_EDITED, NULL); +} + #else static EnumPropertyItem tracker_motion_model[] = { @@ -891,7 +1063,7 @@ static void rna_def_trackingMarker(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "framenr"); RNA_def_property_ui_text(prop, "Frame", "Frame number marker is keyframed on"); RNA_def_property_int_funcs(prop, NULL, "rna_trackingMarker_frame_set", NULL); - RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, 0); + RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL); /* enable */ prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE); @@ -960,11 +1132,11 @@ static void rna_def_trackingMarkers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_return(func, parm); func = RNA_def_function(srna, "insert_frame", "rna_trackingMarkers_insert_frame"); - RNA_def_function_ui_description(func, "Add a number of tracks to this movie clip"); + RNA_def_function_ui_description(func, "Insert a new marker at the specified frame"); parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to insert marker to", MINFRAME, MAXFRAME); RNA_def_property_flag(parm, PROP_REQUIRED); - RNA_def_float_vector(func, "co", 2, 0, -1.0, 1.0, "Coordinate", + RNA_def_float_vector(func, "co", 2, NULL, -1.0, 1.0, "Coordinate", "Place new marker at the given frame using specified in normalized space coordinates", -1.0, 1.0); RNA_def_property_flag(parm, PROP_REQUIRED); @@ -1188,6 +1360,116 @@ static void rna_def_trackingTrack(BlenderRNA *brna) RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL); } +static void rna_def_trackingPlaneMarker(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "MovieTrackingPlaneMarker", NULL); + RNA_def_struct_ui_text(srna, "Movie Tracking Plane Marker Data", "Match-moving plane marker data for tracking"); + + /* frame */ + prop = RNA_def_property(srna, "frame", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "framenr"); + RNA_def_property_ui_text(prop, "Frame", "Frame number marker is keyframed on"); + RNA_def_property_int_funcs(prop, NULL, "rna_trackingPlaneMarker_frame_set", NULL); + RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL); + + /* Corners */ + prop = RNA_def_property(srna, "corners", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "corners"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x2); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); + RNA_def_property_ui_text(prop, "Corners", + "Array of coordinates which represents UI rectangle corners in " + "frame normalized coordinates"); + RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL); + + /* enable */ + prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", PLANE_MARKER_DISABLED); + RNA_def_property_ui_text(prop, "Mode", "Is marker muted for current frame"); + RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL); +} + +static void rna_def_trackingPlaneMarkers(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "MovieTrackingPlaneMarkers"); + srna = RNA_def_struct(brna, "MovieTrackingPlaneMarkers", NULL); + RNA_def_struct_sdna(srna, "MovieTrackingPlaneTrack"); + RNA_def_struct_ui_text(srna, "Movie Tracking Plane Markers", + "Collection of markers for movie tracking plane track"); + + func = RNA_def_function(srna, "find_frame", "rna_trackingPlaneMarkers_find_frame"); + RNA_def_function_ui_description(func, "Get plane marker for specified frame"); + parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", + "Frame number to find marker for", MINFRAME, MAXFRAME); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_boolean(func, "exact", TRUE, "Exact", + "Get plane marker at exact frame number rather than get estimated marker"); + parm = RNA_def_pointer(func, "plane_marker", "MovieTrackingPlaneMarker", "", "Plane marker for specified frame"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "insert_frame", "rna_trackingPlaneMarkers_insert_frame"); + RNA_def_function_ui_description(func, "Insert a new plane marker at the specified frame"); + parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", + "Frame number to insert marker to", MINFRAME, MAXFRAME); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_pointer(func, "plane_marker", "MovieTrackingPlaneMarker", "", "Newly created plane marker"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "delete_frame", "rna_trackingPlaneMarkers_delete_frame"); + RNA_def_function_ui_description(func, "Delete plane marker at specified frame"); + parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", + "Frame number to delete plane marker from", MINFRAME, MAXFRAME); + RNA_def_property_flag(parm, PROP_REQUIRED); +} + +static void rna_def_trackingPlaneTrack(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + rna_def_trackingPlaneMarker(brna); + + srna = RNA_def_struct(brna, "MovieTrackingPlaneTrack", NULL); + RNA_def_struct_path_func(srna, "rna_trackingPlaneTrack_path"); + RNA_def_struct_ui_text(srna, "Movie tracking plane track data", "Match-moving plane track data for tracking"); + RNA_def_struct_ui_icon(srna, ICON_ANIM_DATA); + + /* name */ + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text(prop, "Name", "Unique name of track"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_trackingPlaneTrack_name_set"); + RNA_def_property_string_maxlength(prop, MAX_ID_NAME - 2); + RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL); + RNA_def_struct_name_property(srna, prop); + + /* markers */ + prop = RNA_def_property(srna, "markers", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "MovieTrackingPlaneMarker"); + RNA_def_property_collection_sdna(prop, NULL, "markers", "markersnr"); + RNA_def_property_ui_text(prop, "Markers", "Collection of markers in track"); + rna_def_trackingPlaneMarkers(brna, prop); + + /* select */ + prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SELECT); + RNA_def_property_ui_text(prop, "Select", "Plane track is selected"); + RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL); + + /* auto keyframing */ + prop = RNA_def_property(srna, "use_auto_keying", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", PLANE_TRACK_AUTOKEY); + RNA_def_property_ui_text(prop, "Auto Keyframe", "Automatic keyframe insertion when moving plane corners"); + RNA_def_property_ui_icon(prop, ICON_REC, 0); +} + static void rna_def_trackingStabilization(BlenderRNA *brna) { StructRNA *srna; @@ -1373,6 +1655,26 @@ static void rna_def_trackingTracks(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Active Track", "Active track in this tracking data object"); } +static void rna_def_trackingPlaneTracks(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "MovieTrackingPlaneTracks", NULL); + RNA_def_struct_sdna(srna, "MovieTracking"); + RNA_def_struct_ui_text(srna, "Movie Plane Tracks", "Collection of movie tracking plane tracks"); + + /* TODO(sergey): Add API to create new plane tracks */ + + /* active plane track */ + prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "MovieTrackingPlaneTrack"); + RNA_def_property_pointer_funcs(prop, "rna_tracking_active_plane_track_get", "rna_tracking_active_plane_track_set", + NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); + RNA_def_property_ui_text(prop, "Active Plane Track", "Active plane track in this tracking data object"); +} + static void rna_def_trackingObjectTracks(BlenderRNA *brna) { StructRNA *srna; @@ -1400,6 +1702,24 @@ static void rna_def_trackingObjectTracks(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Active Track", "Active track in this tracking data object"); } +static void rna_def_trackingObjectPlaneTracks(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "MovieTrackingObjectPlaneTracks", NULL); + RNA_def_struct_sdna(srna, "MovieTrackingObject"); + RNA_def_struct_ui_text(srna, "Plane Tracks", "Collection of tracking plane tracks"); + + /* active track */ + prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "MovieTrackingTrack"); + RNA_def_property_pointer_funcs(prop, "rna_tracking_active_plane_track_get", "rna_tracking_active_plane_track_set", + NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); + RNA_def_property_ui_text(prop, "Active Track", "Active track in this tracking data object"); +} + static void rna_def_trackingObject(BlenderRNA *brna) { StructRNA *srna; @@ -1432,6 +1752,15 @@ static void rna_def_trackingObject(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Tracks", "Collection of tracks in this tracking data object"); RNA_def_property_srna(prop, "MovieTrackingObjectTracks"); + /* plane tracks */ + prop = RNA_def_property(srna, "plane_tracks", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_funcs(prop, "rna_trackingObject_plane_tracks_begin", "rna_iterator_listbase_next", + "rna_iterator_listbase_end", "rna_iterator_listbase_get", + NULL, NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "MovieTrackingPlaneTrack"); + RNA_def_property_ui_text(prop, "Plane Tracks", "Collection of plane tracks in this tracking data object"); + RNA_def_property_srna(prop, "MovieTrackingObjectPlaneTracks"); + /* reconstruction */ prop = RNA_def_property(srna, "reconstruction", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "MovieTrackingReconstruction"); @@ -1549,8 +1878,11 @@ static void rna_def_tracking(BlenderRNA *brna) rna_def_trackingSettings(brna); rna_def_trackingCamera(brna); rna_def_trackingTrack(brna); + rna_def_trackingPlaneTrack(brna); rna_def_trackingTracks(brna); + rna_def_trackingPlaneTracks(brna); rna_def_trackingObjectTracks(brna); + rna_def_trackingObjectPlaneTracks(brna); rna_def_trackingStabilization(brna); rna_def_trackingReconstruction(brna); rna_def_trackingObject(brna); @@ -1577,6 +1909,15 @@ static void rna_def_tracking(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Tracks", "Collection of tracks in this tracking data object"); RNA_def_property_srna(prop, "MovieTrackingTracks"); + /* tracks */ + prop = RNA_def_property(srna, "plane_tracks", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_funcs(prop, "rna_trackingPlaneTracks_begin", "rna_iterator_listbase_next", + "rna_iterator_listbase_end", "rna_iterator_listbase_get", + NULL, NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "MovieTrackingPlaneTrack"); + RNA_def_property_ui_text(prop, "Plane Tracks", "Collection of plane tracks in this tracking data object"); + RNA_def_property_srna(prop, "MovieTrackingPlaneTracks"); + /* stabilization */ prop = RNA_def_property(srna, "stabilization", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "MovieTrackingStabilization"); diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 9efe3d9f1d6..39f305f7d47 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -31,6 +31,8 @@ #include "BLF_translation.h" +#include "BKE_idprop.h" + #include "RNA_define.h" #include "rna_internal.h" @@ -58,12 +60,9 @@ EnumPropertyItem operator_context_items[] = { }; EnumPropertyItem uilist_layout_type_items[] = { - {UILST_LAYOUT_DEFAULT, "DEFAULT", 0, "Default Layout", - "Use the default, multi-rows layout"}, - {UILST_LAYOUT_COMPACT, "COMPACT", 0, "Compact Layout", - "Use the compact, single-row layout"}, - {UILST_LAYOUT_GRID, "GRID", 0, "Grid Layout", - "Use the grid-based layout"}, + {UILST_LAYOUT_DEFAULT, "DEFAULT", 0, "Default Layout", "Use the default, multi-rows layout"}, + {UILST_LAYOUT_COMPACT, "COMPACT", 0, "Compact Layout", "Use the compact, single-row layout"}, + {UILST_LAYOUT_GRID, "GRID", 0, "Grid Layout", "Use the grid-based layout"}, {0, NULL, 0, NULL, NULL} }; @@ -167,7 +166,7 @@ static void panel_draw_header(const bContext *C, Panel *pnl) RNA_parameter_list_free(&list); } -static void rna_Panel_unregister(Main *bmain, StructRNA *type) +static void rna_Panel_unregister(Main *UNUSED(bmain), StructRNA *type) { ARegionType *art; PanelType *pt = RNA_struct_blender_type_get(type); @@ -269,8 +268,24 @@ static StructRNA *rna_Panel_refine(PointerRNA *ptr) } /* UIList */ +static unsigned int rna_UIList_filter_const_FILTER_ITEM_get(PointerRNA *UNUSED(ptr)) +{ + return UILST_FLT_ITEM; +} + +static IDProperty *rna_UIList_idprops(PointerRNA *ptr, bool create) +{ + uiList *ui_list = (uiList *)ptr->data; + if (create && !ui_list->properties) { + IDPropertyTemplate val = {0}; + ui_list->properties = IDP_New(IDP_GROUP, &val, "RNA_UIList IDproperties group"); + } + + return ui_list->properties; +} + static void uilist_draw_item(uiList *ui_list, bContext *C, uiLayout *layout, PointerRNA *dataptr, PointerRNA *itemptr, - int icon, PointerRNA *active_dataptr, const char *active_propname, int index) + int icon, PointerRNA *active_dataptr, const char *active_propname, int index, int flt_flag) { extern FunctionRNA rna_UIList_draw_item_func; @@ -290,11 +305,139 @@ static void uilist_draw_item(uiList *ui_list, bContext *C, uiLayout *layout, Poi RNA_parameter_set_lookup(&list, "active_data", active_dataptr); RNA_parameter_set_lookup(&list, "active_property", &active_propname); RNA_parameter_set_lookup(&list, "index", &index); + RNA_parameter_set_lookup(&list, "flt_flag", &flt_flag); + ui_list->type->ext.call((bContext *)C, &ul_ptr, func, &list); + + RNA_parameter_list_free(&list); +} + +static void uilist_draw_filter(uiList *ui_list, bContext *C, uiLayout *layout) +{ + extern FunctionRNA rna_UIList_draw_filter_func; + + PointerRNA ul_ptr; + ParameterList list; + FunctionRNA *func; + + RNA_pointer_create(&CTX_wm_screen(C)->id, ui_list->type->ext.srna, ui_list, &ul_ptr); + func = &rna_UIList_draw_filter_func; /* RNA_struct_find_function(&ul_ptr, "draw_filter"); */ + + RNA_parameter_list_create(&list, &ul_ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + RNA_parameter_set_lookup(&list, "layout", &layout); ui_list->type->ext.call((bContext *)C, &ul_ptr, func, &list); RNA_parameter_list_free(&list); } +static void uilist_filter_items(uiList *ui_list, bContext *C, PointerRNA *dataptr, const char *propname) +{ + extern FunctionRNA rna_UIList_filter_items_func; + + PointerRNA ul_ptr; + ParameterList list; + FunctionRNA *func; + PropertyRNA *parm; + + uiListDyn *flt_data = ui_list->dyn_data; + int *filter_flags, *filter_neworder; + void *ret1, *ret2; + int ret_len; + int len = flt_data->items_len = RNA_collection_length(dataptr, propname); + + RNA_pointer_create(&CTX_wm_screen(C)->id, ui_list->type->ext.srna, ui_list, &ul_ptr); + func = &rna_UIList_filter_items_func; /* RNA_struct_find_function(&ul_ptr, "filter_items"); */ + + RNA_parameter_list_create(&list, &ul_ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + RNA_parameter_set_lookup(&list, "data", dataptr); + RNA_parameter_set_lookup(&list, "property", &propname); + + ui_list->type->ext.call((bContext *)C, &ul_ptr, func, &list); + + parm = RNA_function_find_parameter(NULL, func, "filter_flags"); + ret_len = RNA_parameter_dynamic_length_get(&list, parm); + if (ret_len != len && ret_len != 0) { + printf("%s: Error, py func returned %d items in %s, %d or none were expected.\n", AT, + RNA_parameter_dynamic_length_get(&list, parm), "filter_flags", len); + RNA_parameter_list_free(&list); + return; + } + RNA_parameter_get(&list, parm, &ret1); + filter_flags = (int *)ret1; + + parm = RNA_function_find_parameter(NULL, func, "filter_neworder"); + ret_len = RNA_parameter_dynamic_length_get(&list, parm); + if (ret_len != len && ret_len != 0) { + printf("%s: Error, py func returned %d items in %s, %d or none were expected.\n", AT, + RNA_parameter_dynamic_length_get(&list, parm), "filter_neworder", len); + RNA_parameter_list_free(&list); + return; + } + RNA_parameter_get(&list, parm, &ret2); + filter_neworder = (int *)ret2; + + /* We have to do some final checks and transforms... */ + { + int i, filter_exclude = ui_list->filter_flag & UILST_FLT_EXCLUDE; + if (filter_flags) { + flt_data->items_filter_flags = MEM_mallocN(sizeof(int) * len, AT); + memcpy(flt_data->items_filter_flags, filter_flags, sizeof(int) * len); + + if (filter_neworder) { + /* For sake of simplicity, py filtering is expected to filter all items, but we actually only want + * reordering data for shown items! + */ + int items_shown, shown_idx; + int t_idx, t_ni, prev_ni; + flt_data->items_shown = 0; + for (i = 0, shown_idx = 0; i < len; i++) { + if ((filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude) { + filter_neworder[shown_idx++] = filter_neworder[i]; + } + } + items_shown = flt_data->items_shown = shown_idx; + flt_data->items_filter_neworder = MEM_mallocN(sizeof(int) * items_shown, AT); + /* And now, bring back new indices into the [0, items_shown[ range! + * XXX This is O(N²)... :/ + */ + for (shown_idx = 0, prev_ni = -1; shown_idx < items_shown; shown_idx++) { + for (i = 0, t_ni = len, t_idx = -1; i < items_shown; i++) { + int ni = filter_neworder[i]; + if (ni > prev_ni && ni < t_ni) { + t_idx = i; + t_ni = ni; + } + } + if (t_idx >= 0) { + prev_ni = t_ni; + flt_data->items_filter_neworder[t_idx] = shown_idx; + } + } + } + else { + /* we still have to set flt_data->items_shown... */ + flt_data->items_shown = 0; + for (i = 0; i < len; i++) { + if ((filter_flags[i] & UILST_FLT_ITEM) ^ filter_exclude) { + flt_data->items_shown++; + } + } + } + } + else { + flt_data->items_shown = len; + + if (filter_neworder) { + flt_data->items_filter_neworder = MEM_mallocN(sizeof(int) * len, AT); + memcpy(flt_data->items_filter_neworder, filter_neworder, sizeof(int) * len); + } + } + } + + RNA_parameter_list_free(&list); +} + static void rna_UIList_unregister(Main *UNUSED(bmain), StructRNA *type) { uiListType *ult = RNA_struct_blender_type_get(type); @@ -318,7 +461,7 @@ static StructRNA *rna_UIList_register(Main *bmain, ReportList *reports, void *da uiListType *ult, dummyult = {NULL}; uiList dummyuilist = {NULL}; PointerRNA dummyul_ptr; - int have_function[1]; + int have_function[3]; size_t over_alloc = 0; /* warning, if this becomes a bess, we better do another alloc */ /* setup dummy menu & menu type to store static properties in */ @@ -349,9 +492,10 @@ static StructRNA *rna_UIList_register(Main *bmain, ReportList *reports, void *da ult->ext.call = call; ult->ext.free = free; RNA_struct_blender_type_set(ult->ext.srna, ult); - RNA_def_struct_flag(ult->ext.srna, STRUCT_NO_IDPROPERTIES); ult->draw_item = (have_function[0]) ? uilist_draw_item : NULL; + ult->draw_filter = (have_function[1]) ? uilist_draw_filter : NULL; + ult->filter_items = (have_function[2]) ? uilist_filter_items : NULL; WM_uilisttype_add(ult); @@ -874,8 +1018,46 @@ static void rna_def_uilist(BlenderRNA *brna) RNA_def_struct_sdna(srna, "uiList"); RNA_def_struct_refine_func(srna, "rna_UIList_refine"); RNA_def_struct_register_funcs(srna, "rna_UIList_register", "rna_UIList_unregister", NULL); + RNA_def_struct_idprops_func(srna, "rna_UIList_idprops"); - /* draw */ + /* Registration */ + prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "type->idname"); + RNA_def_property_flag(prop, PROP_REGISTER | PROP_NEVER_CLAMP); + RNA_def_property_ui_text(prop, "ID Name", + "If this is set, the uilist gets a custom ID, otherwise it takes the " + "name of the class used to define the uilist (for example, if the " + "class name is \"OBJECT_UL_vgroups\", and bl_idname is not set by the " + "script, then bl_idname = \"OBJECT_UL_vgroups\")"); + + /* Data */ + prop = RNA_def_property(srna, "layout_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, uilist_layout_type_items); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + /* Filter options */ + prop = RNA_def_property(srna, "use_filter_show", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "filter_flag", UILST_FLT_SHOW); + RNA_def_property_ui_text(prop, "Show Filter", "Show filtering options"); + + prop = RNA_def_property(srna, "filter_name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "filter_byname"); + 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); + RNA_def_property_boolean_sdna(prop, NULL, "filter_flag", UILST_FLT_EXCLUDE); + RNA_def_property_ui_text(prop, "Invert", "Invert filtering (show hidden items, and vice-versa)"); + + prop = RNA_def_property(srna, "use_filter_sort_alpha", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "filter_sort_flag", UILST_FLT_SORT_ALPHA); + RNA_def_property_ui_icon(prop, ICON_SORTALPHA, 0); + RNA_def_property_ui_text(prop, "Sort by Name", "Sort items by their name"); + + prop = RNA_def_property(srna, "use_filter_sort_reverse", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "filter_sort_flag", UILST_FLT_SORT_REVERSE); + RNA_def_property_ui_text(prop, "Invert", "Invert the order of shown items"); + + /* draw_item */ func = RNA_def_function(srna, "draw_item", NULL); RNA_def_function_ui_description(func, "Draw an item in the list (NOTE: when you define your own draw_item " "function, you may want to check given 'item' is of the right type...)"); @@ -897,21 +1079,52 @@ static void rna_def_uilist(BlenderRNA *brna) "Identifier of property in active_data, for the active element"); RNA_def_property_flag(parm, PROP_REQUIRED); RNA_def_int(func, "index", 0, 0, INT_MAX, "", "Index of the item in the collection", 0, INT_MAX); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_PYFUNC_OPTIONAL); + prop = RNA_def_property(func, "flt_flag", PROP_INT, PROP_UNSIGNED); + RNA_def_property_ui_text(prop, "", "The filter-flag result for this item"); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_PYFUNC_OPTIONAL); + + /* draw_filter */ + func = RNA_def_function(srna, "draw_filter", NULL); + RNA_def_function_ui_description(func, "Draw filtering options"); + RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); + parm = RNA_def_pointer(func, "context", "Context", "", ""); RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_pointer(func, "layout", "UILayout", "", "Layout to draw the item"); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); - prop = RNA_def_property(srna, "layout_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, uilist_layout_type_items); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); + /* filter */ + func = RNA_def_function(srna, "filter_items", NULL); + RNA_def_function_ui_description(func, "Filter and/or re-order items of the collection (output filter results in " + "filter_flags, and reorder results in filter_neworder arrays)"); + RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take Collection property"); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + parm = RNA_def_string(func, "property", "", 0, "", "Identifier of property in data, for the collection"); + RNA_def_property_flag(parm, PROP_REQUIRED); + prop = RNA_def_property(func, "filter_flags", PROP_INT, PROP_UNSIGNED); + RNA_def_property_flag(prop, PROP_REQUIRED | PROP_DYNAMIC); + RNA_def_property_array(prop, 1); /* XXX Dummy value, default 0 does not work */ + RNA_def_property_ui_text(prop, "", "An array of filter flags, one for each item in the collection (NOTE: " + "FILTER_ITEM bit is reserved, it defines whether the item is shown or not)"); + RNA_def_function_output(func, prop); + prop = RNA_def_property(func, "filter_neworder", PROP_INT, PROP_UNSIGNED); + RNA_def_property_flag(prop, PROP_REQUIRED | PROP_DYNAMIC); + RNA_def_property_array(prop, 1); /* XXX Dummy value, default 0 does not work */ + RNA_def_property_ui_text(prop, "", "An array of indices, one for each item in the collection, mapping the org " + "index to the new one"); + RNA_def_function_output(func, prop); + + /* "Constants"! */ + RNA_define_verify_sdna(0); /* not in sdna */ - /* registration */ - prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); - RNA_def_property_string_sdna(prop, NULL, "type->idname"); - RNA_def_property_flag(prop, PROP_REGISTER | PROP_NEVER_CLAMP); - RNA_def_property_ui_text(prop, "ID Name", - "If this is set, the uilist gets a custom ID, otherwise it takes the " - "name of the class used to define the uilist (for example, if the " - "class name is \"OBJECT_UL_vgroups\", and bl_idname is not set by the " - "script, then bl_idname = \"OBJECT_UL_vgroups\")"); + prop = RNA_def_property(srna, "bitflag_filter_item", PROP_INT, PROP_UNSIGNED); + RNA_def_property_ui_text(prop, "FILTER_ITEM", + "The value of the reserved bitflag 'FILTER_ITEM' (in filter_flags values)"); + RNA_def_property_int_funcs(prop, "rna_UIList_filter_const_FILTER_ITEM_get", NULL, NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); } static void rna_def_header(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 2d89317b4ae..d79a40aa615 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -428,7 +428,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_ui_description(func, "Sub-layout. Items placed in this sublayout are placed next to each other " "in a row"); - RNA_def_boolean(func, "align", 0, "", "Align buttons to each other"); + RNA_def_boolean(func, "align", false, "", "Align buttons to each other"); func = RNA_def_function(srna, "column", "uiLayoutColumn"); parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); @@ -436,13 +436,13 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_ui_description(func, "Sub-layout. Items placed in this sublayout are placed under each other " "in a column"); - RNA_def_boolean(func, "align", 0, "", "Align buttons to each other"); + RNA_def_boolean(func, "align", false, "", "Align buttons to each other"); func = RNA_def_function(srna, "column_flow", "uiLayoutColumnFlow"); RNA_def_int(func, "columns", 0, 0, INT_MAX, "", "Number of columns, 0 is automatic", 0, INT_MAX); parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); RNA_def_function_return(func, parm); - RNA_def_boolean(func, "align", 0, "", "Align buttons to each other"); + RNA_def_boolean(func, "align", false, "", "Align buttons to each other"); /* box layout */ func = RNA_def_function(srna, "box", "uiLayoutBox"); @@ -456,7 +456,7 @@ void RNA_api_ui_layout(StructRNA *srna) parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); RNA_def_function_return(func, parm); RNA_def_float(func, "percentage", 0.0f, 0.0f, 1.0f, "Percentage", "Percentage of width to split at", 0.0f, 1.0f); - RNA_def_boolean(func, "align", 0, "", "Align buttons to each other"); + RNA_def_boolean(func, "align", false, "", "Align buttons to each other"); /* Icon of a rna pointer */ func = RNA_def_function(srna, "icon", "rna_ui_get_rnaptr_icon"); @@ -501,13 +501,13 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_ui_description(func, "Item. Exposes an RNA item and places it into the layout"); api_ui_item_rna_common(func); api_ui_item_common(func); - RNA_def_boolean(func, "expand", 0, "", "Expand button to show more detail"); - RNA_def_boolean(func, "slider", 0, "", "Use slider widget for numeric values"); - RNA_def_boolean(func, "toggle", 0, "", "Use toggle widget for boolean values"); - RNA_def_boolean(func, "icon_only", 0, "", "Draw only icons in buttons, no text"); - RNA_def_boolean(func, "event", 0, "", "Use button to input key events"); - RNA_def_boolean(func, "full_event", 0, "", "Use button to input full events including modifiers"); - RNA_def_boolean(func, "emboss", 1, "", "Draw the button itself, just the icon/text"); + RNA_def_boolean(func, "expand", false, "", "Expand button to show more detail"); + RNA_def_boolean(func, "slider", false, "", "Use slider widget for numeric values"); + RNA_def_boolean(func, "toggle", false, "", "Use toggle widget for boolean values"); + RNA_def_boolean(func, "icon_only", false, "", "Draw only icons in buttons, no text"); + RNA_def_boolean(func, "event", false, "", "Use button to input key events"); + RNA_def_boolean(func, "full_event", false, "", "Use button to input full events including modifiers"); + RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, just the icon/text"); RNA_def_int(func, "index", -1, -2, INT_MAX, "", "The index of this button, when set a single member of an array can be accessed, " "when set to -1 all array members are used", -2, INT_MAX); /* RNA_NO_INDEX == -1 */ @@ -535,7 +535,7 @@ void RNA_api_ui_layout(StructRNA *srna) func = RNA_def_function(srna, "operator", "rna_uiItemO"); api_ui_item_op_common(func); - RNA_def_boolean(func, "emboss", 1, "", "Draw the button itself, just the icon/text"); + RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, just the icon/text"); parm = RNA_def_pointer(func, "properties", "OperatorProperties", "", "Operator properties to fill in, return when 'properties' is set to true"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); @@ -569,7 +569,7 @@ void RNA_api_ui_layout(StructRNA *srna) api_ui_item_op_common(func); parm = RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator"); RNA_def_property_flag(parm, PROP_REQUIRED); - parm = RNA_def_boolean(func, "value", 0, "", "Value of the property to call the operator with"); + parm = RNA_def_boolean(func, "value", false, "", "Value of the property to call the operator with"); RNA_def_property_flag(parm, PROP_REQUIRED); */ func = RNA_def_function(srna, "operator_int", "uiItemIntO"); @@ -623,7 +623,7 @@ void RNA_api_ui_layout(StructRNA *srna) /* templates */ func = RNA_def_function(srna, "template_header", "uiTemplateHeader"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); - RNA_def_boolean(func, "menus", 1, "", "The header has menus, and should show menu expander"); + RNA_def_boolean(func, "menus", true, "", "The header has menus, and should show menu expander"); func = RNA_def_function(srna, "template_ID", "uiTemplateID"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); @@ -679,7 +679,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_ui_description(func, "Item. A preview window for materials, textures, lamps, etc"); parm = RNA_def_pointer(func, "id", "ID", "", "ID datablock"); RNA_def_property_flag(parm, PROP_REQUIRED); - RNA_def_boolean(func, "show_buttons", 1, "", "Show preview buttons?"); + RNA_def_boolean(func, "show_buttons", true, "", "Show preview buttons?"); RNA_def_pointer(func, "parent", "ID", "", "ID datablock"); RNA_def_pointer(func, "slot", "TextureSlot", "", "Texture slot"); @@ -687,13 +687,13 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_ui_description(func, "Item. A curve mapping widget used for e.g falloff curves for lamps"); api_ui_item_rna_common(func); RNA_def_enum(func, "type", curve_type_items, 0, "Type", "Type of curves to display"); - RNA_def_boolean(func, "levels", 0, "", "Show black/white levels"); - RNA_def_boolean(func, "brush", 0, "", "Show brush options"); + RNA_def_boolean(func, "levels", false, "", "Show black/white levels"); + RNA_def_boolean(func, "brush", false, "", "Show brush options"); func = RNA_def_function(srna, "template_color_ramp", "uiTemplateColorRamp"); RNA_def_function_ui_description(func, "Item. A color ramp widget"); api_ui_item_rna_common(func); - RNA_def_boolean(func, "expand", 0, "", "Expand button to show more detail"); + RNA_def_boolean(func, "expand", false, "", "Expand button to show more detail"); func = RNA_def_function(srna, "template_icon_view", "uiTemplateIconView"); RNA_def_function_ui_description(func, "Enum. Large widget showing Icon previews"); @@ -723,10 +723,10 @@ void RNA_api_ui_layout(StructRNA *srna) func = RNA_def_function(srna, "template_color_picker", "uiTemplateColorPicker"); RNA_def_function_ui_description(func, "Item. A color wheel widget to pick colors"); api_ui_item_rna_common(func); - RNA_def_boolean(func, "value_slider", 0, "", "Display the value slider to the right of the color wheel"); - RNA_def_boolean(func, "lock", 0, "", "Lock the color wheel display to value 1.0 regardless of actual color"); - RNA_def_boolean(func, "lock_luminosity", 0, "", "Keep the color at its original vector length"); - RNA_def_boolean(func, "cubic", 1, "", "Cubic saturation for picking values close to white"); + RNA_def_boolean(func, "value_slider", false, "", "Display the value slider to the right of the color wheel"); + RNA_def_boolean(func, "lock", false, "", "Lock the color wheel display to value 1.0 regardless of actual color"); + RNA_def_boolean(func, "lock_luminosity", false, "", "Keep the color at its original vector length"); + RNA_def_boolean(func, "cubic", true, "", "Cubic saturation for picking values close to white"); func = RNA_def_function(srna, "template_image_layers", "uiTemplateImageLayers"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); @@ -741,19 +741,19 @@ void RNA_api_ui_layout(StructRNA *srna) api_ui_item_rna_common(func); parm = RNA_def_pointer(func, "image_user", "ImageUser", "", ""); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); - RNA_def_boolean(func, "compact", 0, "", "Use more compact layout"); + RNA_def_boolean(func, "compact", false, "", "Use more compact layout"); func = RNA_def_function(srna, "template_image_settings", "uiTemplateImageSettings"); RNA_def_function_ui_description(func, "User interface for setting image format options"); parm = RNA_def_pointer(func, "image_settings", "ImageFormatSettings", "", ""); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); - RNA_def_boolean(func, "color_management", 0, "", "Show color management settings"); + RNA_def_boolean(func, "color_management", false, "", "Show color management settings"); func = RNA_def_function(srna, "template_movieclip", "uiTemplateMovieClip"); RNA_def_function_ui_description(func, "Item(s). User interface for selecting movie clips and their source paths"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); api_ui_item_rna_common(func); - RNA_def_boolean(func, "compact", 0, "", "Use more compact layout"); + RNA_def_boolean(func, "compact", false, "", "Use more compact layout"); func = RNA_def_function(srna, "template_track", "uiTemplateTrack"); RNA_def_function_ui_description(func, "Item. A movie-track widget to preview tracking image."); @@ -766,7 +766,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); parm = RNA_def_pointer(func, "track", "MovieTrackingTrack", "", ""); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); - RNA_def_boolean(func, "compact", 0, "", "Use more compact layout"); + RNA_def_boolean(func, "compact", false, "", "Use more compact layout"); func = RNA_def_function(srna, "template_movieclip_information", "uiTemplateMovieclipInformation"); RNA_def_function_ui_description(func, "Item. Movie clip information data."); @@ -796,9 +796,10 @@ void RNA_api_ui_layout(StructRNA *srna) parm = RNA_def_string(func, "active_propname", "", 0, "", "Identifier of the integer property in active_data, index of the active item"); RNA_def_property_flag(parm, PROP_REQUIRED); - RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Number of rows to display", 0, INT_MAX); - RNA_def_int(func, "maxrows", 5, 0, INT_MAX, "", "Maximum number of rows to display", 0, INT_MAX); + RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Default and minimum number of rows to display", 0, INT_MAX); + RNA_def_int(func, "maxrows", 5, 0, INT_MAX, "", "Default maximum number of rows to display", 0, INT_MAX); RNA_def_enum(func, "type", uilist_layout_type_items, UILST_LAYOUT_DEFAULT, "Type", "Type of layout to use"); + RNA_def_int(func, "columns", 9, 0, INT_MAX, "", "Number of items to display per row, for GRID layout", 0, INT_MAX); func = RNA_def_function(srna, "template_running_jobs", "uiTemplateRunningJobs"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); @@ -859,7 +860,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_ui_description(func, "Item. A widget to control color managed view settings settings."); RNA_def_function_flag(func, FUNC_USE_CONTEXT); api_ui_item_rna_common(func); - /* RNA_def_boolean(func, "show_global_settings", 0, "", "Show widgets to control global color management settings"); */ + /* RNA_def_boolean(func, "show_global_settings", false, "", "Show widgets to control global color management settings"); */ /* node socket icon */ func = RNA_def_function(srna, "template_node_socket", "uiTemplateNodeSocket"); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index f34366a23c7..20e5083b1c4 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -505,6 +505,7 @@ static EnumPropertyItem *rna_userdef_audio_device_itemf(bContext *UNUSED(C), Poi return item; } #else + (void)free; return audio_device_items; #endif } @@ -2134,6 +2135,18 @@ static void rna_def_userdef_theme_space_image(BlenderRNA *brna) RNA_def_property_array(prop, 4); RNA_def_property_ui_text(prop, "Stitch preview active island", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "uv_shadow", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "uv_shadow"); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Texture paint/Modifier UVs", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "uv_others", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "uv_others"); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Other Object UVs", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); } static void rna_def_userdef_theme_space_seq(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 0d1c684e6a1..c6366745c55 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -43,7 +43,8 @@ #include "WM_types.h" -EnumPropertyItem event_keymouse_value_items[] = { +#ifdef RNA_RUNTIME +static EnumPropertyItem event_keymouse_value_items[] = { {KM_ANY, "ANY", 0, "Any", ""}, {KM_PRESS, "PRESS", 0, "Press", ""}, {KM_RELEASE, "RELEASE", 0, "Release", ""}, @@ -52,7 +53,7 @@ EnumPropertyItem event_keymouse_value_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem event_tweak_value_items[] = { +static EnumPropertyItem event_tweak_value_items[] = { {KM_ANY, "ANY", 0, "Any", ""}, {EVT_GESTURE_N, "NORTH", 0, "North", ""}, {EVT_GESTURE_NE, "NORTH_EAST", 0, "North-East", ""}, @@ -65,25 +66,7 @@ EnumPropertyItem event_tweak_value_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem event_value_items[] = { - {KM_ANY, "ANY", 0, "Any", ""}, - {KM_NOTHING, "NOTHING", 0, "Nothing", ""}, - {KM_PRESS, "PRESS", 0, "Press", ""}, - {KM_RELEASE, "RELEASE", 0, "Release", ""}, - {KM_CLICK, "CLICK", 0, "Click", ""}, - {KM_DBL_CLICK, "DOUBLE_CLICK", 0, "Double Click", ""}, - {EVT_GESTURE_N, "NORTH", 0, "North", ""}, - {EVT_GESTURE_NE, "NORTH_EAST", 0, "North-East", ""}, - {EVT_GESTURE_E, "EAST", 0, "East", ""}, - {EVT_GESTURE_SE, "SOUTH_EAST", 0, "South-East", ""}, - {EVT_GESTURE_S, "SOUTH", 0, "South", ""}, - {EVT_GESTURE_SW, "SOUTH_WEST", 0, "South-West", ""}, - {EVT_GESTURE_W, "WEST", 0, "West", ""}, - {EVT_GESTURE_NW, "NORTH_WEST", 0, "North-West", ""}, - {0, NULL, 0, NULL, NULL} -}; - -EnumPropertyItem event_tweak_type_items[] = { +static EnumPropertyItem event_tweak_type_items[] = { {EVT_TWEAK_L, "EVT_TWEAK_L", 0, "Left", ""}, {EVT_TWEAK_M, "EVT_TWEAK_M", 0, "Middle", ""}, {EVT_TWEAK_R, "EVT_TWEAK_R", 0, "Right", ""}, @@ -92,7 +75,7 @@ EnumPropertyItem event_tweak_type_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem event_mouse_type_items[] = { +static EnumPropertyItem event_mouse_type_items[] = { {LEFTMOUSE, "LEFTMOUSE", 0, "Left", ""}, {MIDDLEMOUSE, "MIDDLEMOUSE", 0, "Middle", ""}, {RIGHTMOUSE, "RIGHTMOUSE", 0, "Right", ""}, @@ -113,7 +96,7 @@ EnumPropertyItem event_mouse_type_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem event_timer_type_items[] = { +static EnumPropertyItem event_timer_type_items[] = { {TIMER, "TIMER", 0, "Timer", ""}, {TIMER0, "TIMER0", 0, "Timer 0", ""}, {TIMER1, "TIMER1", 0, "Timer 1", ""}, @@ -125,12 +108,12 @@ EnumPropertyItem event_timer_type_items[] = { {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem event_textinput_type_items[] = { +static EnumPropertyItem event_textinput_type_items[] = { {KM_TEXTINPUT, "TEXTINPUT", 0, "Text Input", ""}, {0, NULL, 0, NULL, NULL} }; -EnumPropertyItem event_ndof_type_items[] = { +static EnumPropertyItem event_ndof_type_items[] = { {NDOF_MOTION, "NDOF_MOTION", 0, "Motion", ""}, /* buttons on all 3dconnexion devices */ {NDOF_BUTTON_MENU, "NDOF_BUTTON_MENU", 0, "Menu", ""}, @@ -179,6 +162,7 @@ EnumPropertyItem event_ndof_type_items[] = { {NDOF_BUTTON_C, "NDOF_BUTTON_C", 0, "Button C", ""}, {0, NULL, 0, NULL, NULL} }; +#endif /* not returned: CAPSLOCKKEY, UNKNOWNKEY */ EnumPropertyItem event_type_items[] = { @@ -386,6 +370,24 @@ EnumPropertyItem event_type_items[] = { {0, NULL, 0, NULL, NULL} }; +EnumPropertyItem event_value_items[] = { + {KM_ANY, "ANY", 0, "Any", ""}, + {KM_NOTHING, "NOTHING", 0, "Nothing", ""}, + {KM_PRESS, "PRESS", 0, "Press", ""}, + {KM_RELEASE, "RELEASE", 0, "Release", ""}, + {KM_CLICK, "CLICK", 0, "Click", ""}, + {KM_DBL_CLICK, "DOUBLE_CLICK", 0, "Double Click", ""}, + {EVT_GESTURE_N, "NORTH", 0, "North", ""}, + {EVT_GESTURE_NE, "NORTH_EAST", 0, "North-East", ""}, + {EVT_GESTURE_E, "EAST", 0, "East", ""}, + {EVT_GESTURE_SE, "SOUTH_EAST", 0, "South-East", ""}, + {EVT_GESTURE_S, "SOUTH", 0, "South", ""}, + {EVT_GESTURE_SW, "SOUTH_WEST", 0, "South-West", ""}, + {EVT_GESTURE_W, "WEST", 0, "West", ""}, + {EVT_GESTURE_NW, "NORTH_WEST", 0, "North-West", ""}, + {0, NULL, 0, NULL, NULL} +}; + EnumPropertyItem keymap_propvalue_items[] = { {0, "NONE", 0, "", ""}, {0, NULL, 0, NULL, NULL} @@ -401,7 +403,9 @@ static EnumPropertyItem keymap_modifiers_items[] = { }; #endif -EnumPropertyItem operator_flag_items[] = { + +#ifndef RNA_RUNTIME +static EnumPropertyItem operator_flag_items[] = { {OPTYPE_REGISTER, "REGISTER", 0, "Register", "Display in the info window and support the redo toolbar panel"}, {OPTYPE_UNDO, "UNDO", 0, "Undo", "Push an undo event (needed for operator redo)"}, {OPTYPE_BLOCKING, "BLOCKING", 0, "Blocking", "Block anything else from using the cursor"}, @@ -413,6 +417,7 @@ EnumPropertyItem operator_flag_items[] = { {OPTYPE_INTERNAL, "INTERNAL", 0, "Internal", "Removes the operator from search results"}, {0, NULL, 0, NULL, NULL} }; +#endif EnumPropertyItem operator_return_items[] = { {OPERATOR_RUNNING_MODAL, "RUNNING_MODAL", 0, "Running Modal", "Keep the operator running with blender"}, @@ -585,7 +590,7 @@ static void rna_Window_screen_set(PointerRNA *ptr, PointerRNA value) win->newscreen = value.data; } -int rna_Window_screen_assign_poll(PointerRNA *ptr, PointerRNA value) +int rna_Window_screen_assign_poll(PointerRNA *UNUSED(ptr), PointerRNA value) { bScreen *screen = (bScreen *)value.id.data; @@ -1735,6 +1740,8 @@ static void rna_def_window(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "sizey"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Height", "Window height"); + + RNA_api_window(srna); } /* curve.splines */ diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index c822378e76e..eb84bb61e1f 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -41,8 +41,31 @@ #include "DNA_space_types.h" #include "DNA_windowmanager_types.h" +#include "wm_cursors.h" + #include "rna_internal.h" /* own include */ +/* confusingm 2 enums mixed up here */ +EnumPropertyItem window_cursor_items[] = { + {CURSOR_STD, "DEFAULT", 0, "Default", ""}, + {CURSOR_NONE, "NONE", 0, "None", ""}, + {CURSOR_WAIT, "WAIT", 0, "Wait", ""}, + {CURSOR_EDIT, "CROSSHAIR", 0, "Crosshair", ""}, + {CURSOR_X_MOVE, "MOVE_X", 0, "Move-X", ""}, + {CURSOR_Y_MOVE, "MOVE_Y", 0, "Move-Y", ""}, + + /* new */ + {BC_KNIFECURSOR, "KNIFE", 0, "Knife", ""}, + {BC_TEXTEDITCURSOR, "TEXT", 0, "Text", ""}, + {BC_PAINTBRUSHCURSOR, "PAINT_BRUSH", 0, "Paint Brush", ""}, + {BC_HANDCURSOR, "HAND", 0, "Hand", ""}, + {BC_EW_SCROLLCURSOR, "SCROLL_X", 0, "Scroll-X", ""}, + {BC_NS_SCROLLCURSOR, "SCROLL_Y", 0, "Scroll-Y", ""}, + {BC_NSEW_SCROLLCURSOR, "SCROLL_XY", 0, "Scroll-XY", ""}, + {BC_EYEDROPPER_CURSOR, "EYEDROPPER", 0, "Eyedropper", ""}, + {0, NULL, 0, NULL, NULL} +}; + #ifdef RNA_RUNTIME #include "UI_interface.h" @@ -95,7 +118,7 @@ struct wmStaticProgress { } wm_progress_state = {0, 0, false}; -static void rna_progress_begin(struct wmWindowManager *wm, float min, float max) +static void rna_progress_begin(struct wmWindowManager *UNUSED(wm), float min, float max) { float range = max - min; if (range != 0) { @@ -120,7 +143,7 @@ static void rna_progress_update(struct wmWindowManager *wm, float value) static void rna_progress_end(struct wmWindowManager *wm) { if (wm_progress_state.is_valid) { - WM_cursor_restore(wm->winactive); + WM_cursor_modal_restore(wm->winactive); wm_progress_state.is_valid = false; } } @@ -239,6 +262,18 @@ static wmKeyMap *rna_keymap_find_modal(wmKeyConfig *UNUSED(keyconf), const char return ot->modalkeymap; } +static void rna_KeyMap_remove(wmKeyConfig *keyconfig, ReportList *reports, PointerRNA *keymap_ptr) +{ + wmKeyMap *keymap = keymap_ptr->data; + + if (WM_keymap_remove(keyconfig, keymap) == FALSE) { + BKE_reportf(reports, RPT_ERROR, "KeyConfig '%s' cannot be removed", keymap->idname); + return; + } + + RNA_POINTER_INVALIDATE(keymap_ptr); +} + static void rna_KeyConfig_remove(wmWindowManager *wm, ReportList *reports, PointerRNA *keyconf_ptr) { wmKeyConfig *keyconf = keyconf_ptr->data; @@ -299,6 +334,34 @@ static void rna_generic_op_invoke(FunctionRNA *func, int flag) } } +void RNA_api_window(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + func = RNA_def_function(srna, "cursor_warp", "WM_cursor_warp"); + parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "", "", INT_MIN, INT_MAX); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "", "", INT_MIN, INT_MAX); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_function_ui_description(func, "Set the cursor position"); + + func = RNA_def_function(srna, "cursor_set", "WM_cursor_set"); + parm = RNA_def_property(func, "cursor", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(parm, window_cursor_items); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_function_ui_description(func, "Set the cursor"); + + func = RNA_def_function(srna, "cursor_modal_set", "WM_cursor_modal_set"); + parm = RNA_def_property(func, "cursor", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(parm, window_cursor_items); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_function_ui_description(func, "Set the cursor, so the previous cursor can be restored"); + + RNA_def_function(srna, "cursor_modal_restore", "WM_cursor_modal_restore"); + RNA_def_function_ui_description(func, "Restore the previous cursor after calling ``cursor_modal_set``"); +} + void RNA_api_wm(StructRNA *srna) { FunctionRNA *func; @@ -620,6 +683,12 @@ void RNA_api_keymaps(StructRNA *srna) parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Added key map"); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "remove", "rna_KeyMap_remove"); /* remove_keymap */ + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Removed key map"); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); + RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + func = RNA_def_function(srna, "find", "rna_keymap_find"); /* find_keymap */ parm = RNA_def_string(func, "name", "", 0, "Name", ""); RNA_def_property_flag(parm, PROP_REQUIRED); diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index e09fa18ffc5..7c47fd5862e 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -50,6 +50,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_displist.h" +#include "BKE_curve.h" #include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -198,7 +199,7 @@ static int *find_doubles_index_map(BMesh *bm, BMOperator *dupe_op, /*element type argument doesn't do anything here*/ BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) { - v2 = BMO_iter_map_value_p(&oiter); + v2 = BMO_iter_map_value_ptr(&oiter); index_map[BM_elem_index_get(v)] = BM_elem_index_get(v2) + 1; } @@ -271,7 +272,7 @@ static void bm_merge_dm_transform(BMesh *bm, DerivedMesh *dm, float mat[4][4], /* add new merge targets to weld operator */ BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) { - v2 = BMO_iter_map_value_p(&oiter); + v2 = BMO_iter_map_value_ptr(&oiter); /* check in case the target vertex (v2) is already marked * for merging */ while ((v3 = BMO_slot_map_elem_get(slot_targetmap, v2))) { @@ -318,8 +319,10 @@ static void merge_first_last(BMesh *bm, /* add new merge targets to weld operator */ slot_targetmap = BMO_slot_get(weld_op->slots_in, "targetmap"); BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) { - v2 = BMO_iter_map_value_p(&oiter); - BMO_slot_map_elem_insert(weld_op, slot_targetmap, v, v2); + if (!BMO_slot_map_contains(slot_targetmap, v)) { + v2 = BMO_iter_map_value_ptr(&oiter); + BMO_slot_map_elem_insert(weld_op, slot_targetmap, v, v2); + } } BMO_op_finish(bm, &find_op); @@ -343,7 +346,7 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, int *indexMap = NULL; DerivedMesh *start_cap = NULL, *end_cap = NULL; MVert *src_mvert; - BMOpSlot *slot_targetmap = NULL; /* for weldop */ + BMOpSlot *slot_targetmap = NULL; /* for weld_op */ /* need to avoid infinite recursion here */ if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH) @@ -387,19 +390,19 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, BKE_object_to_mat3(amd->curve_ob, tmp_mat); scale = mat3_to_scale(tmp_mat); - if (!cu->path) { + if (!amd->curve_ob->curve_cache || !amd->curve_ob->curve_cache->path) { cu->flag |= CU_PATH; // needed for path & bevlist BKE_displist_make_curveTypes(scene, amd->curve_ob, 0); } - if (cu->path) - length = scale * cu->path->totdist; + if (amd->curve_ob->curve_cache->path) + length = scale * amd->curve_ob->curve_cache->path->totdist; } } /* calculate the maximum number of copies which will fit within the * prescribed length */ if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) { - float dist = sqrt(dot_v3v3(offset[3], offset[3])); + float dist = len_v3(offset[3]); if (dist > 1e-6f) /* this gives length = first copy start to last copy end diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index b48f434abe9..326ffba3e2e 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -46,6 +46,7 @@ #include "MOD_util.h" #include "bmesh.h" +#include "bmesh_tools.h" #include "MEM_guardedalloc.h" @@ -116,7 +117,7 @@ static DerivedMesh *applyModifier(ModifierData *md, struct Object *ob, if ((bmd->lim_flags & MOD_BEVEL_VGROUP) && bmd->defgrp_name[0]) { modifier_get_vgroup(ob, dm, bmd->defgrp_name, &dvert, &vgroup); } - BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (!BM_vert_is_manifold(v)) continue; if (vgroup != -1) { diff --git a/source/blender/modifiers/intern/MOD_boolean_util.c b/source/blender/modifiers/intern/MOD_boolean_util.c index 98fab9c06ff..9c8109c7856 100644 --- a/source/blender/modifiers/intern/MOD_boolean_util.c +++ b/source/blender/modifiers/intern/MOD_boolean_util.c @@ -266,44 +266,6 @@ static void FaceIt_Construct( output->it = it; } -static Object *AddNewBlenderMesh(Scene *scene, Base *base) -{ - /* This little function adds a new mesh object to the blender object list - * It uses ob to duplicate data as this seems to be easier than creating - * a new one. This new oject contains no faces nor vertices. */ - Mesh *old_me; - Base *basen; - Object *ob_new; - - /* now create a new blender object. - * duplicating all the settings from the previous object - * to the new one. */ - ob_new = BKE_object_copy(base->object); - - /* Ok we don't want to use the actual data from the - * last object, the above function incremented the - * number of users, so decrement it here. */ - old_me = ob_new->data; - old_me->id.us--; - - /* Now create a new base to add into the linked list of - * vase objects. */ - - basen = MEM_mallocN(sizeof(Base), "duplibase"); - *basen = *base; - BLI_addhead(&scene->base, basen); /* addhead: anders oneindige lus */ - basen->object = ob_new; - basen->flag &= ~SELECT; - - /* Initialize the mesh data associated with this object. */ - ob_new->data = BKE_mesh_add(G.main, "Mesh"); - - /* Finally assign the object type. */ - ob_new->type = OB_MESH; - - return ob_new; -} - static void InterpCSGFace( DerivedMesh *dm, DerivedMesh *orig_dm, int index, int orig_index, int nr, float mapmat[4][4]) @@ -509,9 +471,9 @@ static void FreeMeshDescriptors( FaceIt_Destruct(face_it); } -static DerivedMesh *NewBooleanDerivedMesh_intern( +DerivedMesh *NewBooleanDerivedMesh( DerivedMesh *dm, struct Object *ob, DerivedMesh *dm_select, struct Object *ob_select, - int int_op_type, Material **mat, int *totmat) + int int_op_type) { float inv_mat[4][4]; @@ -567,7 +529,7 @@ static DerivedMesh *NewBooleanDerivedMesh_intern( /* iterate through results of operation and insert * into new object */ result = ConvertCSGDescriptorsToDerivedMesh( - &fd_o, &vd_o, inv_mat, map_mat, mat, totmat, dm_select, ob_select, dm, ob); + &fd_o, &vd_o, inv_mat, map_mat, NULL, NULL, dm_select, ob_select, dm, ob); /* free up the memory */ CSG_FreeVertexDescriptor(&vd_o); @@ -584,67 +546,3 @@ static DerivedMesh *NewBooleanDerivedMesh_intern( return result; } - -int NewBooleanMesh(Scene *scene, Base *base, Base *base_select, int int_op_type) -{ - Mesh *me_new; - int a, maxmat, totmat = 0; - Object *ob_new, *ob, *ob_select; - Material **mat; - DerivedMesh *result; - DerivedMesh *dm_select; - DerivedMesh *dm; - - ob = base->object; - ob_select = base_select->object; - - dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - dm_select = mesh_create_derived_view(scene, ob_select, 0); // no modifiers in editmode ?? - - maxmat = ob->totcol + ob_select->totcol; - mat = (Material **)MEM_mallocN(sizeof(Material *) * maxmat, "NewBooleanMeshMat"); - - /* put some checks in for nice user feedback */ - if (dm == NULL || dm_select == NULL) { - return 0; - } - - if (!dm->getNumTessFaces(dm) || !dm_select->getNumTessFaces(dm_select)) { - MEM_freeN(mat); - return -1; - } - - result = NewBooleanDerivedMesh_intern(dm, ob, dm_select, ob_select, int_op_type, mat, &totmat); - - if (result == NULL) { - MEM_freeN(mat); - return 0; - } - - /* create a new blender mesh object - using 'base' as a template */ - ob_new = AddNewBlenderMesh(scene, base_select); - me_new = ob_new->data; - - DM_to_mesh(result, me_new, ob_new, CD_MASK_MESH); - result->release(result); - - dm->release(dm); - dm_select->release(dm_select); - - /* add materials to object */ - for (a = 0; a < totmat; a++) - assign_material(ob_new, mat[a], a + 1, BKE_MAT_ASSIGN_USERPREF); - - MEM_freeN(mat); - - /* update dag */ - DAG_id_tag_update(&ob_new->id, OB_RECALC_DATA); - - return 1; -} - -DerivedMesh *NewBooleanDerivedMesh(DerivedMesh *dm, struct Object *ob, DerivedMesh *dm_select, struct Object *ob_select, - int int_op_type) -{ - return NewBooleanDerivedMesh_intern(dm, ob, dm_select, ob_select, int_op_type, NULL, NULL); -} diff --git a/source/blender/modifiers/intern/MOD_boolean_util.h b/source/blender/modifiers/intern/MOD_boolean_util.h index 209db60f0c9..04d76d45652 100644 --- a/source/blender/modifiers/intern/MOD_boolean_util.h +++ b/source/blender/modifiers/intern/MOD_boolean_util.h @@ -39,12 +39,6 @@ struct Base; struct DerivedMesh; /* Performs a boolean between two mesh objects, it is assumed that both objects - * are in fact a mesh object. On success returns 1 and creates a new mesh object - * into blender data structures. On failure returns 0 and reports an error. */ -int NewBooleanMesh(struct Scene *scene, struct Base *base, struct Base *base_select, int op); - - -/* Performs a boolean between two mesh objects, it is assumed that both objects * are in fact mesh object. On success returns a DerivedMesh. On failure * returns NULL and reports an error. */ diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c index 9e375b07972..a54cc80839b 100644 --- a/source/blender/modifiers/intern/MOD_build.c +++ b/source/blender/modifiers/intern/MOD_build.c @@ -109,7 +109,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob), edgeMap = MEM_mallocN(sizeof(*edgeMap) * numEdge_src, "build modifier edgeMap"); faceMap = MEM_mallocN(sizeof(*faceMap) * numPoly_src, "build modifier faceMap"); -#pragma omp parallel sections if (numVert_src + numEdge_src + numPoly_src >= DM_OMP_LIMIT) +#pragma omp parallel sections if (numVert_src + numEdge_src + numPoly_src >= BKE_MESH_OMP_LIMIT) { #pragma omp section { range_vn_i(vertMap, numVert_src, 0); } diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index 9fdb40e71dc..a3569cbde68 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -49,11 +49,13 @@ #include "BKE_cdderivedmesh.h" #include "bmesh.h" +#include "bmesh_tools.h" // #define USE_TIMEIT #ifdef USE_TIMEIT # include "PIL_time.h" +# include "PIL_time_utildefines.h" #endif #include "MOD_util.h" diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c index b3d3e65e120..d55ebdad939 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.c +++ b/source/blender/modifiers/intern/MOD_edgesplit.c @@ -44,6 +44,7 @@ #include "BKE_modifier.h" #include "bmesh.h" +#include "bmesh_tools.h" #include "DNA_object_types.h" diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index fe680041197..9fd11f78ea0 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -568,7 +568,7 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm) int numlayer; unsigned int ed_v1, ed_v2; - edgehash = BLI_edgehash_new(); + edgehash = BLI_edgehash_new(__func__); /* recreate vertpa from facepa calculation */ for (i = 0, mf = mface; i < totface; i++, mf++) { @@ -586,12 +586,12 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm) v3 = vertpa[mf->v3]; if (v1 != v2) { - BLI_edgehash_insert(edgehash, mf->v1, mf->v2, NULL); + BLI_edgehash_reinsert(edgehash, mf->v1, mf->v2, NULL); (*fs) |= 1; } if (v2 != v3) { - BLI_edgehash_insert(edgehash, mf->v2, mf->v3, NULL); + BLI_edgehash_reinsert(edgehash, mf->v2, mf->v3, NULL); (*fs) |= 2; } @@ -599,24 +599,24 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm) v4 = vertpa[mf->v4]; if (v3 != v4) { - BLI_edgehash_insert(edgehash, mf->v3, mf->v4, NULL); + BLI_edgehash_reinsert(edgehash, mf->v3, mf->v4, NULL); (*fs) |= 4; } if (v1 != v4) { - BLI_edgehash_insert(edgehash, mf->v1, mf->v4, NULL); + BLI_edgehash_reinsert(edgehash, mf->v1, mf->v4, NULL); (*fs) |= 8; } /* mark center vertex as a fake edge split */ if (*fs == 15) - BLI_edgehash_insert(edgehash, mf->v1, mf->v3, NULL); + BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL); } else { (*fs) |= 16; /* mark face as tri */ if (v1 != v3) { - BLI_edgehash_insert(edgehash, mf->v1, mf->v3, NULL); + BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL); (*fs) |= 4; } } @@ -821,7 +821,7 @@ static DerivedMesh *explodeMesh(ExplodeModifierData *emd, cfra = BKE_scene_frame_get(scene); /* hash table for vertice <-> particle relations */ - vertpahash = BLI_edgehash_new(); + vertpahash = BLI_edgehash_new(__func__); for (i = 0; i < totface; i++) { if (facepa[i] != totpart) { @@ -846,11 +846,11 @@ static DerivedMesh *explodeMesh(ExplodeModifierData *emd, mf = &mface[i]; /* set face vertices to exist in particle group */ - BLI_edgehash_insert(vertpahash, mf->v1, mindex, NULL); - BLI_edgehash_insert(vertpahash, mf->v2, mindex, NULL); - BLI_edgehash_insert(vertpahash, mf->v3, mindex, NULL); + BLI_edgehash_reinsert(vertpahash, mf->v1, mindex, NULL); + BLI_edgehash_reinsert(vertpahash, mf->v2, mindex, NULL); + BLI_edgehash_reinsert(vertpahash, mf->v3, mindex, NULL); if (mf->v4) - BLI_edgehash_insert(vertpahash, mf->v4, mindex, NULL); + BLI_edgehash_reinsert(vertpahash, mf->v4, mindex, NULL); } /* make new vertice indexes & count total vertices after duplication */ @@ -869,7 +869,7 @@ static DerivedMesh *explodeMesh(ExplodeModifierData *emd, /* getting back to object space */ invert_m4_m4(imat, ob->obmat); - psmd->psys->lattice = psys_get_lattice(&sim); + psmd->psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); /* duplicate & displace vertices */ ehi = BLI_edgehashIterator_new(vertpahash); @@ -973,9 +973,9 @@ static DerivedMesh *explodeMesh(ExplodeModifierData *emd, CDDM_tessfaces_to_faces(explode); explode->dirty |= DM_DIRTY_NORMALS; - if (psmd->psys->lattice) { - end_latt_deform(psmd->psys->lattice); - psmd->psys->lattice = NULL; + if (psmd->psys->lattice_deform_data) { + end_latt_deform(psmd->psys->lattice_deform_data); + psmd->psys->lattice_deform_data = NULL; } return explode; diff --git a/source/blender/modifiers/intern/MOD_meshcache_util.c b/source/blender/modifiers/intern/MOD_meshcache_util.c index 679a79322c3..404d0538a29 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_util.c +++ b/source/blender/modifiers/intern/MOD_meshcache_util.c @@ -20,6 +20,10 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/modifiers/intern/MOD_meshcache_util.c + * \ingroup modifiers + */ + #include "BLI_utildefines.h" #include "BLI_math.h" diff --git a/source/blender/modifiers/intern/MOD_meshcache_util.h b/source/blender/modifiers/intern/MOD_meshcache_util.h index d7e71518f77..f3b5f43009d 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_util.h +++ b/source/blender/modifiers/intern/MOD_meshcache_util.h @@ -25,6 +25,7 @@ */ #ifndef __MOD_MESHCACHE_UTIL_H__ +#define __MOD_MESHCACHE_UTIL_H__ struct MPoly; struct MLoop; @@ -64,4 +65,4 @@ void MOD_meshcache_calc_range(const float frame, const char interp, #define FRAME_SNAP_EPS 0.0001f -#endif /* __MOD_MESHCACHE_UTIL_H__ */ +#endif /* __MOD_MESHCACHE_UTIL_H__ */ diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index e846ce11262..c51fa329df2 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -261,7 +261,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, maxloop += totloop; } - psys->lattice = psys_get_lattice(&sim); + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); if (psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) { float min_r[3], max_r[3]; @@ -378,9 +378,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, CDDM_calc_edges(result); - if (psys->lattice) { - end_latt_deform(psys->lattice); - psys->lattice = NULL; + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; } if (size) diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index 83ac9f34df3..09e0ac966d0 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -933,7 +933,6 @@ static void add_poly(SkinOutput *so, BMVert *v4) { BMVert *verts[4] = {v1, v2, v3, v4}; - BMEdge *edges[4]; BMFace *f; BLI_assert(v1 != v2 && v1 != v3 && v1 != v4); @@ -941,18 +940,7 @@ static void add_poly(SkinOutput *so, BLI_assert(v3 != v4); BLI_assert(v1 && v2 && v3); - edges[0] = BM_edge_create(so->bm, v1, v2, NULL, BM_CREATE_NO_DOUBLE); - edges[1] = BM_edge_create(so->bm, v2, v3, NULL, BM_CREATE_NO_DOUBLE); - if (v4) { - edges[2] = BM_edge_create(so->bm, v3, v4, NULL, BM_CREATE_NO_DOUBLE); - edges[3] = BM_edge_create(so->bm, v4, v1, NULL, BM_CREATE_NO_DOUBLE); - } - else { - edges[2] = BM_edge_create(so->bm, v3, v1, NULL, BM_CREATE_NO_DOUBLE); - edges[3] = NULL; - } - - f = BM_face_create(so->bm, verts, edges, v4 ? 4 : 3, BM_CREATE_NO_DOUBLE); + f = BM_face_create_verts(so->bm, verts, v4 ? 4 : 3, NULL, BM_CREATE_NO_DOUBLE, true); if (so->smd->flag & MOD_SKIN_SMOOTH_SHADING) BM_elem_flag_enable(f, BM_ELEM_SMOOTH); f->mat_nr = so->mat_nr; @@ -996,7 +984,7 @@ static void output_frames(BMesh *bm, f = &sn->frames[i]; for (j = 0; j < 4; j++) { if (!f->merge[j].frame) { - BMVert *v = f->verts[j] = BM_vert_create(bm, f->co[j], NULL, 0); + BMVert *v = f->verts[j] = BM_vert_create(bm, f->co[j], NULL, BM_CREATE_NOP); if (input_dvert) { MDeformVert *dv; @@ -1310,7 +1298,7 @@ static void skin_hole_detach_partially_attached_frame(BMesh *bm, Frame *frame) /* Detach everything */ for (i = 0; i < totattached; i++) { BMVert **av = &frame->verts[attached[i]]; - (*av) = BM_vert_create(bm, (*av)->co, *av, 0); + (*av) = BM_vert_create(bm, (*av)->co, *av, BM_CREATE_NOP); } } diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index 98cea62a2ff..4e2656bbf00 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -121,14 +121,14 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, static DerivedMesh *applyModifierEM(ModifierData *md, Object *UNUSED(ob), struct BMEditMesh *UNUSED(editData), DerivedMesh *derivedData, - ModifierApplyFlag UNUSED(flag)) + ModifierApplyFlag flag) { SubsurfModifierData *smd = (SubsurfModifierData *) md; DerivedMesh *result; + /* 'orco' using editmode flags would cause cache to be used twice in editbmesh_calc_modifiers */ + SubsurfFlags ss_flags = (flag & MOD_APPLY_ORCO) ? 0 : (SUBSURF_FOR_EDIT_MODE | SUBSURF_IN_EDIT_MODE); - result = subsurf_make_derived_from_derived(derivedData, smd, - NULL, (SUBSURF_FOR_EDIT_MODE | - SUBSURF_IN_EDIT_MODE)); + result = subsurf_make_derived_from_derived(derivedData, smd, NULL, ss_flags); return result; } diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c index 9155aa0044b..ffc813068b8 100644 --- a/source/blender/modifiers/intern/MOD_triangulate.c +++ b/source/blender/modifiers/intern/MOD_triangulate.c @@ -33,6 +33,9 @@ #include "BKE_modifier.h" #include "BKE_editmesh.h" +#include "bmesh.h" +#include "bmesh_tools.h" + static DerivedMesh *triangulate_dm(DerivedMesh *dm, const int flag) { DerivedMesh *result; diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index b6539f4b028..ad1e2a464a8 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -93,7 +93,7 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED( CustomDataMask dataMask = 0; /* ask for UV coordinates */ - dataMask |= CD_MASK_MTFACE; + dataMask |= CD_MLOOPUV | CD_MTEXPOLY; return dataMask; } diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 63267538528..67168e52949 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -28,18 +28,12 @@ * \ingroup modifiers */ -#define DO_PROFILE 0 - #include "BLI_utildefines.h" #include "BLI_ghash.h" #include "BLI_math.h" #include "BLI_string.h" #include "BLI_rand.h" -#if DO_PROFILE - #include "PIL_time.h" -#endif - #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" @@ -58,6 +52,13 @@ #include "MOD_util.h" #include "MOD_weightvg_util.h" +// #define USE_TIMEIT + +#ifdef USE_TIMEIT +# include "PIL_time.h" +# include "PIL_time_utildefines.h" +#endif + /************************************** * Util functions. * **************************************/ @@ -382,8 +383,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der int do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview); #endif -#if DO_PROFILE - TIMEIT_START(perf) +#ifdef USE_TIMEIT + TIMEIT_START(perf); #endif /* Get number of verts. */ @@ -548,8 +549,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der MEM_freeN(indices); MEM_freeN(v_cos); -#if DO_PROFILE - TIMEIT_END(perf) +#ifdef USE_TIMEIT + TIMEIT_END(perf); #endif /* Return the vgroup-modified mesh. */ diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 64261246e3d..61c8cb5655d 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -92,6 +92,7 @@ set(SRC composite/nodes/node_composite_normal.c composite/nodes/node_composite_normalize.c composite/nodes/node_composite_outputFile.c + composite/nodes/node_composite_planetrackdeform.c composite/nodes/node_composite_premulkey.c composite/nodes/node_composite_rgb.c composite/nodes/node_composite_rotate.c @@ -163,6 +164,7 @@ set(SRC shader/nodes/node_shader_bsdf_translucent.c shader/nodes/node_shader_bsdf_transparent.c shader/nodes/node_shader_bsdf_velvet.c + shader/nodes/node_shader_bsdf_hair.c shader/nodes/node_shader_bump.c shader/nodes/node_shader_emission.c shader/nodes/node_shader_fresnel.c diff --git a/source/blender/nodes/NOD_common.h b/source/blender/nodes/NOD_common.h index ac0ceab36d4..a8279b4c66a 100644 --- a/source/blender/nodes/NOD_common.h +++ b/source/blender/nodes/NOD_common.h @@ -29,8 +29,8 @@ * \ingroup nodes */ -#ifndef NOD_COMMON_H -#define NOD_COMMON_H +#ifndef __NOD_COMMON_H__ +#define __NOD_COMMON_H__ #include "BKE_node.h" @@ -51,4 +51,4 @@ struct bNodeSocket *node_group_output_find_socket(struct bNode *node, const char void node_group_input_verify(struct bNodeTree *ntree, struct bNode *node, struct ID *id); void node_group_output_verify(struct bNodeTree *ntree, struct bNode *node, struct ID *id); -#endif +#endif /* __NOD_COMMON_H__ */ diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index 626e7955b08..78265154125 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -42,8 +42,6 @@ extern struct bNodeTreeType *ntreeType_Composite; void register_node_tree_type_cmp(void); void register_node_type_cmp_group(void); -void register_node_type_cmp_forloop(void); -void register_node_type_cmp_whileloop(void); void register_node_type_cmp_rlayers(void); void register_node_type_cmp_image(void); @@ -137,6 +135,7 @@ void register_node_type_cmp_bokehblur(void); void register_node_type_cmp_switch(void); void register_node_type_cmp_pixelate(void); void register_node_type_cmp_trackpos(void); +void register_node_type_cmp_planetrackdeform(void); void node_cmp_rlayers_force_hidden_passes(struct bNode *node); diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index ec39d81618d..853046a2a23 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -43,8 +43,6 @@ extern struct bNodeTreeType *ntreeType_Shader; void register_node_tree_type_sh(void); void register_node_type_sh_group(void); -void register_node_type_sh_forloop(void); -void register_node_type_sh_whileloop(void); void register_node_type_sh_output(void); void register_node_type_sh_material(void); @@ -108,6 +106,7 @@ void register_node_type_sh_emission(void); void register_node_type_sh_holdout(void); void register_node_type_sh_volume_transparent(void); void register_node_type_sh_volume_isotropic(void); +void register_node_type_sh_bsdf_hair(void); void register_node_type_sh_subsurface_scattering(void); void register_node_type_sh_mix_shader(void); void register_node_type_sh_add_shader(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 0b526fcde0e..db9f710b6cf 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -85,7 +85,8 @@ DefNode( ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BS DefNode( ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_TOON, def_toon, "BSDF_TOON", BsdfToon, "Toon BSDF", "" ) -DefNode( ShaderNode, SH_NODE_SUBSURFACE_SCATTERING, 0, "SUBSURFACE_SCATTERING",SubsurfaceScattering,"Subsurface Scattering","") +DefNode( ShaderNode, SH_NODE_BSDF_HAIR, def_hair, "BSDF_HAIR", BsdfHair, "Hair BSDF", "" ) +DefNode( ShaderNode, SH_NODE_SUBSURFACE_SCATTERING, def_sh_subsurface, "SUBSURFACE_SCATTERING",SubsurfaceScattering,"Subsurface Scattering","") DefNode( ShaderNode, SH_NODE_VOLUME_TRANSPARENT, 0, "VOLUME_TRANSPARENT", VolumeTransparent,"Transparent Volume","" ) DefNode( ShaderNode, SH_NODE_VOLUME_ISOTROPIC, 0, "VOLUME_ISOTROPIC", VolumeIsotropic, "Isotropic Volume", "" ) DefNode( ShaderNode, SH_NODE_EMISSION, 0, "EMISSION", Emission, "Emission", "" ) @@ -141,7 +142,8 @@ DefNode( CompositorNode, CMP_NODE_HUE_SAT, def_cmp_hue_saturation, "HUE_S DefNode( CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" ) DefNode( CompositorNode, CMP_NODE_R_LAYERS, def_cmp_render_layers, "R_LAYERS", RLayers, "Render Layers", "" ) DefNode( CompositorNode, CMP_NODE_COMPOSITE, def_cmp_composite, "COMPOSITE", Composite, "Composite", "" ) -DefNode( CompositorNode, CMP_NODE_OUTPUT_FILE, def_cmp_output_file, "OUTPUT_FILE", OutputFile, "File Output", "" ) +/* NB: OutputFile node has special rna setup function called in rna_nodetree.c */ +DefNode( CompositorNode, CMP_NODE_OUTPUT_FILE, 0, "OUTPUT_FILE", OutputFile, "File Output", "" ) DefNode( CompositorNode, CMP_NODE_TEXTURE, def_texture, "TEXTURE", Texture, "Texture", "" ) DefNode( CompositorNode, CMP_NODE_TRANSLATE, def_cmp_translate, "TRANSLATE", Translate, "Translate", "" ) DefNode( CompositorNode, CMP_NODE_ZCOMBINE, def_cmp_zcombine, "ZCOMBINE", Zcombine, "Z Combine", "" ) @@ -200,6 +202,7 @@ DefNode( CompositorNode, CMP_NODE_KEYINGSCREEN, def_cmp_keyingscreen, "KEYIN DefNode( CompositorNode, CMP_NODE_KEYING, def_cmp_keying, "KEYING", Keying, "Keying", "" ) DefNode( CompositorNode, CMP_NODE_TRACKPOS, def_cmp_trackpos, "TRACKPOS", TrackPos, "Track Position", "" ) DefNode( CompositorNode, CMP_NODE_PIXELATE, 0, "PIXELATE", Pixelate, "Pixelate", "" ) +DefNode( CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" ) DefNode( TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" ) DefNode( TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" ) diff --git a/source/blender/nodes/NOD_texture.h b/source/blender/nodes/NOD_texture.h index ea003f23960..378c96d5882 100644 --- a/source/blender/nodes/NOD_texture.h +++ b/source/blender/nodes/NOD_texture.h @@ -42,8 +42,6 @@ extern struct bNodeTreeType *ntreeType_Texture; void register_node_tree_type_tex(void); void register_node_type_tex_group(void); -void register_node_type_tex_forloop(void); -void register_node_type_tex_whileloop(void); void register_node_type_tex_math(void); void register_node_type_tex_mix_rgb(void); diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c index 0b62481b2f7..31ae46468c3 100644 --- a/source/blender/nodes/composite/node_composite_tree.c +++ b/source/blender/nodes/composite/node_composite_tree.c @@ -318,38 +318,22 @@ static int node_animation_properties(bNodeTree *ntree, bNode *node) lb = RNA_struct_type_properties(ptr.type); for (link = lb->first; link; link = link->next) { - int len = 1, index; - bool driven; prop = (PropertyRNA *)link; - if (RNA_property_array_check(prop)) - len = RNA_property_array_length(&ptr, prop); - - for (index = 0; index < len; index++) { - if (rna_get_fcurve(&ptr, prop, index, NULL, &driven)) { - nodeUpdate(ntree, node); - return 1; - } + if (RNA_property_animated(&ptr, prop)) { + nodeUpdate(ntree, node); + return 1; } } /* now check node sockets */ for (sock = node->inputs.first; sock; sock = sock->next) { - int len = 1, index; - bool driven; - RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); prop = RNA_struct_find_property(&ptr, "default_value"); - if (prop) { - if (RNA_property_array_check(prop)) - len = RNA_property_array_length(&ptr, prop); - - for (index = 0; index < len; index++) { - if (rna_get_fcurve(&ptr, prop, index, NULL, &driven)) { - nodeUpdate(ntree, node); - return 1; - } - } + + if (RNA_property_animated(&ptr, prop)) { + nodeUpdate(ntree, node); + return 1; } } diff --git a/source/blender/nodes/composite/nodes/node_composite_mapValue.c b/source/blender/nodes/composite/nodes/node_composite_mapValue.c index 316e5b344ce..22d16e93879 100644 --- a/source/blender/nodes/composite/nodes/node_composite_mapValue.c +++ b/source/blender/nodes/composite/nodes/node_composite_mapValue.c @@ -44,7 +44,7 @@ static bNodeSocketTemplate cmp_node_map_value_out[] = { static void node_composit_init_map_value(bNodeTree *UNUSED(ntree), bNode *node) { - node->storage = add_tex_mapping(); + node->storage = add_tex_mapping(TEXMAP_TYPE_POINT); } void register_node_type_cmp_map_value(void) diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c index 90b21f1bab0..89c6fbe4590 100644 --- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c +++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c @@ -225,9 +225,24 @@ static void copy_output_file(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, bN static void update_output_file(bNodeTree *ntree, bNode *node) { - bNodeSocket *sock; + bNodeSocket *sock, *sock_next; PointerRNA ptr; + /* XXX fix for #36706: remove invalid sockets added with bpy API. + * This is not ideal, but prevents crashes from missing storage. + * FileOutput node needs a redesign to support this properly. + */ + for (sock = node->inputs.first; sock; sock = sock_next) { + sock_next = sock->next; + if (sock->storage == NULL) { + nodeRemoveSocket(ntree, node, sock); + } + } + for (sock = node->outputs.first; sock; sock = sock_next) { + sock_next = sock->next; + nodeRemoveSocket(ntree, node, sock); + } + cmp_node_update_default(ntree, node); /* automatically update the socket type based on linked input */ diff --git a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c new file mode 100644 index 00000000000..7a15d6364dc --- /dev/null +++ b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c @@ -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. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation, + * Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/nodes/composite/nodes/node_composite_planetrackdeform.c + * \ingroup cmpnodes + */ + + +#include "node_composite_util.h" + +static bNodeSocketTemplate cmp_node_planetrackdeform_in[] = { + { SOCK_RGBA, 1, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE}, + { -1, 0, "" } +}; + +static bNodeSocketTemplate cmp_node_planetrackdeform_out[] = { + { SOCK_RGBA, 0, N_("Image")}, + { SOCK_FLOAT, 0, N_("Plane")}, + { -1, 0, "" } +}; + +static void init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodePlaneTrackDeformData *data = MEM_callocN(sizeof(NodePlaneTrackDeformData), "node plane track deform data"); + + node->storage = data; +} + +void register_node_type_cmp_planetrackdeform(void) +{ + static bNodeType ntype; + + cmp_node_type_base(&ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT, 0); + node_type_socket_templates(&ntype, cmp_node_planetrackdeform_in, cmp_node_planetrackdeform_out); + node_type_init(&ntype, init); + node_type_storage(&ntype, "NodePlaneTrackDeformData", node_free_standard_storage, node_copy_standard_storage); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.c b/source/blender/nodes/composite/nodes/node_composite_scale.c index 134402c00e1..8041a2e56e9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_scale.c +++ b/source/blender/nodes/composite/nodes/node_composite_scale.c @@ -45,12 +45,31 @@ static bNodeSocketTemplate cmp_node_scale_out[] = { { -1, 0, "" } }; +static void node_composite_update_scale(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sock; + bool use_xy_scale = ELEM(node->custom1, CMP_SCALE_RELATIVE, CMP_SCALE_ABSOLUTE); + + /* Only show X/Y scale factor inputs for modes using them! */ + for (sock = node->inputs.first; sock; sock = sock->next) { + if (STREQ(sock->name, "X") || STREQ(sock->name, "Y")) { + if (use_xy_scale) { + sock->flag &= ~SOCK_UNAVAIL; + } + else { + sock->flag |= SOCK_UNAVAIL; + } + } + } +} + void register_node_type_cmp_scale(void) { static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0); node_type_socket_templates(&ntype, cmp_node_scale_in, cmp_node_scale_out); + node_type_update(&ntype, node_composite_update_scale, NULL); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c index 2b6318679e0..812fe5b4ae7 100644 --- a/source/blender/nodes/intern/node_exec.c +++ b/source/blender/nodes/intern/node_exec.c @@ -287,8 +287,8 @@ void ntreeReleaseThreadStack(bNodeThreadStack *nts) bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *callerdata, int thread) { - bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ - bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ + bNodeStack *nsin[MAX_SOCKET] = {NULL}; /* arbitrary... watch this */ + bNodeStack *nsout[MAX_SOCKET] = {NULL}; /* arbitrary... watch this */ bNodeExec *nodeexec; bNode *node; int n; diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index f9a450174a3..e77f0a08331 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -112,86 +112,54 @@ const char *node_filter_label(bNode *node) void node_update_internal_links_default(bNodeTree *ntree, bNode *node) { - bNodeSocket *fromsock_first = NULL, *tosock_first = NULL; /* used for fallback link if no other reconnections are found */ - int datatype; - int num_links_in = 0, num_links_out = 0, num_reconnect = 0; + bNodeLink *link; + bNodeSocket *output, *input, *selected; - /* Security check! */ + /* sanity check */ if (!ntree) return; - for (datatype = 0; datatype < NUM_SOCKET_TYPES; ++datatype) { - bNodeSocket *fromsock, *tosock; - int fromindex, toindex; - bNodeLink *link; - - /* Connect the first input of each type with outputs of the same type. */ + /* use link pointer as a tag for handled sockets (for outputs is unused anyway) */ + for (output = node->outputs.first; output; output = output->next) + output->link = NULL; + + for (link = ntree->links.first; link; link = link->next) { + output = link->fromsock; + if (link->fromnode != node || output->link) + continue; + output->link = link; /* not really used, just for tagging handled sockets */ - fromindex = INT_MAX; - fromsock = NULL; - for (link = ntree->links.first; link; link = link->next) { - if (nodeLinkIsHidden(link)) - continue; - if (link->tonode == node && link->tosock->type == datatype) { - int index = BLI_findindex(&node->inputs, link->tosock); - if (index < fromindex) { - fromindex = index; - fromsock = link->tosock; + /* look for suitable input */ + selected = NULL; + for (input = node->inputs.first; input; input = input->next) { + /* only use if same type */ + if (input->type == output->type) { + if (!selected) { + selected = input; } - } - } - if (fromsock) { - ++num_links_in; - if (!fromsock_first) - fromsock_first = fromsock; - } - - toindex = INT_MAX; - tosock = NULL; - for (link = ntree->links.first; link; link = link->next) { - if (nodeLinkIsHidden(link)) - continue; - if (link->fromnode == node && link->fromsock->type == datatype) { - int index = BLI_findindex(&node->outputs, link->fromsock); - if (index < toindex) { - toindex = index; - tosock = link->fromsock; + else { + /* linked inputs preferred */ + if (input->link && !selected->link) + selected = input; } } } - if (tosock) { - ++num_links_out; - if (!tosock_first) - tosock_first = tosock; - - if (fromsock) { - bNodeLink *ilink = MEM_callocN(sizeof(bNodeLink), "internal node link"); - ilink->fromnode = node; - ilink->fromsock = fromsock; - ilink->tonode = node; - ilink->tosock = tosock; - /* internal link is always valid */ - ilink->flag |= NODE_LINK_VALID; - BLI_addtail(&node->internal_links, ilink); - - ++num_reconnect; - } + + if (selected) { + bNodeLink *ilink = MEM_callocN(sizeof(bNodeLink), "internal node link"); + ilink->fromnode = node; + ilink->fromsock = selected; + ilink->tonode = node; + ilink->tosock = output; + /* internal link is always valid */ + ilink->flag |= NODE_LINK_VALID; + BLI_addtail(&node->internal_links, ilink); } } - /* if there is one input and one output link, but no reconnections by type, - * simply connect those two sockets. - */ - if ((num_reconnect == 0) && (num_links_in == 1) && (num_links_out == 1)) { - bNodeLink *ilink = MEM_callocN(sizeof(bNodeLink), "internal node link"); - ilink->fromnode = node; - ilink->fromsock = fromsock_first; - ilink->tonode = node; - ilink->tosock = tosock_first; - /* internal link is always valid */ - ilink->flag |= NODE_LINK_VALID; - BLI_addtail(&node->internal_links, ilink); - } + /* clean up */ + for (output = node->outputs.first; output; output = output->next) + output->link = NULL; } float node_socket_get_float(bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock) diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 134a5c9575f..1e828ea321c 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -189,13 +189,16 @@ void register_node_tree_type_sh(void) void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat) { + /* localize tree to create links for reroute and mute */ + bNodeTree *localtree = ntreeLocalize(ntree); bNodeTreeExec *exec; - exec = ntreeShaderBeginExecTree(ntree); - + exec = ntreeShaderBeginExecTree(localtree); ntreeExecGPUNodes(exec, mat, 1); - ntreeShaderEndExecTree(exec); + + ntreeFreeTree_ex(localtree, false); + MEM_freeN(localtree); } /* **************** call to switch lamploop for material node ************ */ diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c index f6ecb3e0b72..86e59cd779a 100644 --- a/source/blender/nodes/shader/node_shader_util.c +++ b/source/blender/nodes/shader/node_shader_util.c @@ -195,25 +195,28 @@ static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNode bNode *nodeGetActiveTexture(bNodeTree *ntree) { /* this is the node we texture paint and draw in textured draw */ - bNode *node, *tnode; + bNode *node, *tnode, *inactivenode = NULL; if (!ntree) return NULL; - for (node = ntree->nodes.first; node; node = node->next) + for (node = ntree->nodes.first; node; node = node->next) { if (node->flag & NODE_ACTIVE_TEXTURE) return node; + else if (!inactivenode && node->typeinfo->nclass == NODE_CLASS_TEXTURE) + inactivenode = node; + } /* node active texture node in this tree, look inside groups */ for (node = ntree->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP) { tnode = nodeGetActiveTexture((bNodeTree *)node->id); - if (tnode) + if (tnode && ((tnode->flag & NODE_ACTIVE_TEXTURE) || !inactivenode)) return tnode; } } - return NULL; + return inactivenode; } void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, int do_outputs) @@ -268,6 +271,9 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in GPUNodeLink *tdomax = GPU_uniform(&domax); GPU_link(mat, "mapping", in[0].link, tmat, tmin, tmax, tdomin, tdomax, &in[0].link); + + if (texmap->type == TEXMAP_TYPE_NORMAL) + GPU_link(mat, "texco_norm", in[0].link, &in[0].link); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c new file mode 100644 index 00000000000..ba33a262548 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c @@ -0,0 +1,66 @@ +/* + * ***** 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) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../node_shader_util.h" + +/* **************** OUTPUT ******************** */ + +static bNodeSocketTemplate sh_node_bsdf_hair_in[] = { + { SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 1, N_("Offset"), 0.0f, 0.0f, 0.0f, 0.0f, -M_PI_2, M_PI_2, PROP_ANGLE}, + { SOCK_FLOAT, 1, N_("RoughnessU"), 0.1f, 0.1f, 0.1f, 0.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 1, N_("RoughnessV"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f}, { -1, 0, "" } +}; + +static bNodeSocketTemplate sh_node_bsdf_hair_out[] = { + { SOCK_SHADER, 0, N_("BSDF")}, + { -1, 0, "" } +}; + +static int node_shader_gpu_bsdf_hair(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + if (!in[2].link) + in[2].link = GPU_builtin(GPU_VIEW_NORMAL); + + return GPU_stack_link(mat, "node_bsdf_hair", in, out); +} + +/* node type definition */ +void register_node_type_sh_bsdf_hair(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR, "Hair BSDF", NODE_CLASS_SHADER, 0); + node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_socket_templates(&ntype, sh_node_bsdf_hair_in, sh_node_bsdf_hair_out); + node_type_size(&ntype, 150, 60, 200); + node_type_init(&ntype, NULL); + node_type_storage(&ntype, "", NULL, NULL); + node_type_gpu(&ntype, node_shader_gpu_bsdf_hair); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c index fad1a69d364..9956fd712c8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_gamma.c +++ b/source/blender/nodes/shader/nodes/node_shader_gamma.c @@ -41,6 +41,11 @@ static bNodeSocketTemplate sh_node_gamma_out[] = { { -1, 0, "" } }; +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); +} + void register_node_type_sh_gamma(void) { static bNodeType ntype; @@ -50,6 +55,7 @@ void register_node_type_sh_gamma(void) 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_gpu(&ntype, node_shader_gpu_gamma); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c index 05936e22775..cff4a039602 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mapping.c +++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c @@ -29,7 +29,6 @@ * \ingroup shdnodes */ - #include "node_shader_util.h" /* **************** MAPPING ******************** */ @@ -53,7 +52,7 @@ static void node_shader_exec_mapping(void *UNUSED(data), int UNUSED(thread), bNo /* stack order output: vector */ nodestack_get_vec(vec, SOCK_VECTOR, in[0]); mul_m4_v3(texmap->mat, vec); - + if (texmap->flag & TEXMAP_CLIP_MIN) { if (vec[0] < texmap->min[0]) vec[0] = texmap->min[0]; if (vec[1] < texmap->min[1]) vec[1] = texmap->min[1]; @@ -64,12 +63,15 @@ static void node_shader_exec_mapping(void *UNUSED(data), int UNUSED(thread), bNo if (vec[1] > texmap->max[1]) vec[1] = texmap->max[1]; if (vec[2] > texmap->max[2]) vec[2] = texmap->max[2]; } + + if (texmap->type == TEXMAP_TYPE_NORMAL) + normalize_v3(vec); } static void node_shader_init_mapping(bNodeTree *UNUSED(ntree), bNode *node) { - node->storage = add_tex_mapping(); + node->storage = add_tex_mapping(TEXMAP_TYPE_POINT); } static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) @@ -83,7 +85,12 @@ static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS GPUNodeLink *tdomin = GPU_uniform(&domin); GPUNodeLink *tdomax = GPU_uniform(&domax); - return GPU_stack_link(mat, "mapping", in, out, tmat, tmin, tmax, tdomin, tdomax); + int result = GPU_stack_link(mat, "mapping", in, out, tmat, tmin, tmax, tdomin, tdomax); + + if (result && texmap->type == TEXMAP_TYPE_NORMAL) + GPU_link(mat, "texco_norm", out[0].link, &out[0].link); + + return result; } void register_node_type_sh_mapping(void) diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c index 3bdc3813fd7..fd864f1c7c6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c +++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c @@ -30,11 +30,12 @@ /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_subsurface_scattering_in[] = { - { SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, - { SOCK_FLOAT, 1, N_("Scale"), 1.0, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, - { SOCK_VECTOR, 1, N_("Radius"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f}, - //{ SOCK_FLOAT, 1, N_("IOR"), 1.3f, 0.0f, 0.0f, 0.0f, 1.0f, 1000.0f}, - { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + { SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 1, N_("Scale"), 1.0, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, + { SOCK_VECTOR, 1, N_("Radius"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f}, + { SOCK_FLOAT, 1, N_("Sharpness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("Texture Blur"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, { -1, 0, "" } }; @@ -43,6 +44,20 @@ static bNodeSocketTemplate sh_node_subsurface_scattering_out[] = { { -1, 0, "" } }; +static void node_shader_init_subsurface_scattering(bNodeTree *UNUSED(ntree), bNode *node) +{ + /*bNodeSocket *sock;*/ + + node->custom1 = SHD_SUBSURFACE_CUBIC; + + /*for (sock = node->inputs.first; sock; sock = sock->next) { + if (strcmp(sock->name, "Sharpness") == 0) { + bNodeSocketValueFloat *dval = sock->default_value; + dval->value = 0.0f; + } + }*/ +} + static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[1].link) @@ -51,6 +66,22 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat, bNode *UNUSED return GPU_stack_link(mat, "node_subsurface_scattering", in, out); } +static void node_shader_update_subsurface_scattering(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sock; + int falloff = node->custom1; + + for (sock = node->inputs.first; sock; sock = sock->next) { + if (strcmp(sock->name, "Sharpness") == 0) { + if (falloff == SHD_SUBSURFACE_CUBIC) + sock->flag &= ~SOCK_UNAVAIL; + else + sock->flag |= SOCK_UNAVAIL; + + } + } +} + /* node type definition */ void register_node_type_sh_subsurface_scattering(void) { @@ -60,9 +91,10 @@ void register_node_type_sh_subsurface_scattering(void) node_type_compatibility(&ntype, NODE_NEW_SHADING); node_type_socket_templates(&ntype, sh_node_subsurface_scattering_in, sh_node_subsurface_scattering_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, NULL); + node_type_init(&ntype, node_shader_init_subsurface_scattering); node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_subsurface_scattering); + node_type_update(&ntype, node_shader_update_subsurface_scattering, NULL); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c index 826b7d9337d..12da301d090 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c @@ -51,7 +51,7 @@ static bNodeSocketTemplate sh_node_tex_brick_out[] = { static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node) { NodeTexBrick *tex = MEM_callocN(sizeof(NodeTexBrick), "NodeTexBrick"); - default_tex_mapping(&tex->base.tex_mapping); + default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); default_color_mapping(&tex->base.color_mapping); tex->offset = 0.5f; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c index ceb3911f429..725b5654523 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.c @@ -46,7 +46,7 @@ static bNodeSocketTemplate sh_node_tex_checker_out[] = { static void node_shader_init_tex_checker(bNodeTree *UNUSED(ntree), bNode *node) { NodeTexChecker *tex = MEM_callocN(sizeof(NodeTexChecker), "NodeTexChecker"); - default_tex_mapping(&tex->base.tex_mapping); + default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); default_color_mapping(&tex->base.color_mapping); node->storage = tex; 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 2fbf5b6faf9..5e6471eab77 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c @@ -44,7 +44,7 @@ static bNodeSocketTemplate sh_node_tex_environment_out[] = { static void node_shader_init_tex_environment(bNodeTree *UNUSED(ntree), bNode *node) { NodeTexEnvironment *tex = MEM_callocN(sizeof(NodeTexEnvironment), "NodeTexEnvironment"); - default_tex_mapping(&tex->base.tex_mapping); + default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); default_color_mapping(&tex->base.color_mapping); tex->color_space = SHD_COLORSPACE_COLOR; tex->projection = SHD_PROJ_EQUIRECTANGULAR; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c index 5ee3b1f6176..c3ef897b1ad 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.c @@ -43,7 +43,7 @@ static bNodeSocketTemplate sh_node_tex_gradient_out[] = { static void node_shader_init_tex_gradient(bNodeTree *UNUSED(ntree), bNode *node) { NodeTexGradient *tex = MEM_callocN(sizeof(NodeTexGradient), "NodeTexGradient"); - default_tex_mapping(&tex->base.tex_mapping); + default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); default_color_mapping(&tex->base.color_mapping); tex->gradient_type = SHD_BLEND_LINEAR; 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 53c44ebd715..1b705e12daf 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c @@ -45,7 +45,7 @@ static bNodeSocketTemplate sh_node_tex_image_out[] = { static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node) { NodeTexImage *tex = MEM_callocN(sizeof(NodeTexImage), "NodeTexImage"); - default_tex_mapping(&tex->base.tex_mapping); + default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); default_color_mapping(&tex->base.color_mapping); tex->color_space = SHD_COLORSPACE_COLOR; tex->iuser.frames = 1; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c index 38292939a3c..b9339bc483f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.c @@ -45,7 +45,7 @@ static bNodeSocketTemplate sh_node_tex_magic_out[] = { static void node_shader_init_tex_magic(bNodeTree *UNUSED(ntree), bNode *node) { NodeTexMagic *tex = MEM_callocN(sizeof(NodeTexMagic), "NodeTexMagic"); - default_tex_mapping(&tex->base.tex_mapping); + default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); default_color_mapping(&tex->base.color_mapping); tex->depth = 2; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c index b41cc7d8812..2b5d5e12420 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c @@ -49,7 +49,7 @@ static bNodeSocketTemplate sh_node_tex_musgrave_out[] = { static void node_shader_init_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node) { NodeTexMusgrave *tex = MEM_callocN(sizeof(NodeTexMusgrave), "NodeTexMusgrave"); - default_tex_mapping(&tex->base.tex_mapping); + default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); default_color_mapping(&tex->base.color_mapping); tex->musgrave_type = SHD_MUSGRAVE_FBM; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c index a7009b81e9a..36e26925501 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c @@ -46,7 +46,7 @@ static bNodeSocketTemplate sh_node_tex_noise_out[] = { static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node) { NodeTexNoise *tex = MEM_callocN(sizeof(NodeTexNoise), "NodeTexNoise"); - default_tex_mapping(&tex->base.tex_mapping); + default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); default_color_mapping(&tex->base.color_mapping); node->storage = tex; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c index f9cd4b72912..22061979b12 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c @@ -42,12 +42,14 @@ static bNodeSocketTemplate sh_node_tex_sky_out[] = { static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node) { NodeTexSky *tex = MEM_callocN(sizeof(NodeTexSky), "NodeTexSky"); - default_tex_mapping(&tex->base.tex_mapping); + default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); default_color_mapping(&tex->base.color_mapping); tex->sun_direction[0] = 0.0f; tex->sun_direction[1] = 0.0f; tex->sun_direction[2] = 1.0f; tex->turbidity = 2.2f; + tex->ground_albedo = 0.3f; + tex->sky_model = SHD_SKY_NEW; node->storage = tex; } @@ -70,6 +72,7 @@ void register_node_type_sh_tex_sky(void) sh_node_type_base(&ntype, SH_NODE_TEX_SKY, "Sky Texture", NODE_CLASS_TEXTURE, 0); node_type_compatibility(&ntype, NODE_NEW_SHADING); node_type_socket_templates(&ntype, sh_node_tex_sky_in, sh_node_tex_sky_out); + node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_init(&ntype, node_shader_init_tex_sky); node_type_storage(&ntype, "NodeTexSky", node_free_standard_storage, node_copy_standard_storage); node_type_gpu(&ntype, node_shader_gpu_tex_sky); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c index 3f1b0638b99..f75c05601aa 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c @@ -44,7 +44,7 @@ static bNodeSocketTemplate sh_node_tex_voronoi_out[] = { static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node) { NodeTexVoronoi *tex = MEM_callocN(sizeof(NodeTexVoronoi), "NodeTexVoronoi"); - default_tex_mapping(&tex->base.tex_mapping); + default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); default_color_mapping(&tex->base.color_mapping); tex->coloring = SHD_VORONOI_INTENSITY; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c index a424265c94a..be7df85fbee 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c @@ -47,7 +47,7 @@ static bNodeSocketTemplate sh_node_tex_wave_out[] = { static void node_shader_init_tex_wave(bNodeTree *UNUSED(ntree), bNode *node) { NodeTexWave *tex = MEM_callocN(sizeof(NodeTexWave), "NodeTexWave"); - default_tex_mapping(&tex->base.tex_mapping); + default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); default_color_mapping(&tex->base.color_mapping); tex->wave_type = SHD_WAVE_BANDS; diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c index 6ab8d27f6e6..fec6abbf062 100644 --- a/source/blender/nodes/texture/nodes/node_texture_common.c +++ b/source/blender/nodes/texture/nodes/node_texture_common.c @@ -93,9 +93,12 @@ static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack) for (node = ngroup->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP_INPUT) { for (sock = node->outputs.first, a = 0; sock; sock = sock->next, ++a) { - ns = node_get_socket_stack(gstack, sock); - if (ns) - copy_stack(ns, in[a]); + if (in[a]) { /* shouldn't need to check this [#36694] */ + ns = node_get_socket_stack(gstack, sock); + if (ns) { + copy_stack(ns, in[a]); + } + } } } } @@ -114,9 +117,12 @@ static void group_copy_outputs(bNode *gnode, bNodeStack **out, bNodeStack *gstac for (node = ngroup->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) { for (sock = node->inputs.first, a = 0; sock; sock = sock->next, ++a) { - ns = node_get_socket_stack(gstack, sock); - if (ns) - copy_stack(out[a], ns); + if (out[a]) { /* shouldn't need to check this [#36694] */ + ns = node_get_socket_stack(gstack, sock); + if (ns) { + copy_stack(out[a], ns); + } + } } break; /* only one active output node */ } diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c index 6c7fc686cc0..ec9f2865582 100644 --- a/source/blender/python/bmesh/bmesh_py_ops_call.c +++ b/source/blender/python/bmesh/bmesh_py_ops_call.c @@ -581,11 +581,11 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot) item = PyDict_New(); if (slot_hash) { GHASH_ITER (hash_iter, slot_hash) { - BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter); - BMOElemMapping *ele_val = BLI_ghashIterator_getValue(&hash_iter); + BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter); + void *ele_val = BLI_ghashIterator_getValue(&hash_iter); - PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key); - PyObject *py_val = BPy_BMElem_CreatePyObject(bm, *(void **)BMO_OP_SLOT_MAPPING_DATA(ele_val)); + PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key); + PyObject *py_val = BPy_BMElem_CreatePyObject(bm, ele_val); PyDict_SetItem(item, py_key, py_val); Py_DECREF(py_key); @@ -599,11 +599,11 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot) item = PyDict_New(); if (slot_hash) { GHASH_ITER (hash_iter, slot_hash) { - BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter); - BMOElemMapping *ele_val = BLI_ghashIterator_getValue(&hash_iter); + BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter); + void *ele_val = BLI_ghashIterator_getValue(&hash_iter); PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key); - PyObject *py_val = PyFloat_FromDouble(*(float *)BMO_OP_SLOT_MAPPING_DATA(ele_val)); + PyObject *py_val = PyFloat_FromDouble(*(float *)&ele_val); PyDict_SetItem(item, py_key, py_val); Py_DECREF(py_key); @@ -617,11 +617,11 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot) item = PyDict_New(); if (slot_hash) { GHASH_ITER (hash_iter, slot_hash) { - BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter); - BMOElemMapping *ele_val = BLI_ghashIterator_getValue(&hash_iter); + BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter); + void *ele_val = BLI_ghashIterator_getValue(&hash_iter); PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key); - PyObject *py_val = PyLong_FromLong(*(int *)BMO_OP_SLOT_MAPPING_DATA(ele_val)); + PyObject *py_val = PyLong_FromLong(*(int *)&ele_val); PyDict_SetItem(item, py_key, py_val); Py_DECREF(py_key); @@ -635,11 +635,11 @@ static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot) item = PyDict_New(); if (slot_hash) { GHASH_ITER (hash_iter, slot_hash) { - BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter); - BMOElemMapping *ele_val = BLI_ghashIterator_getValue(&hash_iter); + BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter); + void *ele_val = BLI_ghashIterator_getValue(&hash_iter); PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key); - PyObject *py_val = PyBool_FromLong(*(int *)BMO_OP_SLOT_MAPPING_DATA(ele_val)); + PyObject *py_val = PyBool_FromLong(*(int *)&ele_val); PyDict_SetItem(item, py_key, py_val); Py_DECREF(py_key); diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index 0e2fbe8a526..92fb506497f 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -122,12 +122,12 @@ static int bpy_bm_elem_hflag_set(BPy_BMElem *self, PyObject *value, void *flag) param = PyLong_AsLong(value); - if (param == true) { - BM_elem_flag_enable(self->ele, hflag); - return 0; - } - else if (param == false) { - BM_elem_flag_disable(self->ele, hflag); + if ((unsigned int)param <= 1) { + if (hflag == BM_ELEM_SELECT) + BM_elem_select_set(self->bm, self->ele, param); + else + BM_elem_flag_set(self->ele, hflag, param); + return 0; } else { @@ -1047,6 +1047,8 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject * int use_shape_key = false; int shape_key_index = 0; + BPY_BM_CHECK_OBJ(self); + if (!PyArg_ParseTupleAndKeywords(args, kw, "O|iii:from_mesh", (char **)kwlist, &py_mesh, &use_fnorm, &use_shape_key, &shape_key_index) || !(me = PyC_RNA_AsPointer(py_mesh, "Mesh"))) @@ -1871,7 +1873,7 @@ static PyObject *bpy_bmvertseq_new(BPy_BMElemSeq *self, PyObject *args) return NULL; } - v = BM_vert_create(bm, co, NULL, 0); + v = BM_vert_create(bm, co, NULL, BM_CREATE_NOP); if (v == NULL) { PyErr_SetString(PyExc_ValueError, @@ -1940,7 +1942,7 @@ static PyObject *bpy_bmedgeseq_new(BPy_BMElemSeq *self, PyObject *args) goto cleanup; } - e = BM_edge_create(bm, vert_array[0], vert_array[1], NULL, 0); + e = BM_edge_create(bm, vert_array[0], vert_array[1], NULL, BM_CREATE_NOP); if (e == NULL) { PyErr_SetString(PyExc_ValueError, @@ -2020,7 +2022,8 @@ static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args) /* Go ahead and make the face! * --------------------------- */ - f_new = BM_face_create_ngon_verts(bm, vert_array, vert_seq_len, 0, false, true); + f_new = BM_face_create_verts(bm, vert_array, vert_seq_len, + py_face_example ? py_face_example->f : NULL, BM_CREATE_NOP, true); if (UNLIKELY(f_new == NULL)) { PyErr_SetString(PyExc_ValueError, @@ -2028,10 +2031,6 @@ static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args) goto cleanup; } - if (py_face_example) { - BM_elem_attrs_copy(py_face_example->bm, bm, py_face_example->f, f_new); - } - ret = BPy_BMFace_CreatePyObject(bm, f_new); /* pass through */ @@ -2921,7 +2920,8 @@ static void bpy_bmvert_dealloc(BPy_BMElem *self) BMesh *bm = self->bm; if (bm) { void **ptr = CustomData_bmesh_get(&bm->vdata, self->ele->head.data, CD_BM_ELEM_PYPTR); - *ptr = NULL; + if (ptr) + *ptr = NULL; } PyObject_DEL(self); } @@ -2931,7 +2931,8 @@ static void bpy_bmedge_dealloc(BPy_BMElem *self) BMesh *bm = self->bm; if (bm) { void **ptr = CustomData_bmesh_get(&bm->edata, self->ele->head.data, CD_BM_ELEM_PYPTR); - *ptr = NULL; + if (ptr) + *ptr = NULL; } PyObject_DEL(self); } @@ -2941,7 +2942,8 @@ static void bpy_bmface_dealloc(BPy_BMElem *self) BMesh *bm = self->bm; if (bm) { void **ptr = CustomData_bmesh_get(&bm->pdata, self->ele->head.data, CD_BM_ELEM_PYPTR); - *ptr = NULL; + if (ptr) + *ptr = NULL; } PyObject_DEL(self); } @@ -2951,7 +2953,8 @@ static void bpy_bmloop_dealloc(BPy_BMElem *self) BMesh *bm = self->bm; if (bm) { void **ptr = CustomData_bmesh_get(&bm->ldata, self->ele->head.data, CD_BM_ELEM_PYPTR); - *ptr = NULL; + if (ptr) + *ptr = NULL; } PyObject_DEL(self); } diff --git a/source/blender/python/bmesh/bmesh_py_types.h b/source/blender/python/bmesh/bmesh_py_types.h index f02b94be526..0909ce0d26a 100644 --- a/source/blender/python/bmesh/bmesh_py_types.h +++ b/source/blender/python/bmesh/bmesh_py_types.h @@ -27,8 +27,8 @@ * \ingroup pybmesh */ -#ifndef __BMESH_TYPES_H__ -#define __BMESH_TYPES_H__ +#ifndef __BMESH_PY_TYPES_H__ +#define __BMESH_PY_TYPES_H__ extern PyTypeObject BPy_BMesh_Type; extern PyTypeObject BPy_BMVert_Type; @@ -205,4 +205,4 @@ extern struct PyC_FlagSet bpy_bm_htype_all_flags[]; extern struct PyC_FlagSet bpy_bm_hflag_all_flags[]; #endif -#endif /* __BMESH_TYPES_H__ */ +#endif /* __BMESH_PY_TYPES_H__ */ diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c index b0604fa2dbc..30902c615a1 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c @@ -32,6 +32,7 @@ #include <Python.h> +#include "BLI_utildefines.h" #include "BLI_string.h" #include "BLI_math_vector.h" diff --git a/source/blender/python/generic/blf_py_api.h b/source/blender/python/generic/blf_py_api.h index 12bd9bcf019..d856e68faee 100644 --- a/source/blender/python/generic/blf_py_api.h +++ b/source/blender/python/generic/blf_py_api.h @@ -20,9 +20,13 @@ * ***** END GPL LICENSE BLOCK ***** */ +#ifndef __BLF_PY_API_H__ +#define __BLF_PY_API_H__ + /** \file blender/python/generic/blf_py_api.h * \ingroup pygen */ - PyObject *BPyInit_blf(void); + +#endif /* __BLF_PY_API_H__ */ diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index fc4b78b5c05..f7ed5fec891 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -1518,7 +1518,7 @@ void IDP_spit(IDProperty *prop) { if (prop) { PyGILState_STATE gilstate; - int use_gil = TRUE; /* !PYC_INTERPRETER_ACTIVE; */ + int use_gil = TRUE; /* !PyC_IsInterpreterActive(); */ PyObject *ret_dict; PyObject *ret_str; diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 2876d7666f4..63f66afd8a8 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -191,7 +191,7 @@ void PyC_LineSpit(void) int lineno; /* Note, allow calling from outside python (RNA) */ - if (!PYC_INTERPRETER_ACTIVE) { + if (!PyC_IsInterpreterActive()) { fprintf(stderr, "python line lookup failed, interpreter inactive\n"); return; } @@ -205,7 +205,7 @@ void PyC_LineSpit(void) void PyC_StackSpit(void) { /* Note, allow calling from outside python (RNA) */ - if (!PYC_INTERPRETER_ACTIVE) { + if (!PyC_IsInterpreterActive()) { fprintf(stderr, "python line lookup failed, interpreter inactive\n"); return; } @@ -258,7 +258,7 @@ void PyC_FileAndNum(const char **filename, int *lineno) void PyC_FileAndNum_Safe(const char **filename, int *lineno) { - if (!PYC_INTERPRETER_ACTIVE) { + if (!PyC_IsInterpreterActive()) { return; } @@ -599,6 +599,11 @@ void PyC_SetHomePath(const char *py_path_bundle) } } +bool PyC_IsInterpreterActive(void) +{ + return (((PyThreadState *)_Py_atomic_load_relaxed(&_PyThreadState_Current)) != NULL); +} + /* Would be nice if python had this built in * See: http://wiki.blender.org/index.php/Dev:Doc/Tools/Debugging/PyFromC */ diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h index 239858032de..8928642bc3e 100644 --- a/source/blender/python/generic/py_capi_utils.h +++ b/source/blender/python/generic/py_capi_utils.h @@ -56,7 +56,7 @@ void PyC_MainModule_Restore(PyObject *main_mod); void PyC_SetHomePath(const char *py_path_bundle); -#define PYC_INTERPRETER_ACTIVE (((PyThreadState *)_Py_atomic_load_relaxed(&_PyThreadState_Current)) != NULL) +bool PyC_IsInterpreterActive(void); void *PyC_RNA_AsPointer(PyObject *value, const char *type_name); diff --git a/source/blender/python/intern/bpy.h b/source/blender/python/intern/bpy.h index fe877d161ff..b647d0d450c 100644 --- a/source/blender/python/intern/bpy.h +++ b/source/blender/python/intern/bpy.h @@ -24,6 +24,7 @@ */ #ifndef __BPY_H__ +#define __BPY_H__ void BPy_init_modules(void); extern PyObject *bpy_package_py; diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c index 90a0444ceae..959e4a788dd 100644 --- a/source/blender/python/intern/bpy_app_handlers.c +++ b/source/blender/python/intern/bpy_app_handlers.c @@ -57,6 +57,8 @@ static PyStructSequence_Field app_cb_info_fields[] = { {(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"}, /* sets the permanent tag */ # define APP_CB_OTHER_FIELDS 1 diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c index 481758db252..7141db7352a 100644 --- a/source/blender/python/intern/bpy_driver.c +++ b/source/blender/python/intern/bpy_driver.c @@ -123,7 +123,7 @@ static void bpy_pydriver_update_dict(const float evaltime) void BPY_driver_reset(void) { PyGILState_STATE gilstate; - bool use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + bool use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -162,7 +162,7 @@ static void pydriver_error(ChannelDriver *driver) * * (old)note: PyGILState_Ensure() isn't always called because python can call * the bake operator which intern starts a thread which calls scene update - * which does a driver update. to avoid a deadlock check PYC_INTERPRETER_ACTIVE + * which does a driver update. to avoid a deadlock check PyC_IsInterpreterActive() * if PyGILState_Ensure() is needed - see [#27683] * * (new)note: checking if python is running is not threadsafe [#28114] @@ -199,7 +199,7 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime) return 0.0f; } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index feffea20553..cc1dd369f8b 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -166,7 +166,7 @@ void BPY_text_free_code(Text *text) { if (text->compiled) { PyGILState_STATE gilstate; - bool use_gil = !PYC_INTERPRETER_ACTIVE; + bool use_gil = !PyC_IsInterpreterActive(); if (use_gil) gilstate = PyGILState_Ensure(); @@ -760,7 +760,7 @@ void BPY_modules_load_user(bContext *C) int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *result) { PyGILState_STATE gilstate; - bool use_gil = !PYC_INTERPRETER_ACTIVE; + bool use_gil = !PyC_IsInterpreterActive(); PyObject *pyctx; PyObject *item; @@ -821,8 +821,12 @@ int BPY_context_member_get(bContext *C, const char *member, bContextDataResult * } if (done == false) { - if (item) printf("PyContext '%s' not a valid type\n", member); - else printf("PyContext '%s' not found\n", member); + if (item) { + printf("PyContext '%s' not a valid type\n", member); + } + else { + printf("PyContext '%s' not found\n", member); + } } else { if (G.debug & G_DEBUG_PYTHON) { diff --git a/source/blender/python/intern/bpy_intern_string.h b/source/blender/python/intern/bpy_intern_string.h index 2e0d18d8b7f..41b7303bf8d 100644 --- a/source/blender/python/intern/bpy_intern_string.h +++ b/source/blender/python/intern/bpy_intern_string.h @@ -20,6 +20,9 @@ * ***** END GPL LICENSE BLOCK ***** */ +#ifndef __BPY_INTERN_STRING_H__ +#define __BPY_INTERN_STRING_H__ + /** \file blender/python/intern/bpy_intern_string.h * \ingroup pythonintern */ @@ -36,3 +39,5 @@ extern PyObject *bpy_intern_str_attr; extern PyObject *bpy_intern_str___slots__; extern PyObject *bpy_intern_str___name__; extern PyObject *bpy_intern_str___doc__; + +#endif /* __BPY_INTERN_STRING_H__ */ diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 65b7bf62032..efee9b13d58 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -177,14 +177,17 @@ PyObject *PYOP_wrap_macro_define(PyObject *UNUSED(self), PyObject *args) } /* identifiers */ - srna = srna_from_self(macro, "Macro Define:"); - macroname = RNA_struct_identifier(srna); + srna = pyrna_struct_as_srna((PyObject *)macro, false, "Macro Define:"); + if (srna == NULL) { + return NULL; + } + macroname = RNA_struct_identifier(srna); ot = WM_operatortype_find(macroname, true); if (!ot) { PyErr_Format(PyExc_ValueError, - "Macro Define: '%s' is not a valid macro or hasn't been registered yet", + "Macro Define: '%s' is not a valid macro", macroname); return NULL; } diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 9bd9d33a36c..bfa4954d4bc 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -256,7 +256,7 @@ static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -313,7 +313,7 @@ static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA * pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -368,7 +368,7 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr, struct Propert pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -430,7 +430,7 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct Propert pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -490,7 +490,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop) pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -547,7 +547,7 @@ static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -602,7 +602,7 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -664,7 +664,7 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -724,7 +724,7 @@ static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -781,7 +781,7 @@ static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pr pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -836,7 +836,7 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr, struct PropertyR pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -898,7 +898,7 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyR pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -957,7 +957,7 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -1017,7 +1017,7 @@ static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -1079,7 +1079,7 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr, struct PropertyRNA *p pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -1140,7 +1140,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); @@ -1197,7 +1197,7 @@ static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pro pyrna_write_set(true); } - use_gil = true; /* !PYC_INTERPRETER_ACTIVE; */ + use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) gilstate = PyGILState_Ensure(); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 3cd030e9b08..4d4d4873390 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1341,7 +1341,7 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) return pyrna_py_from_array(ptr, prop); } - /* see if we can coorce into a python type - PropertyType */ + /* see if we can coerce into a python type - PropertyType */ switch (type) { case PROP_BOOLEAN: ret = PyBool_FromLong(RNA_property_boolean_get(ptr, prop)); @@ -1507,7 +1507,7 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb else { /* Normal Property (not an array) */ - /* see if we can coorce into a python type - PropertyType */ + /* see if we can coerce into a python type - PropertyType */ switch (type) { case PROP_BOOLEAN: { @@ -4600,14 +4600,6 @@ PyDoc_STRVAR(pyrna_prop_collection_foreach_get_doc, ".. method:: foreach_get(attr, seq)\n" "\n" " This is a function to give fast access to attributes within a collection.\n" -"\n" -" .. code-block:: python\n" -"\n" -" collection.foreach_get(attr, someseq)\n" -"\n" -" # Python equivalent\n" -" for i in range(len(seq)): someseq[i] = getattr(collection, attr)\n" -"\n" ); static PyObject *pyrna_prop_collection_foreach_get(BPy_PropertyRNA *self, PyObject *args) { @@ -4620,14 +4612,6 @@ PyDoc_STRVAR(pyrna_prop_collection_foreach_set_doc, ".. method:: foreach_set(attr, seq)\n" "\n" " This is a function to give fast access to attributes within a collection.\n" -"\n" -" .. code-block:: python\n" -"\n" -" collection.foreach_set(attr, seq)\n" -"\n" -" # Python equivalent\n" -" for i in range(len(seq)): setattr(collection[i], attr, seq[i])\n" -"\n" ); static PyObject *pyrna_prop_collection_foreach_set(BPy_PropertyRNA *self, PyObject *args) { @@ -4887,7 +4871,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat } } else { - /* see if we can coorce into a python type - PropertyType */ + /* see if we can coerce into a python type - PropertyType */ switch (type) { case PROP_BOOLEAN: ret = PyBool_FromLong(*(int *)data); @@ -5327,7 +5311,7 @@ static PyObject *pyrna_func_doc_get(BPy_FunctionRNA *self, void *UNUSED(closure) PyObject *ret; char *args; - args = RNA_function_as_string_keywords(NULL, self->func, NULL, true, true, INT_MAX); + args = RNA_function_as_string_keywords(NULL, self->func, true, true, INT_MAX); ret = PyUnicode_FromFormat("%.200s.%.200s(%.200s)\n%s", RNA_struct_identifier(self->ptr.type), @@ -6875,7 +6859,7 @@ int pyrna_deferred_register_class(StructRNA *srna, PyTypeObject *py_class) /*-------------------- Type Registration ------------------------*/ -static int rna_function_arg_count(FunctionRNA *func) +static int rna_function_arg_count(FunctionRNA *func, int *min_count) { const ListBase *lb = RNA_function_defined_parameters(func); PropertyRNA *parm; @@ -6883,13 +6867,23 @@ static int rna_function_arg_count(FunctionRNA *func) int flag = RNA_function_flag(func); int is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE); int count = is_staticmethod ? 0 : 1; + bool done_min_count = false; for (link = lb->first; link; link = link->next) { parm = (PropertyRNA *)link; - if (!(RNA_property_flag(parm) & PROP_OUTPUT)) + if (!(RNA_property_flag(parm) & PROP_OUTPUT)) { + if (!done_min_count && (RNA_property_flag(parm) & PROP_PYFUNC_OPTIONAL)) { + /* From now on, following parameters are optional in py func */ + if (min_count) + *min_count = count; + done_min_count = true; + } count++; + } } + if (!done_min_count && min_count) + *min_count = count; return count; } @@ -6904,7 +6898,7 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v PyObject *py_class = (PyObject *)py_data; PyObject *base_class = RNA_struct_py_type_get(srna); PyObject *item; - int i, flag, is_staticmethod, arg_count, func_arg_count; + int i, flag, is_staticmethod, arg_count, func_arg_count, func_arg_min_count = 0; const char *py_class_name = ((PyTypeObject *)py_class)->tp_name; /* __name__ */ if (srna_base) { @@ -6968,7 +6962,7 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v } } - func_arg_count = rna_function_arg_count(func); + func_arg_count = rna_function_arg_count(func, &func_arg_min_count); if (func_arg_count >= 0) { /* -1 if we don't care*/ arg_count = ((PyCodeObject *)PyFunction_GET_CODE(item))->co_argcount; @@ -6976,14 +6970,25 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v /* note, the number of args we check for and the number of args we give to * @staticmethods are different (quirk of python), * this is why rna_function_arg_count() doesn't return the value -1*/ - if (is_staticmethod) + if (is_staticmethod) { func_arg_count++; + func_arg_min_count++; + } - if (arg_count != func_arg_count) { - PyErr_Format(PyExc_ValueError, - "expected %.200s, %.200s class \"%.200s\" function to have %d args, found %d", - class_type, py_class_name, RNA_function_identifier(func), - func_arg_count, arg_count); + if (arg_count < func_arg_min_count || arg_count > func_arg_count) { + if (func_arg_min_count != func_arg_count) { + PyErr_Format(PyExc_ValueError, + "expected %.200s, %.200s class \"%.200s\" function to have between %d and %d " + "args, found %d", + class_type, py_class_name, RNA_function_identifier(func), + func_arg_count, func_arg_min_count, arg_count); + } + else { + PyErr_Format(PyExc_ValueError, + "expected %.200s, %.200s class \"%.200s\" function to have %d args, found %d", + class_type, py_class_name, RNA_function_identifier(func), + func_arg_count, arg_count); + } return -1; } } @@ -7063,7 +7068,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param PropertyRNA *parm; ParameterIterator iter; PointerRNA funcptr; - int err = 0, i, ret_len = 0; + int err = 0, i, ret_len = 0, arg_count; int flag = RNA_function_flag(func); const char is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE); const char is_classmethod = (flag & FUNC_NO_SELF) && (flag & FUNC_USE_SELF_TYPE); @@ -7198,7 +7203,15 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param if (item) { RNA_pointer_create(NULL, &RNA_Function, func, &funcptr); - args = PyTuple_New(rna_function_arg_count(func)); /* first arg is included in 'item' */ + if (is_staticmethod) { + arg_count = ((PyCodeObject *)PyFunction_GET_CODE(((PyMethodObject *)item)->im_func))->co_argcount - 1; + } + else { + arg_count = ((PyCodeObject *)PyFunction_GET_CODE(item))->co_argcount; + } +// args = PyTuple_New(rna_function_arg_count(func)); /* first arg is included in 'item' */ + args = PyTuple_New(arg_count); /* first arg is included in 'item' */ + if (is_staticmethod) { i = 0; @@ -7230,9 +7243,11 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param continue; } - parmitem = pyrna_param_to_py(&funcptr, parm, iter.data); - PyTuple_SET_ITEM(args, i, parmitem); - i++; + if (i < arg_count) { + parmitem = pyrna_param_to_py(&funcptr, parm, iter.data); + PyTuple_SET_ITEM(args, i, parmitem); + i++; + } } #ifdef USE_PEDANTIC_WRITE diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 6e78a543481..e473af9fac8 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -312,7 +312,8 @@ PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args) BKE_reports_init(&reports, RPT_STORE); - result = ANIM_add_driver(&reports, (ID *)self->ptr.id.data, path_full, index, 0, DRIVER_TYPE_PYTHON); + result = ANIM_add_driver(&reports, (ID *)self->ptr.id.data, path_full, index, + CREATEDRIVER_WITH_FMODIFIER, DRIVER_TYPE_PYTHON); if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) return NULL; diff --git a/source/blender/python/intern/bpy_rna_anim.h b/source/blender/python/intern/bpy_rna_anim.h index 005e8f3e1a4..8ef976b8cb4 100644 --- a/source/blender/python/intern/bpy_rna_anim.h +++ b/source/blender/python/intern/bpy_rna_anim.h @@ -20,6 +20,9 @@ * ***** END GPL LICENSE BLOCK ***** */ +#ifndef __BPY_RNA_ANIM_H__ +#define __BPY_RNA_ANIM_H__ + /** \file blender/python/intern/bpy_rna_anim.h * \ingroup pythonintern */ @@ -33,3 +36,5 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyObject *kw); PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args); PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args); + +#endif /* __BPY_RNA_ANIM_H__ */ diff --git a/source/blender/python/intern/bpy_rna_callback.h b/source/blender/python/intern/bpy_rna_callback.h index 4b801f35654..6ef98790b4e 100644 --- a/source/blender/python/intern/bpy_rna_callback.h +++ b/source/blender/python/intern/bpy_rna_callback.h @@ -20,11 +20,13 @@ * ***** END GPL LICENSE BLOCK ***** */ +#ifndef __BPY_RNA_CALLBACK_H__ +#define __BPY_RNA_CALLBACK_H__ + /** \file blender/python/intern/bpy_rna_callback.h * \ingroup pythonintern */ - struct BPy_StructRNA; struct PyObject; @@ -35,3 +37,5 @@ PyObject *pyrna_callback_remove(BPy_StructRNA *self, PyObject *args); PyObject *pyrna_callback_classmethod_add(PyObject *cls, PyObject *args); PyObject *pyrna_callback_classmethod_remove(PyObject *cls, PyObject *args); + +#endif /* __BPY_RNA_CALLBACK_H__ */ diff --git a/source/blender/python/intern/gpu.h b/source/blender/python/intern/gpu.h index f8c751f7f94..82338869b9d 100644 --- a/source/blender/python/intern/gpu.h +++ b/source/blender/python/intern/gpu.h @@ -27,10 +27,13 @@ /** \file blender/python/intern/gpu.h * \ingroup pythonintern - */ - -/** + * * Initializes the gpu Python module. */ + +#ifndef __GPU_H__ +#define __GPU_H__ + PyObject *GPU_initPython(void); +#endif /* __GPU_H__ */ diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index 90e9565f05f..8f94fc8b467 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -510,10 +510,12 @@ PyMODINIT_FUNC PyInit_mathutils(void) PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); Py_INCREF(submodule); +#ifndef MATH_STANDALONE /* Noise submodule */ PyModule_AddObject(mod, "noise", (submodule = PyInit_mathutils_noise())); PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); Py_INCREF(submodule); +#endif mathutils_matrix_row_cb_index = Mathutils_RegisterCallback(&mathutils_matrix_row_cb); mathutils_matrix_col_cb_index = Mathutils_RegisterCallback(&mathutils_matrix_col_cb); diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index d471cd05a2b..3e5dcc28903 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -522,18 +522,12 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args) axis_angle_to_mat3((float (*)[3])mat, tvec, angle); } else if (matSize == 2) { - const float angle_cos = cosf(angle); - const float angle_sin = sinf(angle); + angle_to_mat2((float (*)[2])mat, angle); - /* 2D rotation matrix */ - mat[0] = angle_cos; - mat[1] = angle_sin; - mat[2] = -angle_sin; - mat[3] = angle_cos; } else { /* valid axis checked above */ - single_axis_angle_to_mat3((float (*)[3])mat, axis[0], angle); + axis_angle_to_mat3_single((float (*)[3])mat, axis[0], angle); } if (matSize == 4) { diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index d44bce502ca..8a5a8446ac6 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -1165,7 +1165,7 @@ static PyObject *Vector_lerp(VectorObject *self, PyObject *args) PyDoc_STRVAR(Vector_rotate_doc, ".. function:: rotate(other)\n" "\n" -" Return vector by a rotation value.\n" +" Rotate the vector by a rotation value.\n" "\n" " :arg other: rotation component of mathutils value\n" " :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n" @@ -1286,7 +1286,7 @@ static PyObject *vector_item_internal(VectorObject *self, int i, const int is_at static PyObject *Vector_item(VectorObject *self, int i) { - return vector_item_internal(self, i, FALSE); + return vector_item_internal(self, i, false); } /* sequence accessor (set): vector[index] = value */ static int vector_ass_item_internal(VectorObject *self, int i, PyObject *value, const int is_attr) @@ -1323,7 +1323,7 @@ static int vector_ass_item_internal(VectorObject *self, int i, PyObject *value, static int Vector_ass_item(VectorObject *self, int i, PyObject *value) { - return vector_ass_item_internal(self, i, value, FALSE); + return vector_ass_item_internal(self, i, value, false); } /* sequence slice (get): vector[a:b] */ @@ -2086,12 +2086,12 @@ PyDoc_STRVAR(Vector_axis_w_doc, "Vector W axis (4D Vectors only).\n\n:type: floa static PyObject *Vector_axis_get(VectorObject *self, void *type) { - return vector_item_internal(self, GET_INT_FROM_POINTER(type), TRUE); + return vector_item_internal(self, GET_INT_FROM_POINTER(type), true); } static int Vector_axis_set(VectorObject *self, PyObject *value, void *type) { - return vector_ass_item_internal(self, GET_INT_FROM_POINTER(type), value, TRUE); + return vector_ass_item_internal(self, GET_INT_FROM_POINTER(type), value, true); } /* vector.length */ diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index 8509c46b395..8b5b74c480a 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -34,6 +34,7 @@ # include "MEM_guardedalloc.h" # include "BLI_blenlib.h" # include "BLI_boxpack2d.h" +# include "BLI_convexhull2d.h" # include "BKE_displist.h" # include "BKE_curve.h" #endif @@ -568,22 +569,19 @@ PyDoc_STRVAR(M_Geometry_intersect_line_plane_doc, " :type plane_co: :class:`mathutils.Vector`\n" " :arg plane_no: The direction the plane is facing\n" " :type plane_no: :class:`mathutils.Vector`\n" -" :arg no_flip: Always return an intersection on the directon defined bt line_a -> line_b\n" -" :type no_flip: :boolean\n" " :return: The point of intersection or None when not found\n" " :rtype: :class:`mathutils.Vector` or None\n" ); static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObject *args) { VectorObject *line_a, *line_b, *plane_co, *plane_no; - int no_flip = 0; float isect[3]; + 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)) + &vector_Type, &plane_no)) { return NULL; } @@ -603,7 +601,7 @@ static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObjec return NULL; } - if (isect_line_plane_v3(isect, line_a->vec, line_b->vec, plane_co->vec, plane_no->vec, no_flip) == 1) { + 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); } else { @@ -692,7 +690,7 @@ static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObje { VectorObject *line_a, *line_b, *sphere_co; float sphere_radius; - int clip = TRUE; + int clip = true; float isect_a[3]; float isect_b[3]; @@ -728,12 +726,12 @@ static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObje switch (isect_line_sphere_v3(line_a->vec, line_b->vec, sphere_co->vec, 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->vec, line_b->vec)) >= 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->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; break; default: use_a = false; @@ -773,7 +771,7 @@ static PyObject *M_Geometry_intersect_line_sphere_2d(PyObject *UNUSED(self), PyO { VectorObject *line_a, *line_b, *sphere_co; float sphere_radius; - int clip = TRUE; + int clip = true; float isect_a[2]; float isect_b[2]; @@ -803,7 +801,7 @@ static PyObject *M_Geometry_intersect_line_sphere_2d(PyObject *UNUSED(self), PyO switch (isect_line_sphere_v2(line_a->vec, line_b->vec, sphere_co->vec, 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; - use_b = 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; @@ -980,24 +978,35 @@ PyDoc_STRVAR(M_Geometry_distance_point_to_plane_doc, ); static PyObject *M_Geometry_distance_point_to_plane(PyObject *UNUSED(self), PyObject *args) { - VectorObject *pt, *plene_co, *plane_no; + VectorObject *pt, *plane_co, *plane_no; + float plane[4]; if (!PyArg_ParseTuple(args, "O!O!O!:distance_point_to_plane", &vector_Type, &pt, - &vector_Type, &plene_co, + &vector_Type, &plane_co, &vector_Type, &plane_no)) { return NULL; } + if (pt->size != 3 || + plane_co->size != 3 || + plane_no->size != 3) + { + 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(plene_co) == -1 || + BaseMath_ReadCallback(plane_co) == -1 || BaseMath_ReadCallback(plane_no) == -1) { return NULL; } - return PyFloat_FromDouble(dist_to_plane_v3(pt->vec, plene_co->vec, plane_no->vec)); + plane_from_point_normal_v3(plane, plane_co->vec, plane_no->vec); + return PyFloat_FromDouble(dist_to_plane_v3(pt->vec, plane)); } PyDoc_STRVAR(M_Geometry_barycentric_transform_doc, @@ -1054,6 +1063,17 @@ static PyObject *M_Geometry_barycentric_transform(PyObject *UNUSED(self), PyObje 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) + { + return NULL; + } + barycentric_transform(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); @@ -1099,7 +1119,7 @@ static PyObject *M_Geometry_points_in_planes(PyObject *UNUSED(self), PyObject *a /* python */ PyObject *py_verts = PyList_New(0); - PyObject *py_plene_index = PyList_New(0); + PyObject *py_plane_index = PyList_New(0); memset(planes_used, 0, sizeof(char) * len); @@ -1135,7 +1155,7 @@ static PyObject *M_Geometry_points_in_planes(PyObject *UNUSED(self), PyObject *a PyList_Append(py_verts, item); Py_DECREF(item); - planes_used[i] = planes_used[j] = planes_used[k] = TRUE; + planes_used[i] = planes_used[j] = planes_used[k] = true; } } } @@ -1151,7 +1171,7 @@ static PyObject *M_Geometry_points_in_planes(PyObject *UNUSED(self), PyObject *a for (i = 0; i < len; i++) { if (planes_used[i]) { PyObject *item = PyLong_FromLong(i); - PyList_Append(py_plene_index, item); + PyList_Append(py_plane_index, item); Py_DECREF(item); } } @@ -1160,7 +1180,7 @@ static PyObject *M_Geometry_points_in_planes(PyObject *UNUSED(self), PyObject *a { PyObject *ret = PyTuple_New(2); PyTuple_SET_ITEM(ret, 0, py_verts); - PyTuple_SET_ITEM(ret, 1, py_plene_index); + PyTuple_SET_ITEM(ret, 1, py_plane_index); return ret; } } @@ -1473,7 +1493,7 @@ static PyObject *M_Geometry_box_pack_2d(PyObject *UNUSED(self), PyObject *boxlis } /* Non Python function */ - BLI_box_pack_2D(boxarray, len, &tot_width, &tot_height); + BLI_box_pack_2d(boxarray, len, &tot_width, &tot_height); boxPack_ToPyObject(boxlist, &boxarray); } @@ -1484,6 +1504,87 @@ static PyObject *M_Geometry_box_pack_2d(PyObject *UNUSED(self), PyObject *boxlis return ret; } +PyDoc_STRVAR(M_Geometry_box_fit_2d_doc, +".. function:: box_fit_2d(points)\n" +"\n" +" Returns an angle that best fits the points to an axis aligned rectangle\n" +"\n" +" :arg points: list of 2d points.\n" +" :type points: list\n" +" :return: angle\n" +" :rtype: float\n" +); +static PyObject *M_Geometry_box_fit_2d(PyObject *UNUSED(self), PyObject *pointlist) +{ + float (*points)[2]; + Py_ssize_t len; + + float angle = 0.0f; + + len = mathutils_array_parse_alloc_v(((float **)&points), 2, pointlist, "box_fit_2d"); + if (len == -1) { + return NULL; + } + + if (len) { + /* Non Python function */ + angle = BLI_convexhull_aabb_fit_points_2d((const float (*)[2])points, len); + + PyMem_Free(points); + } + + + return PyFloat_FromDouble(angle); +} + +PyDoc_STRVAR(M_Geometry_convex_hull_2d_doc, +".. function:: convex_hull_2d(points)\n" +"\n" +" Returns a list of indices into the list given\n" +"\n" +" :arg points: list of 2d points.\n" +" :type points: list\n" +" :return: a list of indices\n" +" :rtype: list of ints\n" +); +static PyObject *M_Geometry_convex_hull_2d(PyObject *UNUSED(self), PyObject *pointlist) +{ + float (*points)[2]; + Py_ssize_t len; + + PyObject *ret; + + len = mathutils_array_parse_alloc_v(((float **)&points), 2, pointlist, "convex_hull_2d"); + if (len == -1) { + return NULL; + } + + if (len) { + int *index_map; + Py_ssize_t len_ret, i; + + index_map = MEM_mallocN(sizeof(*index_map) * len, __func__); + + /* Non Python function */ + len_ret = BLI_convexhull_2d((const float (*)[2])points, len, index_map); + + ret = PyList_New(len_ret); + for (i = 0; i < len_ret; i++) { + PyList_SET_ITEM(ret, i, PyLong_FromLong(index_map[i])); + } + + MEM_freeN(index_map); + + PyMem_Free(points); + } + else { + ret = PyList_New(0); + } + + + return ret; +} + #endif /* MATH_STANDALONE */ @@ -1508,6 +1609,8 @@ static PyMethodDef M_Geometry_methods[] = { #ifndef MATH_STANDALONE {"interpolate_bezier", (PyCFunction) M_Geometry_interpolate_bezier, METH_VARARGS, M_Geometry_interpolate_bezier_doc}, {"tessellate_polygon", (PyCFunction) M_Geometry_tessellate_polygon, METH_O, M_Geometry_tessellate_polygon_doc}, + {"convex_hull_2d", (PyCFunction) M_Geometry_convex_hull_2d, METH_O, M_Geometry_convex_hull_2d_doc}, + {"box_fit_2d", (PyCFunction) M_Geometry_box_fit_2d, METH_O, M_Geometry_box_fit_2d_doc}, {"box_pack_2d", (PyCFunction) M_Geometry_box_pack_2d, METH_O, M_Geometry_box_pack_2d_doc}, #endif {NULL, NULL, 0, NULL} diff --git a/source/blender/quicktime/apple/qtkit_export.m b/source/blender/quicktime/apple/qtkit_export.m index 7b42c89d936..8cf91e44c77 100644 --- a/source/blender/quicktime/apple/qtkit_export.m +++ b/source/blender/quicktime/apple/qtkit_export.m @@ -317,7 +317,7 @@ int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, R int success = 1; OSStatus err = noErr; - if(qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport"); + if (qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport"); [QTMovie enterQTKitOnThread]; @@ -476,7 +476,7 @@ int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, R err = AudioFileCreateWithURL(outputFileURL, audioFileType, &qtexport->audioOutputFormat, kAudioFileFlags_EraseFile, &qtexport->audioFile); CFRelease(outputFileURL); - if(err) + if (err) BKE_report(reports, RPT_ERROR, "\nQuicktime: unable to create temporary audio file. Format error ?"); else { err = AudioConverterNew(&qtexport->audioInputFormat, &qtexport->audioOutputFormat, &qtexport->audioConverter); @@ -542,7 +542,7 @@ int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, R else qtexport->movie = [[QTMovie alloc] initToWritableFile:qtexport->filename error:&error]; - if(qtexport->movie == nil) { + if (qtexport->movie == nil) { BKE_report(reports, RPT_ERROR, "Unable to create quicktime movie."); success = 0; if (qtexport->filename) [qtexport->filename release]; @@ -749,13 +749,11 @@ void end_qt(void) if (audioTmpMovie) { NSArray *audioTracks = [audioTmpMovie tracksOfMediaType:QTMediaTypeSound]; QTTrack *audioTrack = nil; - if( [audioTracks count] > 0 ) - { + if ( [audioTracks count] > 0 ) { audioTrack = [audioTracks objectAtIndex:0]; } - if( audioTrack ) - { + if (audioTrack) { QTTimeRange totalRange; totalRange.time = QTZeroTime; totalRange.duration = [[audioTmpMovie attributeForKey:QTMovieDurationAttribute] QTTimeValue]; @@ -798,7 +796,7 @@ void end_qt(void) [QTMovie exitQTKitOnThread]; - if(qtexport) { + if (qtexport) { MEM_freeN(qtexport); qtexport = NULL; } diff --git a/source/blender/quicktime/apple/qtkit_import.m b/source/blender/quicktime/apple/qtkit_import.m index bee26c5348e..fbe4733c3b1 100644 --- a/source/blender/quicktime/apple/qtkit_import.m +++ b/source/blender/quicktime/apple/qtkit_import.m @@ -128,7 +128,7 @@ void free_anim_quicktime(struct anim *anim) if (anim == NULL) return; if (anim->qtime == NULL) return; - if(anim->qtime->ibuf) + if (anim->qtime->ibuf) IMB_freeImBuf(anim->qtime->ibuf); [anim->qtime->media release]; @@ -136,7 +136,7 @@ void free_anim_quicktime(struct anim *anim) [QTMovie exitQTKitOnThread]; - if(anim->qtime) MEM_freeN (anim->qtime); + if (anim->qtime) MEM_freeN (anim->qtime); anim->qtime = NULL; @@ -289,7 +289,7 @@ ImBuf *qtime_fetchibuf (struct anim *anim, int position) } if (frameImage == nil) { - if(QTIME_DEBUG) printf ("Error reading frame from Quicktime"); + if (QTIME_DEBUG) printf ("Error reading frame from Quicktime"); [pool drain]; return NULL; } @@ -312,7 +312,7 @@ int startquicktime(struct anim *anim) anim->qtime = MEM_callocN(sizeof(QuicktimeMovie),"animqt"); if (anim->qtime == NULL) { - if(QTIME_DEBUG) printf("Can't alloc qtime: %s\n", anim->name); + if (QTIME_DEBUG) printf("Can't alloc qtime: %s\n", anim->name); return -1; } @@ -329,9 +329,9 @@ int startquicktime(struct anim *anim) anim->qtime->movie = [QTMovie movieWithAttributes:attributes error:NULL]; if (!anim->qtime->movie) { - if(QTIME_DEBUG) printf("qt: bad movie %s\n", anim->name); + if (QTIME_DEBUG) printf("qt: bad movie %s\n", anim->name); MEM_freeN(anim->qtime); - if(QTIME_DEBUG) printf("qt: can't load %s\n", anim->name); + if (QTIME_DEBUG) printf("qt: can't load %s\n", anim->name); [QTMovie exitQTKitOnThread]; [pool drain]; return -1; @@ -342,11 +342,11 @@ int startquicktime(struct anim *anim) videoTracks = [anim->qtime->movie tracksOfMediaType:QTMediaTypeVideo]; - if([videoTracks count] == 0) { - if(QTIME_DEBUG) printf("qt: no video tracks for movie %s\n", anim->name); + if ([videoTracks count] == 0) { + if (QTIME_DEBUG) printf("qt: no video tracks for movie %s\n", anim->name); [anim->qtime->movie release]; MEM_freeN(anim->qtime); - if(QTIME_DEBUG) printf("qt: can't load %s\n", anim->name); + if (QTIME_DEBUG) printf("qt: can't load %s\n", anim->name); [QTMovie exitQTKitOnThread]; [pool drain]; return -1; @@ -360,8 +360,8 @@ int startquicktime(struct anim *anim) anim->x = frameSize.width; anim->y = frameSize.height; - if(anim->x == 0 && anim->y == 0) { - if(QTIME_DEBUG) printf("qt: error, no dimensions\n"); + if (anim->x == 0 && anim->y == 0) { + if (QTIME_DEBUG) printf("qt: error, no dimensions\n"); free_anim_quicktime(anim); [pool drain]; return -1; @@ -398,12 +398,12 @@ int imb_is_a_quicktime(char *name) int result; NSAutoreleasePool *pool; - if(!G.have_quicktime) return 0; + if (!G.have_quicktime) return 0; pool = [[NSAutoreleasePool alloc] init]; // don't let quicktime image import handle these - if( BLI_testextensie(name, ".swf") || + if (BLI_testextensie(name, ".swf") || BLI_testextensie(name, ".txt") || BLI_testextensie(name, ".mpg") || BLI_testextensie(name, ".wav") || @@ -437,7 +437,7 @@ ImBuf *imb_quicktime_decode(unsigned char *mem, int size, int flags) NSBitmapImageRep *blBitmapFormatImageRGB,*blBitmapFormatImageRGBA; NSAutoreleasePool *pool; - if(!G.have_quicktime) + if (!G.have_quicktime) return NULL; pool = [[NSAutoreleasePool alloc] init]; diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index e154fd42119..73a89ad884f 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -225,8 +225,8 @@ void RE_init_threadcount(Render *re); void RE_TileProcessor(struct Render *re); /* only RE_NewRender() needed, main Blender render calls */ -void RE_BlenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene, struct SceneRenderLayer *srl, struct Object *camera_override, unsigned int lay, int frame, const short write_still); -void RE_BlenderAnim(struct Render *re, struct Main *bmain, struct Scene *scene, struct Object *camera_override, unsigned int lay, int sfra, int efra, int tfra); +void RE_BlenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene, struct SceneRenderLayer *srl, struct Object *camera_override, unsigned int lay_override, int frame, const short write_still); +void RE_BlenderAnim(struct Render *re, struct Main *bmain, struct Scene *scene, struct Object *camera_override, unsigned int lay_override, int sfra, int efra, int tfra); #ifdef WITH_FREESTYLE void RE_RenderFreestyleStrokes(struct Render *re, struct Main *bmain, struct Scene *scene, int render); #endif diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h index 2dc12f39db7..b23d6b09524 100644 --- a/source/blender/render/intern/include/texture.h +++ b/source/blender/render/intern/include/texture.h @@ -35,17 +35,17 @@ #define BRICONT \ texres->tin= (texres->tin-0.5f) * tex->contrast+tex->bright-0.5f; \ - if(texres->tin < 0.0f) texres->tin= 0.0f; \ - else if(texres->tin > 1.0f) texres->tin= 1.0f; \ + if (texres->tin < 0.0f) texres->tin= 0.0f; \ + else if (texres->tin > 1.0f) texres->tin= 1.0f; \ #define BRICONTRGB \ texres->tr= tex->rfac*((texres->tr-0.5f)*tex->contrast+tex->bright-0.5f); \ - if(texres->tr<0.0f) texres->tr= 0.0f; \ + if (texres->tr<0.0f) texres->tr= 0.0f; \ texres->tg= tex->gfac*((texres->tg-0.5f)*tex->contrast+tex->bright-0.5f); \ - if(texres->tg<0.0f) texres->tg= 0.0f; \ + if (texres->tg<0.0f) texres->tg= 0.0f; \ texres->tb= tex->bfac*((texres->tb-0.5f)*tex->contrast+tex->bright-0.5f); \ - if(texres->tb<0.0f) texres->tb= 0.0f; \ - if(tex->saturation != 1.0f) { \ + if (texres->tb<0.0f) texres->tb= 0.0f; \ + if (tex->saturation != 1.0f) { \ float _hsv[3]; \ rgb_to_hsv(texres->tr, texres->tg, texres->tb, \ _hsv, _hsv+1, _hsv+2); \ diff --git a/source/blender/render/intern/include/texture_ocean.h b/source/blender/render/intern/include/texture_ocean.h index 121142aa0b0..4a71aff930a 100644 --- a/source/blender/render/intern/include/texture_ocean.h +++ b/source/blender/render/intern/include/texture_ocean.h @@ -26,6 +26,10 @@ #ifndef __TEXTURE_OCEAN_H__ #define __TEXTURE_OCEAN_H__ +/** \file blender/render/intern/include/texture_ocean.h + * \ingroup render + */ + int ocean_texture(struct Tex *tex, const float texvec[2], struct TexResult *texres); #endif /* __TEXTURE_OCEAN_H__ */ diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c index 564cca09834..6e70e670ff8 100644 --- a/source/blender/render/intern/source/bake.c +++ b/source/blender/render/intern/source/bake.c @@ -647,6 +647,8 @@ static int get_next_bake_face(BakeShade *bs) const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f}; const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f}; const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f}; + const float disp_alpha[4] = {0.5f, 0.5f, 0.5f, 0.0f}; + const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f}; tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0); @@ -686,6 +688,8 @@ static int get_next_bake_face(BakeShade *bs) if (R.r.bake_flag & R_BAKE_CLEAR) { if (R.r.bake_mode == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid); + else if (R.r.bake_mode == RE_BAKE_DISPLACEMENT) + IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid); else IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid); } @@ -828,8 +832,11 @@ static void shade_tface(BakeShade *bs) } } - if (bs->use_displacement_buffer) - userdata->displacement_buffer = MEM_callocN(sizeof(float) * bs->rectx * bs->recty, "BakeDisp"); + if (bs->use_displacement_buffer) { + if (userdata->displacement_buffer == NULL) { + userdata->displacement_buffer = MEM_callocN(sizeof(float) * bs->rectx * bs->recty, "BakeDisp"); + } + } bs->ibuf->userdata = userdata; @@ -1081,12 +1088,12 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up userdata = (BakeImBufuserData *)ibuf->userdata; if (userdata) { - RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, re->r.bake_filter); - if (use_displacement_buffer) { RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer, displacement_min, displacement_max); } + + RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, re->r.bake_filter); } ibuf->userflags |= IB_BITMAPDIRTY; diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index ab888ba198b..a0104a30d0e 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1741,7 +1741,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem } if (path_nbr == 0) - psys->lattice = psys_get_lattice(&sim); + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); /* 3. start creating renderable things */ for (a=0, pa=pars; a<totpart+totchild; a++, pa++, seed++) { @@ -2094,9 +2094,9 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem psys->flag &= ~PSYS_DRAWING; - if (psys->lattice) { - end_latt_deform(psys->lattice); - psys->lattice= NULL; + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; } if (path_nbr && (ma->mode_l & MA_TANGENT_STR)==0) @@ -3279,7 +3279,7 @@ static EdgeHash *make_freestyle_edge_mark_hash(Mesh *me, DerivedMesh *dm) index = dm->getEdgeDataArray(dm, CD_ORIGINDEX); fed = CustomData_get_layer(&me->edata, CD_FREESTYLE_EDGE); if (fed) { - edge_hash = BLI_edgehash_new(); + edge_hash = BLI_edgehash_new(__func__); if (!index) { if (me->totedge == totedge) { for (a = 0; a < me->totedge; a++) { diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index ea22423985b..827a1f8f113 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -49,6 +49,8 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "RNA_access.h" + #ifdef WITH_PYTHON #include "BPY_extern.h" #endif @@ -392,6 +394,17 @@ RenderData *RE_engine_get_render_data(Render *re) /* Render */ +static bool render_layer_exclude_animated(Scene *scene, SceneRenderLayer *srl) +{ + PointerRNA ptr; + PropertyRNA *prop; + + RNA_pointer_create(&scene->id, &RNA_SceneRenderLayer, srl, &ptr); + prop = RNA_struct_find_property(&ptr, "layers_exclude"); + + return RNA_property_animated(&ptr, prop); +} + int RE_engine_render(Render *re, int do_all) { RenderEngineType *type = RE_engines_find(re->r.engine); @@ -420,13 +433,25 @@ int RE_engine_render(Render *re, int do_all) if (re->r.scemode & R_SINGLE_LAYER) { srl = BLI_findlink(&re->r.layers, re->r.actlay); - if (srl) + if (srl) { non_excluded_lay |= ~srl->lay_exclude; + + /* in this case we must update all because animation for + * the scene has not been updated yet, and so may not be + * up to date until after BKE_scene_update_for_newframe */ + if (render_layer_exclude_animated(re->scene, srl)) + non_excluded_lay |= ~0; + } } else { - for (srl = re->r.layers.first; srl; srl = srl->next) - if (!(srl->layflag & SCE_LAY_DISABLE)) + for (srl = re->r.layers.first; srl; srl = srl->next) { + if (!(srl->layflag & SCE_LAY_DISABLE)) { non_excluded_lay |= ~srl->lay_exclude; + + if (render_layer_exclude_animated(re->scene, srl)) + non_excluded_lay |= ~0; + } + } } lay &= non_excluded_lay; diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 899c9b335be..6118d479cab 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -630,6 +630,22 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, SceneRenderLayer * RE_init_threadcount(re); } +/* update some variables that can be animated, and otherwise wouldn't be due to + * RenderData getting copied once at the start of animation render */ +static void render_update_anim_renderdata(Render *re, RenderData *rd) +{ + /* filter */ + re->r.gauss = rd->gauss; + + /* motion blur */ + re->r.mblur_samples = rd->mblur_samples; + re->r.blurfac = rd->blurfac; + + /* freestyle */ + re->r.line_thickness_mode = rd->line_thickness_mode; + re->r.unit_line_thickness = rd->unit_line_thickness; +} + void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend) { /* re->ok flag? */ @@ -1697,12 +1713,17 @@ static void composite_freestyle_renders(Render *re, int sample) for (srl= (SceneRenderLayer *)re->r.layers.first; srl; srl= srl->next) { if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl) continue; + if (FRS_is_freestyle_enabled(srl)) { freestyle_render = (Render *)link->data; - render_result_exr_file_read(freestyle_render, sample); - FRS_composite_result(re, srl, freestyle_render); - RE_FreeRenderResult(freestyle_render->result); - freestyle_render->result = NULL; + + /* may be NULL in case of empty render layer */ + if (freestyle_render) { + render_result_exr_file_read(freestyle_render, sample); + FRS_composite_result(re, srl, freestyle_render); + RE_FreeRenderResult(freestyle_render->result); + freestyle_render->result = NULL; + } } link = link->next; } @@ -1717,8 +1738,9 @@ static void free_all_freestyle_renders(void) for (re1= RenderGlobal.renderlist.first; re1; re1= re1->next) { for (link = (LinkData *)re1->freestyle_renders.first; link; link = link->next) { - if (link->data) { - freestyle_render = (Render *)link->data; + freestyle_render = (Render *)link->data; + + if (freestyle_render) { freestyle_scene = freestyle_render->scene; RE_FreeRender(freestyle_render); BKE_scene_unlink(&re1->freestyle_bmain, freestyle_scene, NULL); @@ -1752,6 +1774,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba"); for (sample = 0; sample < re->r.osa; sample++) { + Scene *sce; Render *re1; RenderResult rres; int mask; @@ -1763,9 +1786,11 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) /* also function below assumes this */ tag_scenes_for_render(re); - for (re1 = RenderGlobal.renderlist.first; re1; re1 = re1->next) { - if (re1->scene->id.flag & LIB_DOIT) { - if (re1->r.scemode & R_FULL_SAMPLE) { + for (sce = re->main->scene.first; sce; sce = sce->id.next) { + if (sce->id.flag & LIB_DOIT) { + re1 = RE_GetRender(sce->id.name); + + if (re1 && (re1->r.scemode & R_FULL_SAMPLE)) { if (sample) { BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); render_result_exr_file_read(re1, sample); @@ -2364,7 +2389,7 @@ static void update_physics_cache(Render *re, Scene *scene, int UNUSED(anim_init) BKE_ptcache_bake(&baker); } /* evaluating scene options for general Blender render */ -static int render_initialize_from_main(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *srl, Object *camera_override, unsigned int lay, int anim, int anim_init) +static int render_initialize_from_main(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *srl, Object *camera_override, unsigned int lay_override, int anim, int anim_init) { int winx, winy; rcti disprect; @@ -2394,11 +2419,12 @@ static int render_initialize_from_main(Render *re, Main *bmain, Scene *scene, Sc re->scene = scene; re->scene_color_manage = BKE_scene_check_color_management_enabled(scene); re->camera_override = camera_override; - re->lay = lay; - re->i.localview = (lay & 0xFF000000) != 0; + re->lay = lay_override ? lay_override : scene->lay; + re->i.localview = (re->lay & 0xFF000000) != 0; /* not too nice, but it survives anim-border render */ if (anim) { + render_update_anim_renderdata(re, &scene->r); re->disprect = disprect; return 1; } @@ -2443,14 +2469,14 @@ void RE_SetReports(Render *re, ReportList *reports) } /* general Blender frame render call */ -void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *srl, Object *camera_override, unsigned int lay, int frame, const short write_still) +void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *srl, Object *camera_override, unsigned int lay_override, int frame, const short write_still) { /* ugly global still... is to prevent preview events and signal subsurfs etc to make full resol */ G.is_rendering = TRUE; scene->r.cfra = frame; - if (render_initialize_from_main(re, bmain, scene, srl, camera_override, lay, 0, 0)) { + if (render_initialize_from_main(re, bmain, scene, srl, camera_override, lay_override, 0, 0)) { MEM_reset_peak_memory(); BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE); @@ -2516,7 +2542,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie } - IMB_colormanagement_imbuf_for_write(ibuf, TRUE, FALSE, &scene->view_settings, + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, &scene->display_settings, &scene->r.im_format); ok = mh->append_movie(&re->r, scene->r.sfra, scene->r.cfra, (int *) ibuf->rect, @@ -2547,7 +2573,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie else { ImBuf *ibuf = render_result_rect_to_ibuf(&rres, &scene->r); - IMB_colormanagement_imbuf_for_write(ibuf, TRUE, FALSE, &scene->view_settings, + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, &scene->display_settings, &scene->r.im_format); ok = BKE_imbuf_write_stamp(scene, camera, ibuf, name, &scene->r.im_format); @@ -2567,7 +2593,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie BKE_add_image_extension(name, &imf); ibuf->planes = 24; - IMB_colormanagement_imbuf_for_write(ibuf, TRUE, FALSE, &scene->view_settings, + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, &scene->display_settings, &imf); BKE_imbuf_write_stamp(scene, camera, ibuf, name, &imf); @@ -2599,14 +2625,14 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie } /* saves images to disk */ -void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_override, unsigned int lay, int sfra, int efra, int tfra) +void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_override, unsigned int lay_override, int sfra, int efra, int tfra) { bMovieHandle *mh = BKE_movie_handle_get(scene->r.im_format.imtype); int cfrao = scene->r.cfra; int nfra, totrendered = 0, totskipped = 0; /* do not fully call for each frame, it initializes & pops output window */ - if (!render_initialize_from_main(re, bmain, scene, NULL, camera_override, lay, 0, 1)) + if (!render_initialize_from_main(re, bmain, scene, NULL, camera_override, lay_override, 0, 1)) return; /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */ @@ -2651,7 +2677,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri char name[FILE_MAX]; /* only border now, todo: camera lens. (ton) */ - render_initialize_from_main(re, bmain, scene, NULL, camera_override, lay, 1, 0); + render_initialize_from_main(re, bmain, scene, NULL, camera_override, lay_override, 1, 0); if (nfra != scene->r.cfra) { /* @@ -2909,7 +2935,7 @@ int RE_WriteEnvmapResult(struct ReportList *reports, Scene *scene, EnvMap *env, return 0; } - IMB_colormanagement_imbuf_for_write(ibuf, TRUE, FALSE, &scene->view_settings, &scene->display_settings, &imf); + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, &scene->display_settings, &imf); /* to save, we first get absolute path */ BLI_strncpy(filepath, relpath, sizeof(filepath)); diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index d4d6bfa5b7f..ce87888b6a0 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -140,7 +140,7 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa invert_m4_m4(ob->imat, ob->obmat); total_particles = psys->totpart+psys->totchild; - psys->lattice=psys_get_lattice(&sim); + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); alloc_point_data(pd, total_particles, data_used); @@ -215,9 +215,9 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa BLI_bvhtree_balance(pd->point_tree); dm->release(dm); - if (psys->lattice) { - end_latt_deform(psys->lattice); - psys->lattice = NULL; + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; } psys_render_restore(ob, psys); diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 7ae64d499fa..90ae39ee767 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -734,6 +734,15 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, con ShadeInput shi = {NULL}; Isect isec; float dist_mir = origshi->mat->dist_mir; + + /* with high depth the number of rays can explode due to the path splitting + * in two each time, giving 2^depth rays. we need to be able to cancel such + * a render to avoid hanging, a better solution would be random picking + * between directions and russian roulette termination */ + if (R.test_break(R.tbh)) { + zero_v4(col); + return; + } copy_v3_v3(isec.start, start); copy_v3_v3(isec.dir, dir); @@ -2308,9 +2317,7 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, const float lampco[3], } copy_v3_v3(isec->start, start); - isec->dir[0] = end[0]-isec->start[0]; - isec->dir[1] = end[1]-isec->start[1]; - isec->dir[2] = end[2]-isec->start[2]; + sub_v3_v3v3(isec->dir, end, start); isec->dist = normalize_v3(isec->dir); if (shi->obi->flag & R_ENV_TRANSFORMED) diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index 1f740e3f483..37587d89ce0 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -1191,7 +1191,7 @@ void render_result_rect_get_pixels(RenderResult *rr, unsigned int *rect, int rec } else if (rr->rectf) { IMB_display_buffer_transform_apply((unsigned char *) rect, rr->rectf, rr->rectx, rr->recty, 4, - view_settings, display_settings, TRUE); + view_settings, display_settings, true); } else /* else fill with black */ diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index fa3cf1cef87..982e9b1a410 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -1957,36 +1957,38 @@ void add_halo_flare(Render *re) RenderResult *rr= re->result; RenderLayer *rl; HaloRen *har; - int a, mode, do_draw = FALSE; + int a, mode; /* for now, we get the first renderlayer in list with halos set */ - for (rl= rr->layers.first; rl; rl= rl->next) - if (rl->layflag & SCE_LAY_HALO) - break; - - if (rl==NULL || rl->rectf==NULL) - return; - - mode= R.r.mode; - R.r.mode &= ~R_PANORAMA; - - project_renderdata(&R, projectverto, 0, 0, 0); - - for (a=0; a<R.tothalo; a++) { - har= R.sortedhalos[a]; + for (rl= rr->layers.first; rl; rl= rl->next) { + int do_draw = FALSE; + + if ((rl->layflag & SCE_LAY_HALO) == 0) + continue; + if (rl->rectf==NULL) + continue; - if (har->flarec) { - do_draw = TRUE; - renderflare(rr, rl->rectf, har); + mode= R.r.mode; + R.r.mode &= ~R_PANORAMA; + + project_renderdata(&R, projectverto, 0, 0, 0); + + for (a=0; a<R.tothalo; a++) { + har= R.sortedhalos[a]; + + if (har->flarec && (har->lay & rl->lay)) { + do_draw = TRUE; + renderflare(rr, rl->rectf, har); + } + } + + if (do_draw) { + /* weak... the display callback wants an active renderlayer pointer... */ + rr->renlay= rl; + re->display_draw(re->ddh, rr, NULL); } - } - if (do_draw) { - /* weak... the display callback wants an active renderlayer pointer... */ - rr->renlay= rl; - re->display_draw(re->ddh, rr, NULL); + R.r.mode= mode; } - - R.r.mode= mode; } diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c index 0d85cfe78b7..0c3bf85cd24 100644 --- a/source/blender/render/intern/source/shadbuf.c +++ b/source/blender/render/intern/source/shadbuf.c @@ -1373,7 +1373,7 @@ float shadow_halo(LampRen *lar, const float p1[3], const float p2[3]) /* printf("start %x %x \n", (int)(0x7FFFFFFF*zf1), (int)(0x7FFFFFFF*zf2)); */ - while (1) { + do { lambda_o= lambda; if (lambda_x==lambda_y) { @@ -1394,7 +1394,13 @@ float shadow_halo(LampRen *lar, const float p1[3], const float p2[3]) } lambda = min_ff(lambda_x, lambda_y); - + + /* not making any progress? */ + if (lambda==lambda_o) break; + + /* clip to end of volume */ + lambda = min_ff(lambda, 1.0f); + zf= zf1 + lambda*(zf2-zf1); count+= (float)shb->totbuf; @@ -1409,10 +1415,9 @@ float shadow_halo(LampRen *lar, const float p1[3], const float p2[3]) lightcount+= readshadowbuf_halo(shb, shsample, x, y, z); } - /* break after sample, so it takes at least one */ - if (lambda==lambda_o || lambda>=1.0f) break; } - + while (lambda < 1.0f); + if (count!=0.0f) return (lightcount/count); return 0.0f; diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index 178d304eca2..114961394c4 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -1191,8 +1191,8 @@ float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *d float visifac= 1.0f, t; sub_v3_v3v3(lv, co, lar->co); - *dist= sqrtf(dot_v3v3(lv, lv)); - t= 1.0f/dist[0]; + *dist = len_v3(lv); + t = 1.0f / (*dist); mul_v3_fl(lv, t); /* area type has no quad or sphere option */ diff --git a/source/blender/render/intern/source/texture_ocean.c b/source/blender/render/intern/source/texture_ocean.c index a7547479093..0d68c40be0f 100644 --- a/source/blender/render/intern/source/texture_ocean.c +++ b/source/blender/render/intern/source/texture_ocean.c @@ -23,6 +23,10 @@ * ***** END GPL LICENSE BLOCK ***** */ +/** \file blender/blenkernel/intern/texture_ocean.c + * \ingroup bke + */ + #include <stddef.h> #include "BLI_math.h" diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index 3f19e77946c..0936d5fcef9 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -109,8 +109,8 @@ static int load_frame_blendervoxel(VoxelData *vd, FILE *fp, int frame) static int load_frame_raw8(VoxelData *vd, FILE *fp, int frame) { const size_t size = vd_resol_size(vd); + size_t i; char *data_c; - int i; if (is_vd_res_ok(vd) == FALSE) return 0; diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index d65db9d47f8..a8ccd1f362f 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -911,7 +911,7 @@ void hoco_to_zco(ZSpan *zspan, float zco[3], const float hoco[4]) void zbufclipwire(ZSpan *zspan, int obi, int zvlnr, int ec, const float ho1[4], const float ho2[4], const float ho3[4], const float ho4[4], - int c1, int c2, int c3, int c4) + const int c1, const int c2, const int c3, const int c4) { float vez[20]; int and, or; diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 8894be111e7..84b376edcd8 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -40,6 +40,7 @@ /* dna-savable wmStructs here */ #include "DNA_windowmanager_types.h" #include "WM_keymap.h" +#include "BLI_compiler_attrs.h" #ifdef __cplusplus extern "C" { @@ -76,17 +77,9 @@ void WM_init_native_pixels(bool do_it); void WM_init (struct bContext *C, int argc, const char **argv); void WM_exit_ext (struct bContext *C, const short do_python); -void WM_exit (struct bContext *C) -#if defined(__GNUC__) || defined(__clang__) -__attribute__((noreturn)) -#endif -; +void WM_exit (struct bContext *C) ATTR_NORETURN; -void WM_main (struct bContext *C) -#if defined(__GNUC__) || defined(__clang__) -__attribute__((noreturn)) -#endif -; +void WM_main (struct bContext *C) ATTR_NORETURN; bool WM_init_game (struct bContext *C); void WM_init_splash (struct bContext *C); @@ -118,9 +111,9 @@ void WM_autosave_init(struct wmWindowManager *wm); void WM_recover_last_session(struct bContext *C, struct ReportList *reports); /* mouse cursors */ -void WM_cursor_set (struct wmWindow *win, int curs); -void WM_cursor_modal (struct wmWindow *win, int curs); -void WM_cursor_restore (struct wmWindow *win); +void WM_cursor_set(struct wmWindow *win, int curs); +void WM_cursor_modal_set(struct wmWindow *win, int curs); +void WM_cursor_modal_restore(struct wmWindow *win); void WM_cursor_wait (bool val); void WM_cursor_grab_enable(struct wmWindow *win, bool wrap, bool hide, int bounds[4]); void WM_cursor_grab_disable(struct wmWindow *win, int mouse_ungrab_xy[2]); @@ -151,9 +144,9 @@ struct wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap); struct wmEventHandler *WM_event_add_ui_handler( - const struct bContext *C, ListBase *handlers, - int (*func)(struct bContext *C, const struct wmEvent *event, void *userdata), - void (*remove)(struct bContext *C, void *userdata), void *userdata); + const struct bContext *C, ListBase *handlers, + int (*func)(struct bContext *C, const struct wmEvent *event, void *userdata), + void (*remove)(struct bContext *C, void *userdata), void *userdata); void WM_event_remove_ui_handler(ListBase *handlers, int (*func)(struct bContext *C, const struct wmEvent *event, void *userdata), @@ -180,11 +173,7 @@ void WM_main_remove_notifier_reference(const void *reference); /* reports */ void WM_report(const struct bContext *C, ReportType type, const char *message); -void WM_reportf(const struct bContext *C, ReportType type, const char *format, ...) -#ifdef __GNUC__ -__attribute__ ((format(printf, 3, 4))) -#endif -; +void WM_reportf(const struct bContext *C, ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4); void wm_event_add(struct wmWindow *win, const struct wmEvent *event_to_add); void wm_event_init_from_window(struct wmWindow *win, struct wmEvent *event); @@ -197,7 +186,8 @@ void WM_event_timer_sleep(struct wmWindowManager *wm, struct wmWindow *win, str /* operator api, default callbacks */ /* invoke callback, uses enum property named "type" */ -int WM_operator_view3d_distance_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); +void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op); +int WM_operator_smooth_viewtx_get(const struct wmOperator *op); int WM_menu_invoke (struct bContext *C, struct wmOperator *op, const struct wmEvent *event); int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); /* invoke callback, confirm menu + exec */ @@ -386,6 +376,7 @@ struct wmJob *WM_jobs_get(struct wmWindowManager *wm, struct wmWindow *win, void int WM_jobs_test(struct wmWindowManager *wm, void *owner, int job_type); float WM_jobs_progress(struct wmWindowManager *wm, void *owner); char *WM_jobs_name(struct wmWindowManager *wm, void *owner); +void *WM_jobs_customdata(struct wmWindowManager *wm, void *owner); int WM_jobs_is_running(struct wmJob *); void *WM_jobs_customdata_get(struct wmJob *); @@ -402,7 +393,7 @@ void WM_jobs_stop(struct wmWindowManager *wm, void *owner, void *startjob); void WM_jobs_kill(struct wmWindowManager *wm, void *owner, void (*)(void *, short int *, short int *, float *)); void WM_jobs_kill_all(struct wmWindowManager *wm); void WM_jobs_kill_all_except(struct wmWindowManager *wm, void *owner); -void WM_jobs_kill_type(struct wmWindowManager *wm, int job_type); +void WM_jobs_kill_type(struct wmWindowManager *wm, void *owner, int job_type); int WM_jobs_has_running(struct wmWindowManager *wm); diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h index cebafcea12d..121e5e401fa 100644 --- a/source/blender/windowmanager/WM_keymap.h +++ b/source/blender/windowmanager/WM_keymap.h @@ -44,7 +44,7 @@ struct EnumPropertyItem; wmKeyConfig *WM_keyconfig_new (struct wmWindowManager *wm, const char *idname); wmKeyConfig *WM_keyconfig_new_user(struct wmWindowManager *wm, const char *idname); -int WM_keyconfig_remove (struct wmWindowManager *wm, struct wmKeyConfig *keyconf); +bool WM_keyconfig_remove (struct wmWindowManager *wm, struct wmKeyConfig *keyconf); void WM_keyconfig_free (struct wmKeyConfig *keyconf); void WM_keyconfig_set_active(struct wmWindowManager *wm, const char *idname); @@ -64,7 +64,7 @@ wmKeyMapItem *WM_keymap_add_item(struct wmKeyMap *keymap, const char *idname, in wmKeyMapItem *WM_keymap_add_menu(struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier); -int WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi); +bool WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi); int WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, const int len); wmKeyMap *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int regionid); @@ -72,6 +72,7 @@ wmKeyMap *WM_keymap_find(struct wmKeyConfig *keyconf, const char *idname, int sp wmKeyMap *WM_keymap_find_all(const struct bContext *C, const char *idname, int spaceid, int regionid); wmKeyMap *WM_keymap_active(struct wmWindowManager *wm, struct wmKeyMap *keymap); wmKeyMap *WM_keymap_guess_opname(const struct bContext *C, const char *opname); +bool WM_keymap_remove(struct wmKeyConfig *keyconfig, struct wmKeyMap *keymap); wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id); int WM_keymap_item_compare(struct wmKeyMapItem *k1, struct wmKeyMapItem *k2); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index f1932c8aa97..ac9af832671 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -115,6 +115,7 @@ struct ImBuf; #include "RNA_types.h" #include "DNA_listBase.h" +#include "BLI_compiler_attrs.h" /* exported types for WM */ #include "wm_cursors.h" @@ -260,7 +261,6 @@ typedef struct wmNotifier { #define ND_EDITOR_CHANGED (6<<16) /*sent to new editors after switching to them*/ #define ND_SCREENSET (7<<16) #define ND_SKETCH (8<<16) -#define ND_SUBWINACTIVE (9<<16) /* NC_SCENE Scene */ #define ND_SCENEBROWSE (1<<16) @@ -522,12 +522,8 @@ typedef struct wmOperatorType { * parameters may be provided through operator properties. cannot use * any interface code or input device state. * - see defines below for return values */ - int (*exec)(struct bContext *, struct wmOperator *) -#ifdef __GNUC__ - __attribute__((warn_unused_result)) -#endif - ; - + int (*exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT; + /* this callback executes on a running operator whenever as property * is changed. It can correct its own properties or report errors for * invalid settings in exceptional cases. @@ -538,25 +534,13 @@ typedef struct wmOperatorType { * any further events are handled in modal. if the operation is * canceled due to some external reason, cancel is called * - see defines below for return values */ - int (*invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) -#ifdef __GNUC__ - __attribute__((warn_unused_result)) -#endif - ; + int (*invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT; int (*cancel)(struct bContext *, struct wmOperator *); - int (*modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) -#ifdef __GNUC__ - __attribute__((warn_unused_result)) -#endif - ; + int (*modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT; /* verify if the operator can be executed in the current context, note * that the operator might still fail to execute even if this return true */ - int (*poll)(struct bContext *) -#ifdef __GNUC__ - __attribute__((warn_unused_result)) -#endif - ; + int (*poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT; /* optional panel for redo and repeat, autogenerated if not set */ void (*ui)(struct bContext *, struct wmOperator *); @@ -580,11 +564,7 @@ typedef struct wmOperatorType { /* only used for operators defined with python * use to store pointers to python functions */ void *pyop_data; - int (*pyop_poll)(struct bContext *, struct wmOperatorType *ot) -#ifdef __GNUC__ - __attribute__((warn_unused_result)) -#endif - ; + int (*pyop_poll)(struct bContext *, struct wmOperatorType *ot) ATTR_WARN_UNUSED_RESULT; /* RNA integration */ ExtensionRNA ext; diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 89c0cde2e88..74c066d1d86 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -156,8 +156,7 @@ void WM_operator_stack_clear(wmWindowManager *wm) { wmOperator *op; - while ((op = wm->operators.first)) { - BLI_remlink(&wm->operators, op); + while ((op = BLI_pophead(&wm->operators))) { WM_operator_free(op); } @@ -226,7 +225,7 @@ void WM_uilisttype_freelink(uiListType *ult) /* called on initialize WM_init() */ void WM_uilisttype_init(void) { - uilisttypes_hash = BLI_ghash_str_new("uilisttypes_hash gh"); + uilisttypes_hash = BLI_ghash_str_new_ex("uilisttypes_hash gh", 16); } void WM_uilisttype_free(void) @@ -279,7 +278,8 @@ void WM_menutype_freelink(MenuType *mt) /* called on initialize WM_init() */ void WM_menutype_init(void) { - menutypes_hash = BLI_ghash_str_new("menutypes_hash gh"); + /* reserve size is set based on blender default setup */ + menutypes_hash = BLI_ghash_str_new_ex("menutypes_hash gh", 512); } void WM_menutype_free(void) @@ -413,20 +413,17 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) if (wm->autosavetimer) wm_autosave_timer_ended(wm); - while ((win = wm->windows.first)) { - BLI_remlink(&wm->windows, win); + while ((win = BLI_pophead(&wm->windows))) { win->screen = NULL; /* prevent draw clear to use screen */ wm_draw_window_clear(win); wm_window_free(C, wm, win); } - while ((op = wm->operators.first)) { - BLI_remlink(&wm->operators, op); + while ((op = BLI_pophead(&wm->operators))) { WM_operator_free(op); } - while ((keyconf = wm->keyconfigs.first)) { - BLI_remlink(&wm->keyconfigs, keyconf); + while ((keyconf = BLI_pophead(&wm->keyconfigs))) { WM_keyconfig_free(keyconf); } diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index 515f80b0ade..9b308553006 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -49,6 +49,7 @@ #include "WM_types.h" #include "WM_api.h" #include "wm_cursors.h" +#include "wm_window.h" /* XXX this still is mess from old code */ @@ -149,7 +150,7 @@ void WM_cursor_set(wmWindow *win, int curs) } } -void WM_cursor_modal(wmWindow *win, int val) +void WM_cursor_modal_set(wmWindow *win, int val) { if (win->lastcursor == 0) win->lastcursor = win->cursor; @@ -157,7 +158,7 @@ void WM_cursor_modal(wmWindow *win, int val) WM_cursor_set(win, val); } -void WM_cursor_restore(wmWindow *win) +void WM_cursor_modal_restore(wmWindow *win) { win->modalcursor = 0; if (win->lastcursor) @@ -174,10 +175,10 @@ void WM_cursor_wait(bool val) for (; win; win = win->next) { if (val) { - WM_cursor_modal(win, BC_WAITCURSOR); + WM_cursor_modal_set(win, BC_WAITCURSOR); } else { - WM_cursor_restore(win); + WM_cursor_modal_restore(win); } } } @@ -233,25 +234,32 @@ void WM_cursor_grab_disable(wmWindow *win, int mouse_ungrab_xy[2]) } } +static void wm_cursor_warp_relative(wmWindow *win, int x, int y) +{ + /* note: don't use wmEvent coords because of continuous grab [#36409] */ + int cx, cy; + wm_get_cursor_position(win, &cx, &cy); + WM_cursor_warp(win, cx + x, cy + y); +} + /* give it a modal keymap one day? */ int wm_cursor_arrow_move(wmWindow *win, wmEvent *event) { if (win && event->val == KM_PRESS) { - if (event->type == UPARROWKEY) { - WM_cursor_warp(win, event->x, event->y + 1); + wm_cursor_warp_relative(win, 0, 1); return 1; } else if (event->type == DOWNARROWKEY) { - WM_cursor_warp(win, event->x, event->y - 1); + wm_cursor_warp_relative(win, 0, -1); return 1; } else if (event->type == LEFTARROWKEY) { - WM_cursor_warp(win, event->x - 1, event->y); + wm_cursor_warp_relative(win, -1, 0); return 1; } else if (event->type == RIGHTARROWKEY) { - WM_cursor_warp(win, event->x + 1, event->y); + wm_cursor_warp_relative(win, 1, 0); return 1; } } diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 0c78338c18a..4c58089f4e7 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -226,17 +226,17 @@ static void wm_drop_operator_options(bContext *C, wmDrag *drag, wmEvent *event) /* check buttons (XXX todo rna and value) */ if (UI_but_active_drop_name(C) ) { - strcpy(drag->opname, IFACE_("Paste name")); + BLI_strncpy(drag->opname, IFACE_("Paste name"), sizeof(drag->opname)); } else { const char *opname = wm_dropbox_active(C, drag, event); if (opname) { - BLI_strncpy(drag->opname, opname, FILE_MAX); - // WM_cursor_modal(win, CURSOR_COPY); + BLI_strncpy(drag->opname, opname, sizeof(drag->opname)); + // WM_cursor_modal_set(win, CURSOR_COPY); } // else - // WM_cursor_restore(win); + // WM_cursor_modal_restore(win); /* unsure about cursor type, feels to be too much */ } } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index b4f193bdbe6..825c1ca9252 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -85,10 +85,11 @@ # include "RNA_enum_types.h" #endif +static void wm_notifier_clear(wmNotifier *note); static void update_tablet_data(wmWindow *win, wmEvent *event); static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, - short context, short poll_only); + const short context, const bool poll_only); /* ************ event management ************** */ @@ -126,8 +127,7 @@ void wm_event_free_all(wmWindow *win) { wmEvent *event; - while ((event = win->queue.first)) { - BLI_remlink(&win->queue, event); + while ((event = BLI_pophead(&win->queue))) { wm_event_free(event); } } @@ -218,19 +218,18 @@ void WM_main_remove_notifier_reference(const void *reference) note_next = note->next; if (note->reference == reference) { - BLI_remlink(&wm->queue, note); - MEM_freeN(note); + /* don't remove because this causes problems for #wm_event_do_notifiers + * which may be looping on the data (deleting screens) */ + wm_notifier_clear(note); } } } } -static wmNotifier *wm_notifier_next(wmWindowManager *wm) +static void wm_notifier_clear(wmNotifier *note) { - wmNotifier *note = wm->queue.first; - - if (note) BLI_remlink(&wm->queue, note); - return note; + /* NULL the entire notifier, only leaving (next, prev) members intact */ + memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link)); } /* called in mainloop */ @@ -265,7 +264,6 @@ void wm_event_do_notifiers(bContext *C) if (note->category == NC_SCREEN) { if (note->data == ND_SCREENBROWSE) { /* free popup handlers only [#35434] */ - wmWindow *win = CTX_wm_window(C); UI_remove_popup_handlers_all(C, &win->modalhandlers); @@ -308,7 +306,7 @@ void wm_event_do_notifiers(bContext *C) } /* the notifiers are sent without context, to keep it clean */ - while ( (note = wm_notifier_next(wm)) ) { + while ((note = BLI_pophead(&wm->queue))) { for (win = wm->windows.first; win; win = win->next) { /* filter out notifiers */ @@ -493,7 +491,7 @@ int WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context) static void wm_operator_print(bContext *C, wmOperator *op) { /* context is needed for enum function */ - char *buf = WM_operator_pystring(C, op->type, op->ptr, 1); + char *buf = WM_operator_pystring(C, op->type, op->ptr, false); printf("%s\n", buf); MEM_freeN(buf); } @@ -628,7 +626,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, int cal if (op->type->flag & OPTYPE_REGISTER) { if (G.background == 0) { /* ends up printing these in the terminal, gets annoying */ /* Report the python string representation of the operator */ - char *buf = WM_operator_pystring(C, op->type, op->ptr, 1); + char *buf = WM_operator_pystring(C, op->type, op->ptr, false); BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf); MEM_freeN(buf); } @@ -662,7 +660,7 @@ static void wm_operator_finished(bContext *C, wmOperator *op, int repeat) if (repeat == 0) { if (G.debug & G_DEBUG_WM) { - char *buf = WM_operator_pystring(C, op->type, op->ptr, 1); + char *buf = WM_operator_pystring(C, op->type, op->ptr, false); BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf); MEM_freeN(buf); } @@ -964,9 +962,8 @@ int WM_operator_last_properties_store(wmOperator *UNUSED(op)) #endif static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, - PointerRNA *properties, ReportList *reports, short poll_only) + PointerRNA *properties, ReportList *reports, const bool poll_only) { - wmWindowManager *wm = CTX_wm_manager(C); int retval = OPERATOR_PASS_THROUGH; /* this is done because complicated setup is done to call this function that is better not duplicated */ @@ -974,9 +971,12 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, return WM_operator_poll(C, ot); if (WM_operator_poll(C, ot)) { + wmWindowManager *wm = CTX_wm_manager(C); wmOperator *op = wm_operator_create(wm, ot, properties, reports); /* if reports == NULL, they'll be initialized */ const short is_nested_call = (wm->op_undo_depth != 0); + op->flag |= OP_IS_INVOKE; + /* initialize setting from previous run */ if (!is_nested_call) { /* not called by py script */ WM_operator_last_properties_init(op); @@ -1102,9 +1102,8 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, * * invokes operator in context */ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, - short context, short poll_only) + const short context, const bool poll_only) { - wmWindow *window = CTX_wm_window(C); wmEvent *event; int retval; @@ -1113,16 +1112,23 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA /* dummie test */ if (ot && C) { + wmWindow *window = CTX_wm_window(C); + switch (context) { case WM_OP_INVOKE_DEFAULT: case WM_OP_INVOKE_REGION_WIN: case WM_OP_INVOKE_AREA: case WM_OP_INVOKE_SCREEN: /* window is needed for invoke, cancel operator */ - if (window == NULL) + if (window == NULL) { + if (poll_only) { + CTX_wm_operator_poll_msg_set(C, "Missing 'window' in context"); + } return 0; - else + } + else { event = window->eventstate; + } break; default: event = NULL; @@ -1323,9 +1329,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) wmWindowManager *wm = CTX_wm_manager(C); /* C is zero on freeing database, modal handlers then already were freed */ - while ((handler = handlers->first)) { - BLI_remlink(handlers, handler); - + while ((handler = BLI_pophead(handlers))) { if (handler->op) { if (handler->op->type->cancel) { ScrArea *area = CTX_wm_area(C); @@ -2100,7 +2104,7 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even win->screen->do_draw_drag = TRUE; /* restore cursor (disabled, see wm_dragdrop.c) */ - // WM_cursor_restore(win); + // WM_cursor_modal_restore(win); } /* overlap fails otherwise */ @@ -2167,7 +2171,7 @@ void wm_event_do_handlers(bContext *C) while ( (event = win->queue.first) ) { int action = WM_HANDLER_CONTINUE; -#ifdef DEBUG +#ifndef NDEBUG if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { printf("\n%s: Handling event\n", __func__); WM_event_print(event); diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index f4b50667b2f..cc4d422331d 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -554,7 +554,7 @@ int wm_homefile_read(bContext *C, ReportList *UNUSED(reports), short from_memory } if (success == 0) { - success = BKE_read_file_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, NULL); + success = BKE_read_file_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, NULL, true); if (wmbase.first == NULL) wm_clear_default_size(C); BLI_init_temporary_dir(U.tempdir); @@ -810,15 +810,14 @@ int write_crash_blend(void) } } -int wm_file_write(bContext *C, const char *target, int fileflags, ReportList *reports) +int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *reports) { Library *li; int len; - char filepath[FILE_MAX]; int *thumb = NULL; ImBuf *ibuf_thumb = NULL; - len = strlen(target); + len = strlen(filepath); if (len == 0) { BKE_report(reports, RPT_ERROR, "Path is empty, cannot save"); @@ -830,9 +829,9 @@ int wm_file_write(bContext *C, const char *target, int fileflags, ReportList *re return -1; } - BLI_strncpy(filepath, target, FILE_MAX); - BLI_replace_extension(filepath, FILE_MAX, ".blend"); - /* don't use 'target' anymore */ + /* note: used to replace the file extension (to ensure '.blend'), + * no need to now because the operator ensures, + * its handy for scripts to save to a predefined name without blender editing it */ /* send the OnSave event */ for (li = G.main->library.first; li; li = li->id.next) { diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index adf159bcfee..05ee23e2361 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -40,6 +40,7 @@ #include "BLI_math.h" #include "BLI_scanfill.h" /* lasso tessellation */ #include "BLI_utildefines.h" +#include "BLI_lasso.h" #include "BKE_context.h" @@ -231,56 +232,73 @@ static void wm_gesture_draw_circle(wmGesture *gt) } -static void draw_filled_lasso(wmGesture *gt) +struct LassoFillData { + unsigned int *px; + int width; +}; + +static void draw_filled_lasso_px_cb(int x, int y, void *user_data) +{ + struct LassoFillData *data = user_data; + unsigned char *col = (unsigned char *)&(data->px[(y * data->width) + x]); + col[0] = col[1] = col[2] = 0xff; + col[3] = 0x10; +} + +static void draw_filled_lasso(wmWindow *win, wmGesture *gt) { - ScanFillContext sf_ctx; - ScanFillVert *sf_vert = NULL, *sf_vert_last = NULL, *sf_vert_first = NULL; - ScanFillFace *sf_tri; short *lasso = (short *)gt->customdata; + const int tot = gt->points; + int (*moves)[2] = MEM_mallocN(sizeof(*moves) * (tot + 1), __func__); int i; - - BLI_scanfill_begin(&sf_ctx); - for (i = 0; i < gt->points; i++, lasso += 2) { - float co[3]; - - co[0] = (float)lasso[0]; - co[1] = (float)lasso[1]; - co[2] = 0.0f; - - sf_vert = BLI_scanfill_vert_add(&sf_ctx, co); - if (sf_vert_last) - /* e = */ /* UNUSED */ BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert); - sf_vert_last = sf_vert; - if (sf_vert_first == NULL) sf_vert_first = sf_vert; + rcti rect; + rcti rect_win; + + for (i = 0; i < tot; i++, lasso += 2) { + moves[i][0] = lasso[0]; + moves[i][1] = lasso[1]; } - - /* highly unlikely this will fail, but could crash if (gt->points == 0) */ - if (sf_vert_first) { - const float zvec[3] = {0.0f, 0.0f, 1.0f}; - BLI_scanfill_edge_add(&sf_ctx, sf_vert_first, sf_vert); - BLI_scanfill_calc_ex(&sf_ctx, BLI_SCANFILL_CALC_REMOVE_DOUBLES | BLI_SCANFILL_CALC_HOLES, zvec); - + + BLI_lasso_boundbox(&rect, (const int (*)[2])moves, tot); + + wm_subwindow_getrect(win, gt->swinid, &rect_win); + BLI_rcti_translate(&rect, rect_win.xmin, rect_win.ymin); + BLI_rcti_isect(&rect_win, &rect, &rect); + BLI_rcti_translate(&rect, -rect_win.xmin, -rect_win.ymin); + + /* highly unlikely this will fail, but could crash if (tot == 0) */ + if (BLI_rcti_is_empty(&rect) == false) { + const int w = BLI_rcti_size_x(&rect); + const int h = BLI_rcti_size_y(&rect); + unsigned int *pixel_buf = MEM_callocN(sizeof(*pixel_buf) * w * h, __func__); + struct LassoFillData lasso_fill_data = {pixel_buf, w}; + + fill_poly_v2i_n( + rect.xmin, rect.ymin, rect.xmax, rect.ymax, + (const int (*)[2])moves, tot, + draw_filled_lasso_px_cb, &lasso_fill_data); + glEnable(GL_BLEND); - glColor4f(1.0, 1.0, 1.0, 0.05); - glBegin(GL_TRIANGLES); - for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { - glVertex2fv(sf_tri->v1->co); - glVertex2fv(sf_tri->v2->co); - glVertex2fv(sf_tri->v3->co); - } - glEnd(); + // glColor4f(1.0, 1.0, 1.0, 0.05); + + glRasterPos2f(rect.xmin, rect.ymin); + + glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixel_buf); + glDisable(GL_BLEND); - - BLI_scanfill_end(&sf_ctx); + MEM_freeN(pixel_buf); } + + MEM_freeN(moves); } -static void wm_gesture_draw_lasso(wmGesture *gt) + +static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt) { short *lasso = (short *)gt->customdata; int i; - draw_filled_lasso(gt); + draw_filled_lasso(win, gt); glEnable(GL_LINE_STIPPLE); glColor3ub(96, 96, 96); @@ -347,9 +365,9 @@ void wm_gesture_draw(wmWindow *win) wm_gesture_draw_cross(win, gt); } else if (gt->type == WM_GESTURE_LINES) - wm_gesture_draw_lasso(gt); + wm_gesture_draw_lasso(win, gt); else if (gt->type == WM_GESTURE_LASSO) - wm_gesture_draw_lasso(gt); + wm_gesture_draw_lasso(win, gt); else if (gt->type == WM_GESTURE_STRAIGHTLINE) wm_gesture_draw_line(gt); } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 63cf1eeb40d..4e9b849af40 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -51,6 +51,7 @@ #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_threads.h" #include "BLI_utildefines.h" #include "BKE_blender.h" @@ -510,6 +511,8 @@ void WM_exit_ext(bContext *C, const short do_python) GHOST_DisposeSystemPaths(); + BLI_threadapi_exit(); + if (MEM_get_memory_blocks_in_use() != 0) { printf("Error: Not freed memory blocks: %d\n", MEM_get_memory_blocks_in_use()); MEM_printmemlist(); diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index c6e067dc2f9..c9c3d2df788 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -255,6 +255,17 @@ char *WM_jobs_name(wmWindowManager *wm, void *owner) return NULL; } +void *WM_jobs_customdata(wmWindowManager *wm, void *owner) +{ + wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY); + + if (wm_job) + return WM_jobs_customdata_get(wm_job); + + return NULL; + +} + int WM_jobs_is_running(wmJob *wm_job) { return wm_job->running; @@ -463,15 +474,16 @@ void WM_jobs_kill_all_except(wmWindowManager *wm, void *owner) } -void WM_jobs_kill_type(struct wmWindowManager *wm, int job_type) +void WM_jobs_kill_type(struct wmWindowManager *wm, void *owner, int job_type) { wmJob *wm_job, *next_job; for (wm_job = wm->jobs.first; wm_job; wm_job = next_job) { next_job = wm_job->next; - if (wm_job->job_type == job_type) - wm_jobs_kill_job(wm, wm_job); + if (!owner || wm_job->owner == owner) + if (wm_job->job_type == job_type) + wm_jobs_kill_job(wm, wm_job); } } diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index ff805579b44..43a98a4600b 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -101,7 +101,7 @@ static int wm_keymap_item_equals_result(wmKeyMapItem *a, wmKeyMapItem *b) if (strcmp(a->idname, b->idname) != 0) return 0; - if (!RNA_struct_equals(a->ptr, b->ptr, true)) + if (!RNA_struct_equals(a->ptr, b->ptr, RNA_EQ_UNSET_MATCH_NONE)) return 0; if ((a->flag & KMI_INACTIVE) != (b->flag & KMI_INACTIVE)) @@ -190,7 +190,7 @@ wmKeyConfig *WM_keyconfig_new_user(wmWindowManager *wm, const char *idname) return keyconf; } -int WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf) +bool WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf) { if (BLI_findindex(&wm->keyconfigs, keyconf) != -1) { if (strncmp(U.keyconfigstr, keyconf->idname, sizeof(U.keyconfigstr)) == 0) { @@ -201,10 +201,10 @@ int WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf) BLI_remlink(&wm->keyconfigs, keyconf); WM_keyconfig_free(keyconf); - return TRUE; + return true; } else { - return FALSE; + return false; } } @@ -299,6 +299,21 @@ void WM_keymap_free(wmKeyMap *keymap) BLI_freelistN(&keymap->items); } +bool WM_keymap_remove(wmKeyConfig *keyconf, wmKeyMap *keymap) +{ + if (BLI_findindex(&keyconf->keymaps, keymap) != -1) { + + WM_keymap_free(keymap); + BLI_remlink(&keyconf->keymaps, keymap); + MEM_freeN(keymap); + + return true; + } + else { + return false; + } +} + static void keymap_event_set(wmKeyMapItem *kmi, short type, short val, int modifier, short keymodifier) { kmi->type = type; @@ -375,7 +390,7 @@ wmKeyMapItem *WM_keymap_add_menu(wmKeyMap *keymap, const char *idname, int type, return kmi; } -int WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi) +bool WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi) { if (BLI_findindex(&keymap->items, kmi) != -1) { if (kmi->ptr) { @@ -385,10 +400,10 @@ int WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi) BLI_freelinkN(&keymap->items, kmi); WM_keyconfig_update_tag(keymap, NULL); - return TRUE; + return true; } else { - return FALSE; + return false; } } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index f1a9f6dc007..5e1e5890c6b 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -542,22 +542,20 @@ char *WM_operator_pystring(bContext *C, wmOperatorType *ot, PointerRNA *opptr, i /* only to get the orginal props for comparisons */ PointerRNA opptr_default; - if (all_args == 0 || opptr == NULL) { + if (opptr == NULL) { WM_operator_properties_create_ptr(&opptr_default, ot); - - if (opptr == NULL) - opptr = &opptr_default; + opptr = &opptr_default; } WM_operator_py_idname(idname_py, ot->idname); BLI_dynstr_appendf(dynstr, "bpy.ops.%s(", idname_py); - cstring_args = RNA_pointer_as_string_keywords(C, opptr, &opptr_default, FALSE, + cstring_args = RNA_pointer_as_string_keywords(C, opptr, false, all_args, max_prop_length); BLI_dynstr_append(dynstr, cstring_args); MEM_freeN(cstring_args); - if (all_args == 0 || opptr == &opptr_default) + if (opptr == &opptr_default) WM_operator_properties_free(&opptr_default); BLI_dynstr_append(dynstr, ")"); @@ -796,7 +794,7 @@ void WM_operator_properties_alloc(PointerRNA **ptr, IDProperty **properties, con void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context) { - RNA_STRUCT_BEGIN(ptr, prop) + RNA_STRUCT_BEGIN (ptr, prop) { switch (RNA_property_type(prop)) { case PROP_ENUM: @@ -833,7 +831,7 @@ void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context) int WM_operator_properties_default(PointerRNA *ptr, const bool do_update) { int is_change = FALSE; - RNA_STRUCT_BEGIN(ptr, prop) + RNA_STRUCT_BEGIN (ptr, prop) { switch (RNA_property_type(prop)) { case PROP_POINTER: @@ -866,7 +864,7 @@ void WM_operator_properties_reset(wmOperator *op) PropertyRNA *iterprop; iterprop = RNA_struct_iterator_property(op->type->srna); - RNA_PROP_BEGIN(op->ptr, itemptr, iterprop) + RNA_PROP_BEGIN (op->ptr, itemptr, iterprop) { PropertyRNA *prop = itemptr.data; @@ -892,33 +890,38 @@ void WM_operator_properties_free(PointerRNA *ptr) /* ************ default op callbacks, exported *********** */ -int WM_operator_view3d_distance_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *UNUSED(event)) +void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op) { - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); + if (op->flag & OP_IS_INVOKE) { + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); - const float dia = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) : ED_scene_grid_scale(scene, NULL); + const float dia = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) : ED_scene_grid_scale(scene, NULL); - /* always run, so the values are initialized, - * otherwise we may get differ behavior when (dia != 1.0) */ - RNA_STRUCT_BEGIN(op->ptr, prop) - { - if (RNA_property_type(prop) == PROP_FLOAT) { - PropertySubType pstype = RNA_property_subtype(prop); - if (pstype == PROP_DISTANCE) { - /* we don't support arrays yet */ - BLI_assert(RNA_property_array_check(prop) == FALSE); - /* initialize */ - if (!RNA_property_is_set_ex(op->ptr, prop, FALSE)) { - const float value = RNA_property_float_get_default(op->ptr, prop) * dia; - RNA_property_float_set(op->ptr, prop, value); + /* always run, so the values are initialized, + * otherwise we may get differ behavior when (dia != 1.0) */ + RNA_STRUCT_BEGIN (op->ptr, prop) + { + if (RNA_property_type(prop) == PROP_FLOAT) { + PropertySubType pstype = RNA_property_subtype(prop); + if (pstype == PROP_DISTANCE) { + /* we don't support arrays yet */ + BLI_assert(RNA_property_array_check(prop) == FALSE); + /* initialize */ + if (!RNA_property_is_set_ex(op->ptr, prop, FALSE)) { + const float value = RNA_property_float_get_default(op->ptr, prop) * dia; + RNA_property_float_set(op->ptr, prop, value); + } } } } + RNA_STRUCT_END; } - RNA_STRUCT_END; +} - return op->type->exec(C, op); +int WM_operator_smooth_viewtx_get(const wmOperator *op) +{ + return (op->flag & OP_IS_INVOKE) ? U.smooth_viewtx : 0; } /* invoke callback, uses enum property named "type" */ @@ -1137,10 +1140,16 @@ void WM_operator_properties_select_all(wmOperatorType *ot) void WM_operator_properties_border(wmOperatorType *ot) { - RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX); - RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX); - RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX); - RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX); + PropertyRNA *prop; + + prop = RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } void WM_operator_properties_border_to_rcti(struct wmOperator *op, rcti *rect) @@ -1171,14 +1180,18 @@ void WM_operator_properties_mouse_select(wmOperatorType *ot) void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor) { - RNA_def_int(ot->srna, "xstart", 0, INT_MIN, INT_MAX, "X Start", "", INT_MIN, INT_MAX); - RNA_def_int(ot->srna, "xend", 0, INT_MIN, INT_MAX, "X End", "", INT_MIN, INT_MAX); - RNA_def_int(ot->srna, "ystart", 0, INT_MIN, INT_MAX, "Y Start", "", INT_MIN, INT_MAX); - RNA_def_int(ot->srna, "yend", 0, INT_MIN, INT_MAX, "Y End", "", INT_MIN, INT_MAX); + PropertyRNA *prop; + + prop = RNA_def_int(ot->srna, "xstart", 0, INT_MIN, INT_MAX, "X Start", "", INT_MIN, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_int(ot->srna, "xend", 0, INT_MIN, INT_MAX, "X End", "", INT_MIN, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_int(ot->srna, "ystart", 0, INT_MIN, INT_MAX, "Y Start", "", INT_MIN, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_int(ot->srna, "yend", 0, INT_MIN, INT_MAX, "Y End", "", INT_MIN, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); if (cursor) { - PropertyRNA *prop; - prop = RNA_def_int(ot->srna, "cursor", cursor, 0, INT_MAX, "Cursor", "Mouse cursor style to use during the modal operator", 0, INT_MAX); RNA_def_property_flag(prop, PROP_HIDDEN); @@ -1553,7 +1566,7 @@ static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unused); -/* XXX: hack to refresh splash screen with updated prest menu name, +/* XXX: hack to refresh splash screen with updated preset menu name, * since popup blocks don't get regenerated like panels do */ static void wm_block_splash_refreshmenu(bContext *UNUSED(C), void *UNUSED(arg_block), void *UNUSED(arg)) { @@ -1668,7 +1681,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar uiItemStringO(col, IFACE_("Credits"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org/development/credits"); uiItemStringO(col, IFACE_("Release Log"), ICON_URL, "WM_OT_url_open", "url", - "http://www.blender.org/development/release-logs/blender-268"); + "http://www.blender.org/development/release-logs/blender-269"); uiItemStringO(col, IFACE_("Manual"), ICON_URL, "WM_OT_url_open", "url", "http://wiki.blender.org/index.php/Doc:2.6/Manual"); uiItemStringO(col, IFACE_("Blender Website"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org"); @@ -2253,7 +2266,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag); } else { - RNA_BEGIN(op->ptr, itemptr, "files") + RNA_BEGIN (op->ptr, itemptr, "files") { RNA_string_get(&itemptr, "name", name); BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag); @@ -2419,15 +2432,10 @@ static void WM_OT_recover_auto_save(wmOperatorType *ot) /* *************** save file as **************** */ -static void untitled(char *filepath) +static void wm_filepath_default(char *filepath) { - if (G.save_over == 0 && strlen(filepath) < FILE_MAX - 16) { - char *c = (char *)BLI_last_slash(filepath); - - if (c) - strcpy(&c[1], "untitled.blend"); - else - strcpy(filepath, "untitled.blend"); + if (G.save_over == false) { + BLI_ensure_filename(filepath, FILE_MAX, "untitled.blend"); } } @@ -2455,7 +2463,7 @@ static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent else BLI_strncpy(name, G.main->name, FILE_MAX); - untitled(name); + wm_filepath_default(name); RNA_string_set(op->ptr, "filepath", name); WM_event_add_fileselect(C, op); @@ -2471,11 +2479,12 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) save_set_compress(op); - if (RNA_struct_property_is_set(op->ptr, "filepath")) + if (RNA_struct_property_is_set(op->ptr, "filepath")) { RNA_string_get(op->ptr, "filepath", path); + } else { BLI_strncpy(path, G.main->name, FILE_MAX); - untitled(path); + wm_filepath_default(path); } fileflags = G.fileflags & ~G_FILE_USERPREFS; @@ -2566,7 +2575,7 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U else BLI_strncpy(name, G.main->name, FILE_MAX); - untitled(name); + wm_filepath_default(name); RNA_string_set(op->ptr, "filepath", name); @@ -2750,7 +2759,7 @@ static void wm_gesture_end(bContext *C, wmOperator *op) ED_area_tag_redraw(CTX_wm_area(C)); if (RNA_struct_find_property(op->ptr, "cursor") ) - WM_cursor_restore(CTX_wm_window(C)); + WM_cursor_modal_restore(CTX_wm_window(C)); } int WM_border_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -3059,7 +3068,7 @@ int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event) wm_gesture_tag_redraw(C); if (RNA_struct_find_property(op->ptr, "cursor") ) - WM_cursor_modal(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor")); + WM_cursor_modal_set(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor")); return OPERATOR_RUNNING_MODAL; } @@ -3074,7 +3083,7 @@ int WM_gesture_lines_invoke(bContext *C, wmOperator *op, const wmEvent *event) wm_gesture_tag_redraw(C); if (RNA_struct_find_property(op->ptr, "cursor") ) - WM_cursor_modal(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor")); + WM_cursor_modal_set(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor")); return OPERATOR_RUNNING_MODAL; } @@ -3199,7 +3208,7 @@ const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C), wmOperator *op, int i = 0; mcords = MEM_mallocN(sizeof(int) * 2 * len, __func__); - RNA_PROP_BEGIN(op->ptr, itemptr, prop) + RNA_PROP_BEGIN (op->ptr, itemptr, prop) { float loc[2]; @@ -3225,7 +3234,7 @@ const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C), wmOperator *op, static int gesture_lasso_exec(bContext *C, wmOperator *op) { - RNA_BEGIN(op->ptr, itemptr, "path") + RNA_BEGIN (op->ptr, itemptr, "path") { float loc[2]; @@ -3291,7 +3300,7 @@ int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, const wmEvent *e wm_gesture_tag_redraw(C); if (RNA_struct_find_property(op->ptr, "cursor") ) - WM_cursor_modal(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor")); + WM_cursor_modal_set(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor")); return OPERATOR_RUNNING_MODAL; } @@ -3385,6 +3394,7 @@ typedef struct { int initial_mouse[2]; unsigned int gltex; ListBase orig_paintcursors; + bool use_secondary_tex; void *cursor; } RadialControl; @@ -3428,7 +3438,7 @@ static void radial_control_set_tex(RadialControl *rc) switch (RNA_type_to_ID_code(rc->image_id_ptr.type)) { case ID_BR: - if ((ibuf = BKE_brush_gen_radial_control_imbuf(rc->image_id_ptr.data))) { + if ((ibuf = BKE_brush_gen_radial_control_imbuf(rc->image_id_ptr.data, rc->use_secondary_tex))) { glGenTextures(1, &rc->gltex); glBindTexture(GL_TEXTURE_2D, rc->gltex); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, ibuf->x, ibuf->y, 0, @@ -3701,6 +3711,8 @@ static int radial_control_get_properties(bContext *C, wmOperator *op) } } + rc->use_secondary_tex = RNA_boolean_get(op->ptr, "secondary_tex"); + return 1; } @@ -3894,6 +3906,7 @@ static void WM_OT_radial_control(wmOperatorType *ot) RNA_def_string(ot->srna, "fill_color_path", "", 0, "Fill Color Path", "Path of property used to set the fill color of the control"); RNA_def_string(ot->srna, "zoom_path", "", 0, "Zoom Path", "Path of property used to set the zoom level for the control"); RNA_def_string(ot->srna, "image_id", "", 0, "Image ID", "Path of ID that is used to generate an image for the control"); + RNA_def_boolean(ot->srna, "secondary_tex", 0, "Secondary Texture", "Tweak brush secondary/mask texture"); } /* ************************** timer for testing ***************** */ @@ -4142,7 +4155,8 @@ void wm_operatortype_free(void) /* called on initialize WM_init() */ void wm_operatortype_init(void) { - global_ops_hash = BLI_ghash_str_new("wm_operatortype_init gh"); + /* reserve size is set based on blender default setup */ + global_ops_hash = BLI_ghash_str_new_ex("wm_operatortype_init gh", 2048); WM_operatortype_append(WM_OT_window_duplicate); WM_operatortype_append(WM_OT_read_history); @@ -4259,6 +4273,7 @@ static void gesture_straightline_modal_keymap(wmKeyConfig *keyconf) /* assign map to operators */ WM_modalkeymap_assign(keymap, "IMAGE_OT_sample_line"); WM_modalkeymap_assign(keymap, "PAINT_OT_weight_gradient"); + WM_modalkeymap_assign(keymap, "MESH_OT_bisect"); } diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index e8ab1fef8b7..a02fc75a3fb 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * 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. diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 4ad4286b657..ae535ed45e8 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -148,6 +148,15 @@ void wm_subwindow_getmatrix(wmWindow *win, int swinid, float mat[4][4]) } } +void wm_subwindow_getrect(wmWindow *win, int swinid, rcti *r_rect) +{ + wmSubWindow *swin = swin_from_swinid(win, swinid); + + if (swin) { + *r_rect = swin->winrct; + } +} + /* always sets pixel-precise 2D window/view matrices */ /* coords is in whole pixels. xmin = 15, xmax = 16: means window is 2 pix big */ int wm_subwindow_open(wmWindow *win, rcti *winrct) diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 062107f834e..9e89c17e024 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -114,8 +114,8 @@ void wm_get_screensize(int *width_r, int *height_r) *height_r = uiheight; } -/* size of all screens, useful since the mouse is bound by this */ -void wm_get_screensize_all(int *width_r, int *height_r) +/* size of all screens (desktop), useful since the mouse is bound by this */ +void wm_get_desktopsize(int *width_r, int *height_r) { unsigned int uiwidth; unsigned int uiheight; @@ -375,15 +375,15 @@ static void wm_window_add_ghostwindow(const char *title, wmWindow *win) /* needed so we can detect the graphics card below */ GPU_extensions_init(); - /* set the state*/ - GHOST_SetWindowState(ghostwin, (GHOST_TWindowState)win->windowstate); - win->ghostwin = ghostwin; GHOST_SetWindowUserData(ghostwin, win); /* pointer back */ if (win->eventstate == NULL) win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state"); + /* set the state */ + GHOST_SetWindowState(ghostwin, (GHOST_TWindowState)win->windowstate); + /* until screens get drawn, make it nice gray */ glClearColor(0.55, 0.55, 0.55, 0.0); /* Crash on OSS ATI: bugs.launchpad.net/ubuntu/+source/mesa/+bug/656100 */ @@ -856,7 +856,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr GHOST_DisposeRectangle(client_rect); - wm_get_screensize_all(&scr_w, &scr_h); + wm_get_desktopsize(&scr_w, &scr_h); sizex = r - l; sizey = b - t; posx = l; diff --git a/source/blender/windowmanager/wm_subwindow.h b/source/blender/windowmanager/wm_subwindow.h index 064d00b0723..a70e7765ecf 100644 --- a/source/blender/windowmanager/wm_subwindow.h +++ b/source/blender/windowmanager/wm_subwindow.h @@ -45,6 +45,7 @@ void wm_subwindow_position(wmWindow *win, int swinid, rcti *winrct); void wm_subwindow_getsize(wmWindow *win, int swinid, int *x, int *y); void wm_subwindow_getorigin(wmWindow *win, int swinid, int *x, int *y); void wm_subwindow_getmatrix(wmWindow *win, int swinid, float mat[4][4]); +void wm_subwindow_getrect(wmWindow *win, int swinid, struct rcti *r_rect); unsigned int index_to_framebuffer(int index); diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index d7e938fec7c..e0639b098a8 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -40,7 +40,7 @@ void wm_ghost_init (bContext *C); void wm_ghost_exit(void); void wm_get_screensize(int *width_r, int *height_r); -void wm_get_screensize_all(int *width_r, int *height_r); +void wm_get_desktopsize(int *width_r, int *height_r); wmWindow *wm_window_new (bContext *C); void wm_window_free (bContext *C, wmWindowManager *wm, wmWindow *win); diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 21502492c05..f55f307e095 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -207,8 +207,11 @@ void WM_jobs_kill_all_except(struct wmWindowManager *wm) {STUB_ASSERT(0);} char *WM_clipboard_text_get(int selection) {STUB_ASSERT(0); return (char *)0;} void WM_clipboard_text_set(char *buf, int selection) {STUB_ASSERT(0);} -void WM_cursor_restore(struct wmWindow *win) {STUB_ASSERT(0);} -void WM_cursor_time(struct wmWindow *win, int nr) {STUB_ASSERT(0);} +void WM_cursor_set(struct wmWindow *win, int curor) {STUB_ASSERT(0);} +void WM_cursor_modal_set(struct wmWindow *win, int curor) {STUB_ASSERT(0);} +void WM_cursor_modal_restore(struct wmWindow *win) {STUB_ASSERT(0);} +void WM_cursor_time(struct wmWindow *win, int nr) {STUB_ASSERT(0);} +void WM_cursor_warp(struct wmWindow *win, int x, int y) {STUB_ASSERT(0);} void WM_uilisttype_init(void) {STUB_ASSERT(0);} struct uiListType *WM_uilisttype_find(const char *idname, int quiet) {STUB_ASSERT(0); return (struct uiListType *)NULL;} @@ -273,6 +276,7 @@ struct wmKeyMap *WM_keymap_list_find(struct ListBase *lb, char *idname, int spac struct wmKeyConfig *WM_keyconfig_new(struct wmWindowManager *wm, char *idname) {STUB_ASSERT(0); return (struct wmKeyConfig *) NULL;} struct wmKeyConfig *WM_keyconfig_new_user(struct wmWindowManager *wm, char *idname) {STUB_ASSERT(0); return (struct wmKeyConfig *) NULL;} void WM_keyconfig_remove(struct wmWindowManager *wm, char *idname) {STUB_ASSERT(0);} +void WM_keymap_remove(struct wmKeyConfig *keyconf, char *idname) {STUB_ASSERT(0);} void WM_keyconfig_set_active(struct wmWindowManager *wm, const char *idname) {STUB_ASSERT(0);} void WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi) {STUB_ASSERT(0);} void WM_keymap_restore_to_default(struct wmKeyMap *keymap) {STUB_ASSERT(0);} @@ -331,6 +335,7 @@ void ED_view3D_background_image_remove(struct View3D *v3d, struct BGpic *bgpic) void ED_view3D_background_image_clear(struct View3D *v3d) {STUB_ASSERT(0);} void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4]) {STUB_ASSERT(0);} float ED_view3d_grid_scale(struct Scene *scene, struct View3D *v3d, const char **grid_unit) {STUB_ASSERT(0); return 0.0f;} +void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa) {STUB_ASSERT(0);} void view3d_apply_mat4(float mat[4][4], float *ofs, float *quat, float *dist) {STUB_ASSERT(0);} int text_file_modified(struct Text *text) {STUB_ASSERT(0); return 0;} void ED_node_shader_default(struct bContext *C, struct ID *id) {STUB_ASSERT(0);} @@ -458,7 +463,7 @@ void uiTemplateLayers(struct uiLayout *layout, struct PointerRNA *ptr, char *pro void uiTemplateImageLayers(struct uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser) {STUB_ASSERT(0);} void uiTemplateList(struct uiLayout *layout, struct bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, - const char *active_propname, int rows, int maxrows, int layout_type) {STUB_ASSERT(0);} + const char *active_propname, int rows, int maxrows, int layout_type, int columns) {STUB_ASSERT(0);} void uiTemplateRunningJobs(struct uiLayout *layout, struct bContext *C) {STUB_ASSERT(0);} void uiTemplateOperatorSearch(struct uiLayout *layout) {STUB_ASSERT(0);} void uiTemplateHeader3D(struct uiLayout *layout, struct bContext *C) {STUB_ASSERT(0);} diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 8ff4ec445ea..b24339cff1b 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -234,8 +234,16 @@ set(BLENDER_TEXT_FILES ${CMAKE_SOURCE_DIR}/release/text/Python-license.txt ${CMAKE_SOURCE_DIR}/release/text/copyright.txt ${CMAKE_SOURCE_DIR}/release/text/readme.html + ${CMAKE_SOURCE_DIR}/release/datafiles/LICENSE-bfont.ttf.txt ) +if(WITH_INTERNATIONAL) + list(APPEND BLENDER_TEXT_FILES + ${CMAKE_SOURCE_DIR}/release/datafiles/LICENSE-droidsans.ttf.txt + ${CMAKE_SOURCE_DIR}/release/datafiles/LICENSE-bmonofont-i18n.ttf.txt + ) +endif() + # ----------------------------------------------------------------------------- # Platform Specific Var: TARGETDIR_VER @@ -992,6 +1000,10 @@ endif() list(APPEND BLENDER_SORTED_LIBS bf_quicktime) endif() + if(WITH_INPUT_NDOF) + list(APPEND BLENDER_SORTED_LIBS bf_intern_ghostndof3dconnexion) + endif() + if(WITH_MOD_BOOLEAN) list(APPEND BLENDER_SORTED_LIBS extern_carve) endif() diff --git a/source/creator/creator.c b/source/creator/creator.c index a710c07f34b..a3bce79b6e7 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -76,13 +76,13 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" #include "BLI_callbacks.h" +#include "BLI_blenlib.h" +#include "BLI_mempool.h" #include "DNA_ID.h" #include "DNA_scene_types.h" #include "DNA_userdef_types.h" -#include "BLI_blenlib.h" - #include "BKE_blender.h" #include "BKE_brush.h" #include "BKE_context.h" @@ -92,6 +92,7 @@ #include "BKE_library.h" #include "BKE_main.h" #include "BKE_material.h" +#include "BKE_modifier.h" #include "BKE_packedFile.h" #include "BKE_scene.h" #include "BKE_node.h" @@ -117,8 +118,6 @@ #include "GPU_draw.h" #include "GPU_extensions.h" -#include "BLI_scanfill.h" /* for BLI_setErrorCallBack, TODO, move elsewhere */ - #ifdef WITH_FREESTYLE # include "FRS_freestyle.h" #endif @@ -173,11 +172,12 @@ static int print_version(int argc, const char **argv, void *data); #endif /* for the callbacks: */ - +#ifndef WITH_PYTHON_MODULE #define BLEND_VERSION_FMT "Blender %d.%02d (sub %d)" #define BLEND_VERSION_ARG BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION /* pass directly to printf */ #define BLEND_VERSION_STRING_FMT BLEND_VERSION_FMT "\n", BLEND_VERSION_ARG +#endif /* Initialize callbacks for the modules that need them */ static void setCallbacks(void); @@ -412,10 +412,13 @@ static int debug_mode(int UNUSED(argc), const char **UNUSED(argv), void *data) G.debug |= G_DEBUG; /* std output printf's */ printf(BLEND_VERSION_STRING_FMT); MEM_set_memory_debug(); +#ifdef DEBUG + BLI_mempool_set_memory_debug(); +#endif #ifdef WITH_BUILDINFO printf("Build: %s %s %s %s\n", build_date, build_time, build_platform, build_type); -#endif // WITH_BUILDINFO +#endif BLI_argsPrint(data); return 0; @@ -1517,6 +1520,7 @@ int main(int argc, const char **argv) IMB_init(); BKE_images_init(); + BKE_modifier_init(); BKE_brush_system_init(); @@ -1682,12 +1686,6 @@ void main_python_exit(void) } #endif -static void error_cb(const char *err) -{ - - printf("%s\n", err); /* XXX do this in WM too */ -} - static void mem_error_cb(const char *errorStr) { fputs(errorStr, stderr); @@ -1698,9 +1696,4 @@ static void setCallbacks(void) { /* Error output from the alloc routines: */ MEM_set_error_callback(mem_error_cb); - - - /* BLI_blenlib: */ - - BLI_setErrorCallBack(error_cb); /* */ } diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index 7b5f5a7096a..484e51c4ed1 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -266,7 +266,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0); bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0); bool animation_record = (SYS_GetCommandLineInt(syshandle, "animation_record", 0) != 0); - bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0); + bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0) && GPU_display_list_support(); #ifdef WITH_PYTHON bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 0) != 0); #endif @@ -290,7 +290,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c if (startscene->gm.vsync == VSYNC_ADAPTIVE) canvas->SetSwapInterval(-1); else - canvas->SetSwapInterval(startscene->gm.vsync); // VSYNC_OFF == 0, VSYNC_ON == 1, so this works + canvas->SetSwapInterval((startscene->gm.vsync == VSYNC_ON) ? 1 : 0); RAS_IRenderTools* rendertools = new KX_BlenderRenderTools(); RAS_IRasterizer* rasterizer = NULL; diff --git a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp index a6b71e0bc43..bcc62a341f8 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderRenderTools.cpp @@ -211,7 +211,7 @@ void KX_BlenderRenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmat MT_Vector3 dir = (campos - objpos).safe_normalized(); MT_Vector3 up(0,0,1.0); - KX_GameObject* gameobj = (KX_GameObject*)m_clientobject; + KX_GameObject* gameobj = (KX_GameObject *)this->m_clientobject; // get scaling of halo object MT_Vector3 size = gameobj->GetSGNode()->GetWorldScaling(); @@ -225,7 +225,7 @@ void KX_BlenderRenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmat } MT_Vector3 left = dir.normalized(); - dir = (up.cross(left)).normalized(); + dir = (left.cross(up)).normalized(); // we have calculated the row vectors, now we keep // local scaling into account: @@ -241,14 +241,13 @@ void KX_BlenderRenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmat glTranslated(objpos[0],objpos[1],objpos[2]); glMultMatrixd(maat); - } else { if (objectdrawmode & RAS_IPolyMaterial::SHADOW) { // shadow must be cast to the ground, physics system needed here! MT_Point3 frompoint(oglmatrix[12],oglmatrix[13],oglmatrix[14]); - KX_GameObject *gameobj = (KX_GameObject*)m_clientobject; + KX_GameObject *gameobj = (KX_GameObject *)this->m_clientobject; MT_Vector3 direction = MT_Vector3(0,0,-1); direction.normalize(); @@ -328,7 +327,7 @@ void KX_BlenderRenderTools::RenderText( RAS_IPolyMaterial* polymat, float v1[3], float v2[3], float v3[3], float v4[3], int glattrib) { - const STR_String& mytext = ((CValue*)m_clientobject)->GetPropertyText("Text"); + const STR_String &mytext = ((CValue *)m_clientobject)->GetPropertyText("Text"); const unsigned int flag = polymat->GetFlag(); struct MTFace* tface = 0; @@ -408,3 +407,4 @@ void KX_BlenderRenderTools::MotionBlur(RAS_IRasterizer* rasterizer) } } } + diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index 90383021c90..a28906254a1 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -66,6 +66,7 @@ BL_ActionActuator::BL_ActionActuator(SCA_IObject *gameobj, float endtime, struct bAction *action, short playtype, + short blend_mode, short blendin, short priority, short layer, @@ -88,6 +89,7 @@ BL_ActionActuator::BL_ActionActuator(SCA_IObject *gameobj, m_stridelength(stride), m_layer_weight(layer_weight), m_playtype(playtype), + m_blendmode(blend_mode), m_priority(priority), m_layer(layer), m_ipo_flags(ipo_flags), @@ -187,6 +189,7 @@ bool BL_ActionActuator::Update(double curtime, bool frame) bool bUseContinue = false; KX_GameObject *obj = (KX_GameObject*)GetParent(); short playtype = BL_Action::ACT_MODE_PLAY; + short blendmode = (m_blendmode == ACT_ACTION_ADD) ? BL_Action::ACT_BLEND_ADD : BL_Action::ACT_BLEND_BLEND; float start = m_startframe; float end = m_endframe; @@ -283,7 +286,7 @@ bool BL_ActionActuator::Update(double curtime, bool frame) ResetStartTime(curtime); } - if (obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, m_blendin, playtype, m_layer_weight, m_ipo_flags)) + if (obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, m_blendin, playtype, m_layer_weight, m_ipo_flags, 1.f, blendmode)) { m_flag |= ACT_FLAG_ACTIVE; if (bUseContinue) @@ -328,7 +331,7 @@ bool BL_ActionActuator::Update(double curtime, bool frame) // Convert into a play action and play back to the beginning end = start; start = obj->GetActionFrame(m_layer); - 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); + 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; break; diff --git a/source/gameengine/Converter/BL_ActionActuator.h b/source/gameengine/Converter/BL_ActionActuator.h index ce805c774ef..4579a21f554 100644 --- a/source/gameengine/Converter/BL_ActionActuator.h +++ b/source/gameengine/Converter/BL_ActionActuator.h @@ -48,6 +48,7 @@ public: float endtime, struct bAction *action, short playtype, + short blend_mode, short blendin, short priority, short layer, @@ -129,6 +130,7 @@ protected: float m_stridelength; float m_layer_weight; short m_playtype; + short m_blendmode; short m_priority; short m_layer; short m_ipo_flags; diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index 55d9decb333..d8ddb33ddc4 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -32,6 +32,7 @@ #include "BL_ArmatureObject.h" #include "BL_ActionActuator.h" +#include "BL_Action.h" #include "KX_BlenderSceneConverter.h" #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" @@ -50,7 +51,6 @@ #include "DNA_armature_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "DNA_nla_types.h" #include "DNA_constraint_types.h" #include "KX_PythonSeq.h" #include "KX_PythonInit.h" @@ -137,25 +137,22 @@ void game_copy_pose(bPose **dst, bPose *src, int copy_constraint) /* Only allowed for Poses with identical channels */ -void game_blend_poses(bPose *dst, bPose *src, float srcweight/*, short mode*/) +void game_blend_poses(bPose *dst, bPose *src, float srcweight, short mode) { - short mode= ACTSTRIPMODE_BLEND; - bPoseChannel *dchan; const bPoseChannel *schan; bConstraint *dcon, *scon; float dstweight; int i; - switch (mode) { - case ACTSTRIPMODE_BLEND: - dstweight = 1.0F - srcweight; - break; - case ACTSTRIPMODE_ADD: - dstweight = 1.0F; - break; - default : - dstweight = 1.0F; + if (mode == BL_Action::ACT_BLEND_BLEND) + { + dstweight = 1.0f - srcweight; + } else if (mode == BL_Action::ACT_BLEND_ADD) + { + dstweight = 1.0f; + } else { + dstweight = 1.0f; } schan= (bPoseChannel *)src->chanbase.first; @@ -167,7 +164,7 @@ void game_blend_poses(bPose *dst, bPose *src, float srcweight/*, short mode*/) copy_qt_qt(dquat, dchan->quat); copy_qt_qt(squat, schan->quat); - if (mode==ACTSTRIPMODE_BLEND) + if (mode==BL_Action::ACT_BLEND_BLEND) interp_qt_qtqt(dchan->quat, dquat, squat, srcweight); else { mul_fac_qt_fl(squat, srcweight); diff --git a/source/gameengine/Converter/BL_ArmatureObject.h b/source/gameengine/Converter/BL_ArmatureObject.h index 445b9af1b10..81388355fc4 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.h +++ b/source/gameengine/Converter/BL_ArmatureObject.h @@ -147,7 +147,7 @@ protected: }; /* Pose function specific to the game engine */ -void game_blend_poses(struct bPose *dst, struct bPose *src, float srcweight/*, short mode*/); /* was blend_poses */ +void game_blend_poses(struct bPose *dst, struct bPose *src, float srcweight, short mode); /* was blend_poses */ //void extract_pose_from_pose(struct bPose *pose, const struct bPose *src); void game_copy_pose(struct bPose **dst, struct bPose *src, int copy_con); void game_free_pose(struct bPose *pose); diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 99613f8bd99..dd9609968b0 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -2950,7 +2950,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, struct Object* blenderobj = gameobj->GetBlenderObject(); int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0; bool isInActiveLayer = (blenderobj->lay & layerMask)!=0; - BL_ConvertActuators(maggie->name, blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,layerMask,isInActiveLayer,rendertools,converter); + BL_ConvertActuators(maggie->name, blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,layerMask,isInActiveLayer,converter); } for ( i=0;i<logicbrick_conversionlist->GetCount();i++) { diff --git a/source/gameengine/Converter/BL_ShapeDeformer.cpp b/source/gameengine/Converter/BL_ShapeDeformer.cpp index 59cf10d326a..5aec3c9e965 100644 --- a/source/gameengine/Converter/BL_ShapeDeformer.cpp +++ b/source/gameengine/Converter/BL_ShapeDeformer.cpp @@ -159,16 +159,20 @@ bool BL_ShapeDeformer::Update(void) /* the key coefficient have been set already, we just need to blend the keys */ Object* blendobj = m_gameobj->GetBlendObject(); - // make sure the vertex weight cache is in line with this object - m_pMeshObject->CheckWeightCache(blendobj); - /* we will blend the key directly in m_transverts array: it is used by armature as the start position */ /* m_key can be NULL in case of Modifier deformer */ if (m_key) { + WeightsArrayCache cache = {0, NULL}; + float **per_keyblock_weights; + /* store verts locally */ VerifyStorage(); - BKE_key_evaluate_relative(0, m_bmesh->totvert, m_bmesh->totvert, (char *)(float *)m_transverts, m_key, NULL, 0); /* last arg is ignored */ + per_keyblock_weights = BKE_keyblock_get_per_block_weights(blendobj, m_key, &cache); + BKE_key_evaluate_relative(0, m_bmesh->totvert, m_bmesh->totvert, (char *)(float *)m_transverts, + m_key, NULL, per_keyblock_weights, 0); /* last arg is ignored */ + BKE_keyblock_free_per_block_weights(m_key, per_keyblock_weights, &cache); + m_bDynamic = true; } diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index 5b528972e00..e9461a15578 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -120,7 +120,6 @@ void BL_ConvertActuators(const char* maggiename, KX_KetsjiEngine* ketsjiEngine, int activeLayerBitInfo, bool isInActiveLayer, - RAS_IRenderTools* rendertools, KX_BlenderSceneConverter* converter ) { @@ -206,8 +205,8 @@ void BL_ConvertActuators(const char* maggiename, case ACT_ACTION: { bActionActuator* actact = (bActionActuator*) bact->data; - STR_String propname = (actact->name ? actact->name : ""); - STR_String propframe = (actact->frameProp ? actact->frameProp : ""); + STR_String propname = actact->name; + STR_String propframe = actact->frameProp; short ipo_flags = 0; @@ -225,6 +224,7 @@ void BL_ConvertActuators(const char* maggiename, actact->end, actact->act, actact->type, // + 1, because Blender starts to count at zero, + actact->blend_mode, actact->blendin, actact->priority, actact->layer, @@ -241,8 +241,8 @@ void BL_ConvertActuators(const char* maggiename, { if (blenderobject->type==OB_MESH) { bActionActuator* actact = (bActionActuator*) bact->data; - STR_String propname = (actact->name ? actact->name : ""); - STR_String propframe = (actact->frameProp ? actact->frameProp : ""); + STR_String propname = actact->name; + STR_String propframe = actact->frameProp; BL_ShapeActionActuator* tmpbaseact = new BL_ShapeActionActuator( gameobj, @@ -748,9 +748,8 @@ void BL_ConvertActuators(const char* maggiename, break; }; - if (sceneact->scene) - { - nextSceneName = sceneact->scene->id.name + 2; // this '2' is necessary to remove prefix 'SC' + if (sceneact->scene) { + nextSceneName = sceneact->scene->id.name + 2; } break; diff --git a/source/gameengine/Converter/KX_ConvertActuators.h b/source/gameengine/Converter/KX_ConvertActuators.h index 385d274bf89..688b5db50ce 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.h +++ b/source/gameengine/Converter/KX_ConvertActuators.h @@ -40,7 +40,6 @@ void BL_ConvertActuators(const char* maggiename, class KX_KetsjiEngine* ketsjiEngine, int activeLayerBitInfo, bool isInActiveLayer, - class RAS_IRenderTools* rendertools, class KX_BlenderSceneConverter* converter); #endif /* __KX_CONVERTACTUATORS_H__ */ diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp index 1aae2738311..3bb12c12cd1 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.cpp +++ b/source/gameengine/Converter/KX_ConvertSensors.cpp @@ -194,30 +194,6 @@ void BL_ConvertSensors(struct Object* blenderobject, break; } - case SENS_TOUCH: - { - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR); - if (eventmgr) - { - STR_String touchpropertyname; - bTouchSensor* blendertouchsensor = (bTouchSensor*)sens->data; - - if (blendertouchsensor->ma) - { - touchpropertyname = (char*) (blendertouchsensor->ma->id.name+2); - } - bool bFindMaterial = true; - if (gameobj->GetPhysicsController()) - { - gamesensor = new KX_TouchSensor(eventmgr, - gameobj, - bFindMaterial, - false, - touchpropertyname); - } - } - break; - } case SENS_MESSAGE: { KX_NetworkEventManager* eventmgr = (KX_NetworkEventManager*) diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp index 8e729ffd7ae..793ce6a7b83 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp +++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp @@ -39,6 +39,8 @@ #include "SCA_Joystick.h" #include "SCA_JoystickPrivate.h" +#include "BLI_path_util.h" + SCA_Joystick::SCA_Joystick(short int index) : m_joyindex(index), @@ -88,14 +90,26 @@ SCA_Joystick *SCA_Joystick::GetInstance( short int joyindex ) if (m_refCount == 0) { int i; + /* The video subsystem is required for joystick input to work. However, - * when GHOST is running under SDL, video is initialized elsewhere. - * Do this once only. */ + * when GHOST is running under SDL, video is initialized elsewhere. We + * also need to set the videodriver to dummy, and do it here to avoid + * interfering with addons that may use SDL too. + * + * We also init SDL once only. */ # ifdef WITH_GHOST_SDL - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1 ) { + int success = (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != -1 ); # else - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO) == -1 ) { + /* set and restore environment variable */ + char *videodriver = getenv("SDL_VIDEODRIVER"); + BLI_setenv("SDL_VIDEODRIVER", "dummy"); + + int success = (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO) != -1 ); + + BLI_setenv("SDL_VIDEODRIVER", videodriver); # endif + + if (!success) { JOYSTICK_ECHO("Error-Initializing-SDL: " << SDL_GetError()); return NULL; } @@ -278,7 +292,11 @@ void SCA_Joystick::DestroyJoystickDevice(void) { #ifdef WITH_SDL if (m_isinit) { +#if SDL_VERSION_ATLEAST(2, 0, 0) + if (SDL_JoystickGetAttached(m_private->m_joystick)) { +#else if (SDL_JoystickOpened(m_joyindex)) { +#endif JOYSTICK_ECHO("Closing-joystick " << m_joyindex); SDL_JoystickClose(m_private->m_joystick); } @@ -290,7 +308,12 @@ void SCA_Joystick::DestroyJoystickDevice(void) int SCA_Joystick::Connected(void) { #ifdef WITH_SDL - if (m_isinit && SDL_JoystickOpened(m_joyindex)) + if (m_isinit +#if SDL_VERSION_ATLEAST(2, 0, 0) + && SDL_JoystickGetAttached(m_private->m_joystick)) +#else + && SDL_JoystickOpened(m_joyindex)) +#endif return 1; #endif return 0; @@ -328,7 +351,11 @@ int SCA_Joystick::pAxisTest(int axisnum) const char *SCA_Joystick::GetName() { #ifdef WITH_SDL +#if SDL_VERSION_ATLEAST(2, 0, 0) + return SDL_JoystickName(m_private->m_joystick); +#else return SDL_JoystickName(m_joyindex); +#endif #else /* WITH_SDL */ return ""; #endif /* WITH_SDL */ diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp index f50137cfcf6..2911b3b1a14 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp +++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp @@ -118,7 +118,7 @@ void SCA_Joystick::HandleEvents(void) break; #endif default: - printf("SCA_Joystick::HandleEvents, Unknown SDL event, this should not happen\n"); + printf("SCA_Joystick::HandleEvents, Unknown SDL event (%d), this should not happen\n", sdl_event.type); break; } } diff --git a/source/gameengine/GameLogic/SCA_IScene.cpp b/source/gameengine/GameLogic/SCA_IScene.cpp index 60b4d19e155..c98c86639d3 100644 --- a/source/gameengine/GameLogic/SCA_IScene.cpp +++ b/source/gameengine/GameLogic/SCA_IScene.cpp @@ -87,7 +87,7 @@ void SCA_IScene::AddDebugProperty(class CValue* debugprop, void SCA_IScene::RemoveObjectDebugProperties(class CValue* gameobj) { vector<SCA_DebugProp*>::iterator it = m_debugList.begin(); - while(it != m_debugList.end()) { + while (it != m_debugList.end()) { CValue* debugobj = (*it)->m_obj; if (debugobj == gameobj) { diff --git a/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp b/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp index e8c29d5aa4f..0d851c4f10d 100644 --- a/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp +++ b/source/gameengine/GamePlayer/common/GPC_RenderTools.cpp @@ -66,9 +66,7 @@ unsigned int GPC_RenderTools::m_numgllights; GPC_RenderTools::GPC_RenderTools() { -// XXX m_font = BMF_GetFont(BMF_kHelvetica10); - - glGetIntegerv(GL_MAX_LIGHTS, (GLint*) &m_numgllights); + glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &m_numgllights); if (m_numgllights < 8) m_numgllights = 8; } @@ -220,7 +218,7 @@ void GPC_RenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmatrix,in MT_Vector3 dir = (campos - objpos).safe_normalized(); MT_Vector3 up(0,0,1.0); - KX_GameObject* gameobj = (KX_GameObject*) this->m_clientobject; + KX_GameObject* gameobj = (KX_GameObject *)this->m_clientobject; // get scaling of halo object MT_Vector3 size = gameobj->GetSGNode()->GetWorldScaling(); @@ -256,7 +254,7 @@ void GPC_RenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmatrix,in { // shadow must be cast to the ground, physics system needed here! MT_Point3 frompoint(oglmatrix[12],oglmatrix[13],oglmatrix[14]); - KX_GameObject *gameobj = (KX_GameObject*) this->m_clientobject; + KX_GameObject *gameobj = (KX_GameObject *)this->m_clientobject; MT_Vector3 direction = MT_Vector3(0,0,-1); direction.normalize(); @@ -280,6 +278,12 @@ void GPC_RenderTools::applyTransform(RAS_IRasterizer* rasty,double* oglmatrix,in // couldn't find something to cast the shadow on... glMultMatrixd(oglmatrix); } + else + { // we found the "ground", but the cast matrix doesn't take + // scaling in consideration, so we must apply the object scale + MT_Vector3 size = gameobj->GetSGNode()->GetLocalScale(); + glScalef(size[0], size[1], size[2]); + } } else { @@ -490,7 +494,7 @@ void GPC_RenderTools::RenderText( RAS_IPolyMaterial* polymat, float v1[3], float v2[3], float v3[3], float v4[3], int glattrib) { - STR_String mytext = ((CValue*)m_clientobject)->GetPropertyText("Text"); + const STR_String &mytext = ((CValue *)m_clientobject)->GetPropertyText("Text"); const unsigned int flag = polymat->GetFlag(); struct MTFace* tface = 0; @@ -562,8 +566,7 @@ void GPC_RenderTools::MotionBlur(RAS_IRasterizer* rasterizer) glAccum(GL_LOAD, 1.0); rasterizer->SetMotionBlurState(2); } - else if (motionblurvalue>=0.0 && motionblurvalue<=1.0) - { + else if (motionblurvalue >= 0.0f && motionblurvalue <= 1.0f) { glAccum(GL_MULT, motionblurvalue); glAccum(GL_ACCUM, 1-motionblurvalue); glAccum(GL_RETURN, 1.0); diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index c3cbf381af4..c74e3daf7b2 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp @@ -566,7 +566,7 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) bool fixed_framerate= (SYS_GetCommandLineInt(syshandle, "fixedtime", (gm->flag & GAME_ENABLE_ALL_FRAMES)) != 0); bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0); - bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", gm->flag & GAME_DISPLAY_LISTS) != 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; @@ -586,7 +586,7 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) if (gm->vsync == VSYNC_ADAPTIVE) m_canvas->SetSwapInterval(-1); else - m_canvas->SetSwapInterval(gm->vsync); // VSYNC_OFF == 0, VSYNC_ON == 1, so this works + m_canvas->SetSwapInterval((gm->vsync == VSYNC_ON) ? 1 : 0); m_canvas->Init(); if (gm->flag & GAME_SHOW_MOUSE) diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index ccbcdd25639..5bed4fa40b6 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -57,22 +57,29 @@ extern "C" { #endif // __cplusplus #include "MEM_guardedalloc.h" +#include "BLI_threads.h" +#include "BLI_mempool.h" +#include "BLI_blenlib.h" + +#include "DNA_scene_types.h" +#include "DNA_userdef_types.h" + +#include "BLO_readfile.h" +#include "BLO_runtime.h" + #include "BKE_blender.h" +#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_icons.h" #include "BKE_image.h" #include "BKE_node.h" #include "BKE_report.h" #include "BKE_library.h" -#include "BLI_threads.h" -#include "BLI_blenlib.h" -#include "DNA_scene_types.h" -#include "DNA_userdef_types.h" -#include "BLO_readfile.h" -#include "BLO_runtime.h" -#include "IMB_imbuf.h" +#include "BKE_modifier.h" #include "BKE_text.h" #include "BKE_sound.h" + +#include "IMB_imbuf.h" int GHOST_HACK_getFirstFile(char buf[]); @@ -456,6 +463,7 @@ int main(int argc, char** argv) IMB_init(); BKE_images_init(); + BKE_modifier_init(); #ifdef WITH_FFMPEG IMB_ffmpeg_init(); @@ -577,8 +585,11 @@ int main(int argc, char** argv) case 'd': i++; - G.debug |= G_DEBUG; /* std output printf's */ + G.debug |= G_DEBUG; MEM_set_memory_debug(); +#ifdef DEBUG + BLI_mempool_set_memory_debug(); +#endif break; case 'f': diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp index 9d189a6170e..6d9b22eed91 100644 --- a/source/gameengine/Ketsji/BL_Action.cpp +++ b/source/gameengine/Ketsji/BL_Action.cpp @@ -65,7 +65,8 @@ BL_Action::BL_Action(class KX_GameObject* gameobj) m_blendstart(0.f), m_speed(0.f), m_priority(0), - m_playmode(0), + m_playmode(ACT_MODE_PLAY), + m_blendmode(ACT_BLEND_BLEND), m_ipo_flags(0), m_done(true), m_calc_localtime(true) @@ -104,7 +105,8 @@ bool BL_Action::Play(const char* name, short play_mode, float layer_weight, short ipo_flags, - float playback_speed) + float playback_speed, + short blend_mode) { // Only start playing a new action if we're done, or if @@ -229,6 +231,7 @@ bool BL_Action::Play(const char* name, m_endframe = end; m_blendin = blendin; m_playmode = play_mode; + m_blendmode = blend_mode; m_endtime = 0.f; m_blendframe = 0.f; m_blendstart = 0.f; @@ -423,7 +426,7 @@ void BL_Action::Update(float curtime) float weight = 1.f - (m_blendframe/m_blendin); // Blend the poses - game_blend_poses(m_pose, m_blendinpose, weight); + game_blend_poses(m_pose, m_blendinpose, weight, ACT_BLEND_BLEND); } @@ -431,7 +434,7 @@ void BL_Action::Update(float curtime) if (m_layer_weight >= 0) { obj->GetMRDPose(&m_blendpose); - game_blend_poses(m_pose, m_blendpose, m_layer_weight); + game_blend_poses(m_pose, m_blendpose, m_layer_weight, m_blendmode); } obj->SetPose(m_pose); diff --git a/source/gameengine/Ketsji/BL_Action.h b/source/gameengine/Ketsji/BL_Action.h index e4088633e61..e9d09916517 100644 --- a/source/gameengine/Ketsji/BL_Action.h +++ b/source/gameengine/Ketsji/BL_Action.h @@ -34,7 +34,6 @@ #include "MEM_guardedalloc.h" #endif - class BL_Action { private: @@ -64,6 +63,7 @@ private: short m_priority; short m_playmode; + short m_blendmode; short m_ipo_flags; @@ -91,7 +91,8 @@ public: short play_mode, float layer_weight, short ipo_flags, - float playback_speed); + float playback_speed, + short blend_mode); /** * Stop playing the action */ @@ -114,7 +115,7 @@ public: void SetPlayMode(short play_mode); void SetTimes(float start, float end); - enum + enum { ACT_MODE_PLAY = 0, ACT_MODE_LOOP, @@ -124,6 +125,13 @@ public: enum { + ACT_BLEND_BLEND=0, + ACT_BLEND_ADD=1, + ACT_BLEND_MAX, + }; + + enum + { ACT_IPOFLAG_FORCE = 1, ACT_IPOFLAG_LOCAL = 2, ACT_IPOFLAG_ADD = 4, diff --git a/source/gameengine/Ketsji/BL_ActionManager.cpp b/source/gameengine/Ketsji/BL_ActionManager.cpp index e3402972ca6..2e882ceba74 100644 --- a/source/gameengine/Ketsji/BL_ActionManager.cpp +++ b/source/gameengine/Ketsji/BL_ActionManager.cpp @@ -25,6 +25,7 @@ */ #include "BL_ActionManager.h" +#include "BL_Action.h" BL_ActionManager::BL_ActionManager(class KX_GameObject *obj) { @@ -72,12 +73,13 @@ bool BL_ActionManager::PlayAction(const char* name, short play_mode, float layer_weight, short ipo_flags, - float playback_speed) + float playback_speed, + short blend_mode) { // Disable layer blending on the first layer if (layer == 0) layer_weight = -1.f; - return m_layers[layer]->Play(name, start, end, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed); + return m_layers[layer]->Play(name, start, end, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed, blend_mode); } void BL_ActionManager::StopAction(short layer) diff --git a/source/gameengine/Ketsji/BL_ActionManager.h b/source/gameengine/Ketsji/BL_ActionManager.h index 600e7b6621e..8c5b8e909da 100644 --- a/source/gameengine/Ketsji/BL_ActionManager.h +++ b/source/gameengine/Ketsji/BL_ActionManager.h @@ -27,10 +27,14 @@ #ifndef __BL_ACTIONMANAGER_H__ #define __BL_ACTIONMANAGER_H__ -#include "BL_Action.h" +#ifdef WITH_CXX_GUARDEDALLOC + #include "MEM_guardedalloc.h" +#endif #define MAX_ACTION_LAYERS 8 +class BL_Action; + /** * BL_ActionManager is responsible for handling a KX_GameObject's actions. */ @@ -52,7 +56,8 @@ public: short play_mode=0, float layer_weight=0.f, short ipo_flags=0, - float playback_speed=1.f); + float playback_speed=1.f, + short blend_mode=0); /** * Gets the current frame of an action */ diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp index 97dc8f72aec..6f6925dcf76 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.cpp +++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp @@ -44,7 +44,6 @@ BL_BlenderShader::BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lightlayer) : - mScene(scene), mMat(ma), mLightLayer(lightlayer), mGPUMat(NULL) diff --git a/source/gameengine/Ketsji/BL_BlenderShader.h b/source/gameengine/Ketsji/BL_BlenderShader.h index 71f66c2a49d..e03bb5a11d9 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.h +++ b/source/gameengine/Ketsji/BL_BlenderShader.h @@ -57,7 +57,6 @@ class BL_Material; class BL_BlenderShader { private: - KX_Scene *mScene; struct Scene *mBlenderScene; struct Material *mMat; int mLightLayer; @@ -86,13 +85,6 @@ public: void ReloadMaterial(); int GetAlphaBlend(); - void SetScene(KX_Scene *scene) - { - mScene = scene; - mBlenderScene = scene->GetBlenderScene(); - ReloadMaterial(); - } - bool Equals(BL_BlenderShader *blshader); diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp index 28abdc898ae..b3a38cb4f98 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -808,9 +808,7 @@ void KX_BlenderMaterial::UpdateIPO( void KX_BlenderMaterial::Replace_IScene(SCA_IScene *val) { mScene= static_cast<KX_Scene *>(val); - if (mBlenderShader) - mBlenderShader->SetScene(mScene); - + OnConstruction(); } diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index ec62ae63f0c..e06f7ab6633 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -73,6 +73,7 @@ typedef unsigned long uint_ptr; #include "KX_ObstacleSimulation.h" #include "BL_ActionManager.h" +#include "BL_Action.h" #include "PyObjectPlus.h" /* python stuff */ @@ -113,8 +114,10 @@ KX_GameObject::KX_GameObject( m_pDupliGroupObject(NULL), m_actionManager(NULL), m_isDeformable(false) + #ifdef WITH_PYTHON - , m_attr_dict(NULL) + , m_attr_dict(NULL), + m_collisionCallbacks(NULL) #endif { m_ignore_activity_culling = false; @@ -132,6 +135,20 @@ KX_GameObject::KX_GameObject( KX_GameObject::~KX_GameObject() { +#ifdef WITH_PYTHON + if (m_attr_dict) { + PyDict_Clear(m_attr_dict); /* in case of circular refs or other weird cases */ + /* Py_CLEAR: Py_DECREF's and NULL's */ + Py_CLEAR(m_attr_dict); + } + // Unregister collision callbacks + // Do this before we start freeing physics information like m_pClient_info + if (m_collisionCallbacks){ + UnregisterCollisionCallbacks(); + Py_CLEAR(m_collisionCallbacks); + } +#endif // WITH_PYTHON + RemoveMeshes(); // is this delete somewhere ? @@ -179,13 +196,6 @@ KX_GameObject::~KX_GameObject() { m_pInstanceObjects->Release(); } -#ifdef WITH_PYTHON - if (m_attr_dict) { - PyDict_Clear(m_attr_dict); /* in case of circular refs or other weird cases */ - /* Py_CLEAR: Py_DECREF's and NULL's */ - Py_CLEAR(m_attr_dict); - } -#endif // WITH_PYTHON } KX_GameObject* KX_GameObject::GetClientObject(KX_ClientObjectInfo *info) @@ -429,9 +439,10 @@ bool KX_GameObject::PlayAction(const char* name, short play_mode, float layer_weight, short ipo_flags, - float playback_speed) + float playback_speed, + short blend_mode) { - return GetActionManager()->PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed); + return GetActionManager()->PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed, blend_mode); } void KX_GameObject::StopAction(short layer) @@ -1334,6 +1345,77 @@ const MT_Point3& KX_GameObject::NodeGetLocalPosition() const } +void KX_GameObject::UnregisterCollisionCallbacks() +{ + if (!GetPhysicsController()) { + printf("Warning, trying to unregister collision callbacks for object without collisions: %s!\n", GetName().ReadPtr()); + return; + } + + // Unregister from callbacks + KX_Scene* scene = GetScene(); + PHY_IPhysicsEnvironment* pe = scene->GetPhysicsEnvironment(); + PHY_IPhysicsController* spc = static_cast<PHY_IPhysicsController*> (GetPhysicsController()->GetUserData()); + // If we are the last to unregister on this physics controller + if (pe->removeCollisionCallback(spc)){ + // If we are a sensor object + if (m_pClient_info->isSensor()) + // Remove sensor body from physics world + pe->removeSensor(spc); + } +} + +void KX_GameObject::RegisterCollisionCallbacks() +{ + if (!GetPhysicsController()) { + printf("Warning, trying to register collision callbacks for object without collisions: %s!\n", GetName().ReadPtr()); + return; + } + + // Register from callbacks + KX_Scene* scene = GetScene(); + PHY_IPhysicsEnvironment* pe = scene->GetPhysicsEnvironment(); + PHY_IPhysicsController* spc = static_cast<PHY_IPhysicsController*> (GetPhysicsController()->GetUserData()); + // If we are the first to register on this physics controller + if (pe->requestCollisionCallback(spc)){ + // If we are a sensor object + if (m_pClient_info->isSensor()) + // Add sensor body to physics world + pe->addSensor(spc); + } +} +void KX_GameObject::RunCollisionCallbacks(KX_GameObject *collider) +{ + #ifdef WITH_PYTHON + Py_ssize_t len; + PyObject* collision_callbacks = m_collisionCallbacks; + + if (collision_callbacks && (len=PyList_GET_SIZE(collision_callbacks))) + { + PyObject* args = Py_BuildValue("(O)", collider->GetProxy()); // save python creating each call + PyObject *func; + PyObject *ret; + + // Iterate the list and run the callbacks + for (Py_ssize_t pos=0; pos < len; pos++) + { + func = PyList_GET_ITEM(collision_callbacks, pos); + ret = PyObject_Call(func, args, NULL); + + if (ret == NULL) { + PyErr_Print(); + PyErr_Clear(); + } + else { + Py_DECREF(ret); + } + } + + Py_DECREF(args); + } + #endif +} + /* Suspend/ resume: for the dynamic behavior, there is a simple * method. For the residual motion, there is not. I wonder what the * correct solution is for Sumo. Remove from the motion-update tree? @@ -1714,6 +1796,7 @@ PyAttributeDef KX_GameObject::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("orientation",KX_GameObject,pyattr_get_worldOrientation,pyattr_set_localOrientation), KX_PYATTRIBUTE_RW_FUNCTION("scaling", KX_GameObject, pyattr_get_worldScaling, pyattr_set_localScaling), KX_PYATTRIBUTE_RW_FUNCTION("timeOffset",KX_GameObject, pyattr_get_timeOffset,pyattr_set_timeOffset), + KX_PYATTRIBUTE_RW_FUNCTION("collisionCallbacks", KX_GameObject, pyattr_get_collisionCallbacks, pyattr_set_collisionCallbacks), KX_PYATTRIBUTE_RW_FUNCTION("state", KX_GameObject, pyattr_get_state, pyattr_set_state), KX_PYATTRIBUTE_RO_FUNCTION("meshes", KX_GameObject, pyattr_get_meshes), KX_PYATTRIBUTE_RW_FUNCTION("localOrientation",KX_GameObject,pyattr_get_localOrientation,pyattr_set_localOrientation), @@ -2006,6 +2089,51 @@ PyObject *KX_GameObject::pyattr_get_group_members(void *self_v, const KX_PYATTRI Py_RETURN_NONE; } +PyObject* KX_GameObject::pyattr_get_collisionCallbacks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + + // Only objects with a physics controller should have collision callbacks + if (!self->GetPhysicsController()) { + PyErr_SetString(PyExc_AttributeError, "KX_GameObject.collisionCallbacks: attribute only available for objects with collisions enabled"); + return NULL; + } + + // Return the existing callbacks + if (self->m_collisionCallbacks == NULL) + { + self->m_collisionCallbacks = PyList_New(0); + // Subscribe to collision update from KX_TouchManager + self->RegisterCollisionCallbacks(); + } + Py_INCREF(self->m_collisionCallbacks); + return self->m_collisionCallbacks; +} + +int KX_GameObject::pyattr_set_collisionCallbacks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject* self = static_cast<KX_GameObject*>(self_v); + + // Only objects with a physics controller should have collision callbacks + if (!self->GetPhysicsController()) { + PyErr_SetString(PyExc_AttributeError, "KX_GameObject.collisionCallbacks: attribute only available for objects with collisions enabled"); + return PY_SET_ATTR_FAIL; + } + + if (!PyList_CheckExact(value)) + { + PyErr_SetString(PyExc_ValueError, "Expected a list"); + return PY_SET_ATTR_FAIL; + } + + Py_XDECREF(self->m_collisionCallbacks); + Py_INCREF(value); + + self->m_collisionCallbacks = value; + + return PY_SET_ATTR_SUCCESS; +} + PyObject* KX_GameObject::pyattr_get_scene(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_GameObject *self = static_cast<KX_GameObject*>(self_v); @@ -3311,11 +3439,12 @@ KX_PYMETHODDEF_DOC(KX_GameObject, playAction, short layer=0, priority=0; short ipo_flags=0; short play_mode=0; + short blend_mode=0; - static const char *kwlist[] = {"name", "start_frame", "end_frame", "layer", "priority", "blendin", "play_mode", "layer_weight", "ipo_flags", "speed", NULL}; + static const char *kwlist[] = {"name", "start_frame", "end_frame", "layer", "priority", "blendin", "play_mode", "layer_weight", "ipo_flags", "speed", "blend_mode", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "sff|hhfhfhf:playAction", const_cast<char**>(kwlist), - &name, &start, &end, &layer, &priority, &blendin, &play_mode, &layer_weight, &ipo_flags, &speed)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "sff|hhfhfhfh:playAction", const_cast<char**>(kwlist), + &name, &start, &end, &layer, &priority, &blendin, &play_mode, &layer_weight, &ipo_flags, &speed, &blend_mode)) return NULL; layer_check(layer, "playAction"); @@ -3323,7 +3452,13 @@ KX_PYMETHODDEF_DOC(KX_GameObject, playAction, if (play_mode < 0 || play_mode > BL_Action::ACT_MODE_MAX) { printf("KX_GameObject.playAction(): given play_mode (%d) is out of range (0 - %d), setting to ACT_MODE_PLAY", play_mode, BL_Action::ACT_MODE_MAX-1); - play_mode = BL_Action::ACT_MODE_MAX; + play_mode = BL_Action::ACT_MODE_PLAY; + } + + if (blend_mode < 0 || blend_mode > BL_Action::ACT_BLEND_MAX) + { + printf("KX_GameObject.playAction(): given blend_mode (%d) is out of range (0 - %d), setting to ACT_BLEND_BLEND", blend_mode, BL_Action::ACT_BLEND_MAX-1); + blend_mode = BL_Action::ACT_BLEND_BLEND; } if (layer_weight < 0.f || layer_weight > 1.f) @@ -3332,7 +3467,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, playAction, layer_weight = 0.f; } - PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, speed); + PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, speed, blend_mode); Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 13a79cebefb..dde3ff53299 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -137,21 +137,22 @@ public: #ifdef WITH_PYTHON // Python attributes that wont convert into CValue - // + // // there are 2 places attributes can be stored, in the CValue, // where attributes are converted into BGE's CValue types // these can be used with property actuators // // For the python API, For types that cannot be converted into CValues (lists, dicts, GameObjects) // these will be put into "m_attr_dict", logic bricks cannot access them. - // + // // rules for setting attributes. - // + // // * there should NEVER be a CValue and a m_attr_dict attribute with matching names. get/sets make sure of this. // * if CValue conversion fails, use a PyObject in "m_attr_dict" // * when assigning a value, first see if it can be a CValue, if it can remove the "m_attr_dict" and set the CValue - // - PyObject* m_attr_dict; + // + PyObject* m_attr_dict; + PyObject* m_collisionCallbacks; #endif virtual void /* This function should be virtual - derived classed override it */ @@ -255,7 +256,8 @@ public: short play_mode=0, float layer_weight=0.f, short ipo_flags=0, - float playback_speed=1.f); + float playback_speed=1.f, + short blend_mode=0); /** * Gets the current frame of an action @@ -871,6 +873,9 @@ public: * \section Logic bubbling methods. */ + void RegisterCollisionCallbacks(); + void UnregisterCollisionCallbacks(); + void RunCollisionCallbacks(KX_GameObject *collider); /** * Stop making progress */ @@ -1039,6 +1044,8 @@ public: static PyObject* pyattr_get_attrDict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_obcolor(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_collisionCallbacks(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_collisionCallbacks(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 32666ec0792..c685dcfe068 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -1201,6 +1201,7 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) /* render */ m_rasterizer->ClearDepthBuffer(); + m_rasterizer->ClearColorBuffer(); scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools); /* unbind framebuffer object, restore drawmode, free camera */ diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp index a8f309cc592..0e4db0d351e 100644 --- a/source/gameengine/Ketsji/KX_Light.cpp +++ b/source/gameengine/Ketsji/KX_Light.cpp @@ -48,6 +48,9 @@ #include "DNA_scene_types.h" #include "DNA_lamp_types.h" #include "GPU_material.h" + +#include "BKE_scene.h" +#include "MEM_guardedalloc.h" KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks, class RAS_IRenderTools* rendertools, @@ -62,6 +65,7 @@ KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks, m_rendertools->AddLight(&m_lightobj); m_glsl = glsl; m_blenderscene = ((KX_Scene*)sgReplicationInfo)->GetBlenderScene(); + m_base = NULL; }; @@ -78,6 +82,11 @@ KX_LightObject::~KX_LightObject() } m_rendertools->RemoveLight(&m_lightobj); + + if (m_base) { + BKE_scene_base_unlink(m_blenderscene, m_base); + MEM_freeN(m_base); + } } @@ -216,6 +225,13 @@ void KX_LightObject::Update() } } +void KX_LightObject::UpdateScene(KX_Scene *kxscene) +{ + m_lightobj.m_scene = (void*)kxscene; + m_blenderscene = kxscene->GetBlenderScene(); + m_base = BKE_scene_base_add(m_blenderscene, GetBlenderObject()); +} + bool KX_LightObject::HasShadowBuffer() { GPULamp *lamp; diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h index f88fc7f6a1b..43421a3faf3 100644 --- a/source/gameengine/Ketsji/KX_Light.h +++ b/source/gameengine/Ketsji/KX_Light.h @@ -37,6 +37,7 @@ struct GPULamp; struct Scene; +struct Base; class KX_Camera; class RAS_IRasterizer; class RAS_IRenderTools; @@ -50,6 +51,7 @@ protected: class RAS_IRenderTools* m_rendertools; //needed for registering and replication of lightobj bool m_glsl; Scene* m_blenderscene; + Base* m_base; public: KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,class RAS_IRenderTools* rendertools,const struct RAS_LightObject& lightobj, bool glsl); @@ -69,7 +71,7 @@ public: struct Image *GetTextureImage(short texslot); void Update(); - void UpdateScene(class KX_Scene *kxscene) {m_lightobj.m_scene = (void*)kxscene;} + void UpdateScene(class KX_Scene *kxscene); virtual int GetGameObjectType() { return OBJ_LIGHT; } diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index d8b4bf9e8bd..29f28b7cc24 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -1378,14 +1378,14 @@ static PyObject *gPySetVsync(PyObject *, PyObject *args) if (!PyArg_ParseTuple(args, "i:setVsync", &interval)) return NULL; - if (interval < VSYNC_OFF || interval > VSYNC_ADAPTIVE) { + if (interval < 0 || interval > VSYNC_ADAPTIVE) { PyErr_SetString(PyExc_ValueError, "Rasterizer.setVsync(value): value must be VSYNC_OFF, VSYNC_ON, or VSYNC_ADAPTIVE"); return NULL; } if (interval == VSYNC_ADAPTIVE) interval = -1; - gp_Canvas->SetSwapInterval(interval); + gp_Canvas->SetSwapInterval((interval == VSYNC_ON) ? 1 : 0); Py_RETURN_NONE; } @@ -1675,16 +1675,16 @@ PyObject *initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_POS_X, KX_RadarSensor::KX_RADAR_AXIS_POS_X); KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_POS_Y, KX_RadarSensor::KX_RADAR_AXIS_POS_Y); KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_POS_Z, KX_RadarSensor::KX_RADAR_AXIS_POS_Z); - KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_NEG_X, KX_RadarSensor::KX_RADAR_AXIS_NEG_Y); - KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_NEG_Y, KX_RadarSensor::KX_RADAR_AXIS_NEG_X); + KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_NEG_X, KX_RadarSensor::KX_RADAR_AXIS_NEG_X); + KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_NEG_Y, KX_RadarSensor::KX_RADAR_AXIS_NEG_Y); KX_MACRO_addTypesToDict(d, KX_RADAR_AXIS_NEG_Z, KX_RadarSensor::KX_RADAR_AXIS_NEG_Z); /* Ray Sensor */ KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_POS_X, KX_RaySensor::KX_RAY_AXIS_POS_X); KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_POS_Y, KX_RaySensor::KX_RAY_AXIS_POS_Y); KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_POS_Z, KX_RaySensor::KX_RAY_AXIS_POS_Z); - KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_NEG_X, KX_RaySensor::KX_RAY_AXIS_NEG_Y); - KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_NEG_Y, KX_RaySensor::KX_RAY_AXIS_NEG_X); + KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_NEG_X, KX_RaySensor::KX_RAY_AXIS_NEG_X); + KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_NEG_Y, KX_RaySensor::KX_RAY_AXIS_NEG_Y); KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_NEG_Z, KX_RaySensor::KX_RAY_AXIS_NEG_Z); /* Dynamic actuator */ @@ -1820,6 +1820,10 @@ PyObject *initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack KX_MACRO_addTypesToDict(d, KX_ACTION_MODE_LOOP, BL_Action::ACT_MODE_LOOP); KX_MACRO_addTypesToDict(d, KX_ACTION_MODE_PING_PONG, BL_Action::ACT_MODE_PING_PONG); + /* BL_Action blend modes */ + KX_MACRO_addTypesToDict(d, KX_ACTION_BLEND_BLEND, BL_Action::ACT_BLEND_BLEND); + KX_MACRO_addTypesToDict(d, KX_ACTION_BLEND_ADD, BL_Action::ACT_BLEND_ADD); + // Check for errors if (PyErr_Occurred()) { diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h index 9d40fb55747..ca14867e892 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.h +++ b/source/gameengine/Ketsji/KX_RaySensor.h @@ -83,8 +83,8 @@ public: //Python Interface enum RayAxis { - KX_RAY_AXIS_POS_Y = 0, - KX_RAY_AXIS_POS_X, + KX_RAY_AXIS_POS_X = 0, + KX_RAY_AXIS_POS_Y, KX_RAY_AXIS_POS_Z, KX_RAY_AXIS_NEG_X, KX_RAY_AXIS_NEG_Y, diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 35084061ab0..4fa51b48ab8 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -445,7 +445,7 @@ void KX_Scene::AddObjectDebugProperties(class KX_GameObject* gameobj) Object* blenderobject = gameobj->GetBlenderObject(); bProperty* prop = (bProperty*)blenderobject->prop.first; - while(prop) { + while (prop) { if (prop->flag & PROP_DEBUG) AddDebugProperty(gameobj,STR_String(prop->name)); prop = prop->next; @@ -1953,8 +1953,6 @@ bool KX_Scene::MergeScene(KX_Scene *other) GetBucketManager()->MergeBucketManager(other->GetBucketManager(), this); - /* move materials across, assume they both use the same scene-converters */ - GetSceneConverter()->MergeScene(this, other); /* active + inactive == all ??? - lets hope so */ for (int i = 0; i < other->GetObjectList()->GetCount(); i++) @@ -1991,7 +1989,12 @@ bool KX_Scene::MergeScene(KX_Scene *other) if (env) /* bullet scene? - dummy scenes don't need touching */ env->MergeEnvironment(env_other); #endif - + + /* move materials across, assume they both use the same scene-converters + * Do this after lights are merged so materials can use the lights in shaders + */ + GetSceneConverter()->MergeScene(this, other); + /* merge logic */ { SCA_LogicManager *logicmgr= GetLogicManager(); diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index 5438ae5a97c..3a4b1d82946 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.cpp +++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp @@ -109,7 +109,7 @@ void KX_SoundActuator::play() try { - m_handle = AUD_getDevice()->play(sound, 0); + m_handle = AUD_getDevice()->play(sound); } catch(AUD_Exception&) { diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp index 96872f4e6fd..1a9e1442cc8 100644 --- a/source/gameengine/Ketsji/KX_TouchEventManager.cpp +++ b/source/gameengine/Ketsji/KX_TouchEventManager.cpp @@ -81,28 +81,42 @@ bool KX_TouchEventManager::newBroadphaseResponse(void *client_data, void *object2, const PHY_CollData *coll_data) { - PHY_IPhysicsController* ctrl = static_cast<PHY_IPhysicsController*>(object1); - KX_ClientObjectInfo *info = (ctrl) ? static_cast<KX_ClientObjectInfo*>(ctrl->getNewClientInfo()) : NULL; + PHY_IPhysicsController* ctrl1 = static_cast<PHY_IPhysicsController*>(object1); + PHY_IPhysicsController* ctrl2 = static_cast<PHY_IPhysicsController*>(object2); + + KX_ClientObjectInfo *info1 = (ctrl1) ? static_cast<KX_ClientObjectInfo*>(ctrl1->getNewClientInfo()) : NULL; + KX_ClientObjectInfo *info2 = (ctrl1) ? static_cast<KX_ClientObjectInfo*>(ctrl2->getNewClientInfo()) : NULL; + // This call back should only be called for controllers of Near and Radar sensor - if (!info) + if (!info1) return true; - switch (info->m_type) + // Get KX_GameObjects for callbacks + KX_GameObject* gobj1 = info1->m_gameobject; + KX_GameObject* gobj2 = (info2) ? info2->m_gameobject : NULL; + + bool has_py_callbacks = false; + + // Consider callbacks for broadphase inclusion if it's a sensor object type + if (gobj1 && gobj2) + has_py_callbacks = gobj1->m_collisionCallbacks || gobj2->m_collisionCallbacks; + + switch (info1->m_type) { case KX_ClientObjectInfo::SENSOR: - if (info->m_sensors.size() == 1) + if (info1->m_sensors.size() == 1) { // only one sensor for this type of object - KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(*info->m_sensors.begin()); - return touchsensor->BroadPhaseFilterCollision(object1,object2); + KX_TouchSensor* touchsensor = static_cast<KX_TouchSensor*>(*info1->m_sensors.begin()); + return touchsensor->BroadPhaseFilterCollision(object1, object2); } break; case KX_ClientObjectInfo::OBSENSOR: case KX_ClientObjectInfo::OBACTORSENSOR: // this object may have multiple collision sensors, // check is any of them is interested in this object - for (std::list<SCA_ISensor*>::iterator it = info->m_sensors.begin(); - it != info->m_sensors.end(); + for (std::list<SCA_ISensor*>::iterator it = info1->m_sensors.begin(); + it != info1->m_sensors.end(); ++it) { if ((*it)->GetSensorType() == SCA_ISensor::ST_TOUCH) @@ -112,7 +126,8 @@ bool KX_TouchEventManager::newBroadphaseResponse(void *client_data, return true; } } - return false; + + return has_py_callbacks; // quiet the compiler case KX_ClientObjectInfo::STATIC: @@ -155,32 +170,43 @@ void KX_TouchEventManager::EndFrame() void KX_TouchEventManager::NextFrame() { - if (!m_sensors.Empty()) - { SG_DList::iterator<KX_TouchSensor> it(m_sensors); for (it.begin();!it.end();++it) (*it)->SynchronizeTransform(); for (std::set<NewCollision>::iterator cit = m_newCollisions.begin(); cit != m_newCollisions.end(); ++cit) { + // Controllers PHY_IPhysicsController* ctrl1 = (*cit).first; -// PHY_IPhysicsController* ctrl2 = (*cit).second; -// KX_GameObject* gameOb1 = ctrl1->getClientInfo(); -// KX_GameObject* gameOb1 = ctrl1->getClientInfo(); + PHY_IPhysicsController* ctrl2 = (*cit).second; - KX_ClientObjectInfo *client_info = static_cast<KX_ClientObjectInfo *>(ctrl1->getNewClientInfo()); + // Sensor iterator list<SCA_ISensor*>::iterator sit; + + // First client info + KX_ClientObjectInfo *client_info = static_cast<KX_ClientObjectInfo*>(ctrl1->getNewClientInfo()); + // First gameobject + KX_GameObject *kxObj1 = KX_GameObject::GetClientObject(client_info); + // Invoke sensor response for each object if (client_info) { for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit) { - static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision((*cit).first, (*cit).second, NULL); + static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision(ctrl1, ctrl2, NULL); } } - client_info = static_cast<KX_ClientObjectInfo *>((*cit).second->getNewClientInfo()); + + // Second client info + client_info = static_cast<KX_ClientObjectInfo *>(ctrl2->getNewClientInfo()); + // Second gameobject + KX_GameObject *kxObj2 = KX_GameObject::GetClientObject(client_info); if (client_info) { for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit) { - static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision((*cit).second, (*cit).first, NULL); + static_cast<KX_TouchSensor*>(*sit)->NewHandleCollision(ctrl2, ctrl1, NULL); } } + // Run python callbacks + kxObj1->RunCollisionCallbacks(kxObj2); + kxObj2->RunCollisionCallbacks(kxObj1); + } m_newCollisions.clear(); @@ -188,4 +214,3 @@ void KX_TouchEventManager::NextFrame() for (it.begin();!it.end();++it) (*it)->Activate(m_logicmgr); } -} diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.cpp b/source/gameengine/Rasterizer/RAS_BucketManager.cpp index 7d1190bef5c..713d324bf17 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.cpp +++ b/source/gameengine/Rasterizer/RAS_BucketManager.cpp @@ -378,17 +378,10 @@ void RAS_BucketManager::MergeBucketManager(RAS_BucketManager *other, SCA_IScene { /* concatinate lists */ // printf("BEFORE %d %d\n", GetSolidBuckets().size(), GetAlphaBuckets().size()); - BucketList::iterator it; - - for (it = other->GetSolidBuckets().begin(); it != other->GetSolidBuckets().end(); ++it) - (*it)->GetPolyMaterial()->Replace_IScene(scene); GetSolidBuckets().insert( GetSolidBuckets().end(), other->GetSolidBuckets().begin(), other->GetSolidBuckets().end() ); other->GetSolidBuckets().clear(); - for (it = other->GetAlphaBuckets().begin(); it != other->GetAlphaBuckets().end(); ++it) - (*it)->GetPolyMaterial()->Replace_IScene(scene); - GetAlphaBuckets().insert( GetAlphaBuckets().end(), other->GetAlphaBuckets().begin(), other->GetAlphaBuckets().end() ); other->GetAlphaBuckets().clear(); //printf("AFTER %d %d\n", GetSolidBuckets().size(), GetAlphaBuckets().size()); diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.cpp b/source/gameengine/Rasterizer/RAS_MeshObject.cpp index 2af71c5efa9..8a9672f0092 100644 --- a/source/gameengine/Rasterizer/RAS_MeshObject.cpp +++ b/source/gameengine/Rasterizer/RAS_MeshObject.cpp @@ -125,17 +125,6 @@ RAS_MeshObject::~RAS_MeshObject() { vector<RAS_Polygon*>::iterator it; - if (m_mesh && m_mesh->key) - { - KeyBlock *kb; - // remove the weight cache to avoid memory leak - for (kb = (KeyBlock *)m_mesh->key->block.first; kb; kb = (KeyBlock *)kb->next) { - if (kb->weights) - MEM_freeN(kb->weights); - kb->weights= NULL; - } - } - for (it=m_Polygons.begin(); it!=m_Polygons.end(); it++) delete (*it); @@ -559,61 +548,3 @@ void RAS_MeshObject::SchedulePolygons(int drawingmode) m_bMeshModified = true; } } - -static int get_def_index(Object* ob, const char* vgroup) -{ - bDeformGroup *curdef; - int index = 0; - - for (curdef = (bDeformGroup*)ob->defbase.first; curdef; curdef=(bDeformGroup*)curdef->next, index++) - if (!strcmp(curdef->name, vgroup)) - return index; - - return -1; -} - -void RAS_MeshObject::CheckWeightCache(Object* obj) -{ - KeyBlock *kb; - int kbindex, defindex; - MDeformVert *dv= NULL; - int totvert, i; - float *weights; - - if (!m_mesh->key) - return; - - for (kbindex = 0, kb = (KeyBlock *)m_mesh->key->block.first; kb; kb = kb->next, kbindex++) - { - // first check the cases where the weight must be cleared - if (kb->vgroup[0] == 0 || - m_mesh->dvert == NULL || - (defindex = get_def_index(obj, kb->vgroup)) == -1) { - if (kb->weights) { - MEM_freeN(kb->weights); - kb->weights = NULL; - } - m_cacheWeightIndex[kbindex] = -1; - } else if (m_cacheWeightIndex[kbindex] != defindex) { - // a weight array is required but the cache is not matching - if (kb->weights) { - MEM_freeN(kb->weights); - kb->weights = NULL; - } - - dv= m_mesh->dvert; - totvert= m_mesh->totvert; - - weights= (float*)MEM_mallocN(totvert*sizeof(float), "weights"); - - for (i=0; i < totvert; i++, dv++) { - weights[i] = defvert_find_weight(dv, defindex); - } - - kb->weights = weights; - m_cacheWeightIndex[kbindex] = defindex; - } - } -} - - diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.h b/source/gameengine/Rasterizer/RAS_MeshObject.h index d77d0483024..e5ae78d006e 100644 --- a/source/gameengine/Rasterizer/RAS_MeshObject.h +++ b/source/gameengine/Rasterizer/RAS_MeshObject.h @@ -83,9 +83,6 @@ public: virtual ~RAS_MeshObject(); - // for shape keys, - void CheckWeightCache(struct Object* obj); - /* materials */ int NumMaterials(); const STR_String& GetMaterialName(unsigned int matid); diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp index a1c0836417a..e1dbd6f0a7f 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp @@ -127,11 +127,8 @@ bool RAS_ListSlot::End() RAS_ListRasterizer::RAS_ListRasterizer(RAS_ICanvas* canvas, bool lock, int storage) -: RAS_OpenGLRasterizer(canvas, storage), - mATI(false) +: RAS_OpenGLRasterizer(canvas, storage) { - if (!strcmp((const char*)glGetString(GL_VENDOR), "ATI Technologies Inc.")) - mATI = true; } RAS_ListRasterizer::~RAS_ListRasterizer() diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h index 558850a9173..d394c72b2a2 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h @@ -51,7 +51,6 @@ typedef std::map<DerivedMesh*, RAS_ListSlots*> RAS_DerivedMeshLists; class RAS_ListRasterizer : public RAS_OpenGLRasterizer { - bool mATI; RAS_ArrayLists mArrayLists; RAS_DerivedMeshLists mDerivedMeshLists; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp index c24cfdb4ef0..bfc74e0c6dc 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp @@ -1010,7 +1010,11 @@ void RAS_OpenGLRasterizer::DisableMotionBlur() void RAS_OpenGLRasterizer::SetAlphaBlend(int alphablend) { - GPU_set_material_alpha_blend(alphablend); + /* Variance shadow maps don't handle alpha well, best to not allow it for now */ + if (m_drawingmode == KX_SHADOW && m_usingoverrideshader) + GPU_set_material_alpha_blend(GPU_BLEND_SOLID); + else + GPU_set_material_alpha_blend(alphablend); /* if (alphablend == m_last_alphablend) return; diff --git a/source/tests/bl_run_operators.py b/source/tests/bl_run_operators.py index effc06cd15f..ad8a6919c91 100644 --- a/source/tests/bl_run_operators.py +++ b/source/tests/bl_run_operators.py @@ -342,7 +342,8 @@ def ctx_editmode_curves(): def ctx_editmode_curves_empty(): bpy.ops.curve.primitive_nurbs_circle_add() bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.curve.delete(type='ALL') + bpy.ops.curve.select_all(action='SELECT') + bpy.ops.curve.delete(type='VERT') def ctx_editmode_surface(): |