diff options
Diffstat (limited to 'source')
694 files changed, 26376 insertions, 8774 deletions
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 2bdae87dc83..4891c332c87 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -186,9 +186,9 @@ void blf_font_draw(FontBLF *font, const char *str, size_t len) while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); - if (c == BLI_UTF8_ERR) + if (UNLIKELY(c == BLI_UTF8_ERR)) break; - if (g == NULL) + if (UNLIKELY(g == NULL)) continue; if (has_kerning) BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); @@ -196,7 +196,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 += (int)g->advance; + pen_x += g->advance_i; g_prev = g; } } @@ -224,7 +224,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 += (int)g->advance; + pen_x += g->advance_i; g_prev = g; } } @@ -244,9 +244,9 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); - if (c == BLI_UTF8_ERR) + if (UNLIKELY(c == BLI_UTF8_ERR)) break; - if (g == NULL) + if (UNLIKELY(g == NULL)) continue; /* do not return this loop if clipped, we want every character tested */ @@ -303,9 +303,9 @@ void blf_font_buffer(FontBLF *font, const char *str) while (str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); - if (c == BLI_UTF8_ERR) + if (UNLIKELY(c == BLI_UTF8_ERR)) break; - if (g == NULL) + if (UNLIKELY(g == NULL)) continue; if (has_kerning) BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); @@ -415,7 +415,7 @@ void blf_font_buffer(FontBLF *font, const char *str) } } - pen_x += (int)g->advance; + pen_x += g->advance_i; g_prev = g; } } @@ -438,14 +438,14 @@ size_t blf_font_width_to_strlen(FontBLF *font, const char *str, size_t len, floa while ((i_prev = i), (width_new = pen_x), ((i < len) && str[i])) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); - if (c == BLI_UTF8_ERR) + if (UNLIKELY(c == BLI_UTF8_ERR)) break; - if (g == NULL) + if (UNLIKELY(g == NULL)) continue; if (has_kerning) BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); - pen_x += (int)g->advance; + pen_x += g->advance_i; if (width_i < pen_x) { break; @@ -501,14 +501,14 @@ size_t blf_font_width_to_rstrlen(FontBLF *font, const char *str, size_t len, flo while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); - if (c == BLI_UTF8_ERR) + if (UNLIKELY(c == BLI_UTF8_ERR)) break; - if (g == NULL) + if (UNLIKELY(g == NULL)) continue; if (has_kerning) BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); - pen_x += (int)g->advance; + pen_x += g->advance_i; width_accum[width_accum_ofs][0] = (int)i; width_accum[width_accum_ofs][1] = pen_x; @@ -570,9 +570,9 @@ void blf_font_boundbox(FontBLF *font, const char *str, size_t len, rctf *box) while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); - if (c == BLI_UTF8_ERR) + if (UNLIKELY(c == BLI_UTF8_ERR)) break; - if (g == NULL) + if (UNLIKELY(g == NULL)) continue; if (has_kerning) BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); @@ -588,7 +588,7 @@ void blf_font_boundbox(FontBLF *font, const char *str, size_t len, rctf *box) if (gbox.xmax > box->xmax) box->xmax = gbox.xmax; if (gbox.ymax > box->ymax) box->ymax = gbox.ymax; - pen_x += (int)g->advance; + pen_x += g->advance_i; g_prev = g; } diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 7c3cfa30e16..a2462f3e302 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -153,7 +153,7 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc) /* move the index. */ gc->cur_tex++; - if (gc->cur_tex >= gc->ntex) { + if (UNLIKELY(gc->cur_tex >= gc->ntex)) { gc->ntex *= 2; gc->textures = (GLuint *)MEM_reallocN((void *)gc->textures, sizeof(GLuint) * gc->ntex); } @@ -279,6 +279,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c) } g->advance = ((float)slot->advance.x) / 64.0f; + g->advance_i = (int)g->advance; g->pos_x = (float)slot->bitmap_left; g->pos_y = (float)slot->bitmap_top; g->pitch = slot->bitmap.pitch; diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index c64b7e974e7..da756d65483 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -99,6 +99,8 @@ typedef struct GlyphBLF { /* advance size. */ float advance; + /* avoid conversion to int while drawing */ + int advance_i; /* texture id where this glyph is store. */ GLuint tex; diff --git a/source/blender/blenfont/intern/blf_lang.c b/source/blender/blenfont/intern/blf_lang.c index 2852b8161c8..12d71827136 100644 --- a/source/blender/blenfont/intern/blf_lang.c +++ b/source/blender/blenfont/intern/blf_lang.c @@ -235,15 +235,11 @@ void BLF_lang_set(const char *str) else { short_locale_utf8 = BLI_sprintfN("%s.UTF-8", short_locale); } + bl_locale_set(short_locale_utf8); + MEM_freeN((void *)short_locale_utf8); } else { - short_locale_utf8 = short_locale; - } - - bl_locale_set(short_locale_utf8); - - if (short_locale[0]) { - MEM_freeN((void *)short_locale_utf8); + bl_locale_set(short_locale); } #else (void)str; diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 1ab5ec51de8..229d2fc17cd 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -150,8 +150,10 @@ typedef DMDrawOption (*DMSetDrawOptions)(void *userData, int index); typedef DMDrawOption (*DMSetDrawOptionsTex)(struct MTFace *tface, const bool has_vcol, int matnr); typedef enum DMDrawFlag { - DM_DRAW_USE_COLORS = 1, - DM_DRAW_ALWAYS_SMOOTH = 2 + DM_DRAW_USE_COLORS = (1 << 0), + DM_DRAW_ALWAYS_SMOOTH = (1 << 1), + DM_DRAW_USE_ACTIVE_UV = (1 << 2), + DM_DRAW_USE_TEXPAINT_UV = (1 << 3), } DMDrawFlag; typedef enum DMForeachFlag { @@ -389,7 +391,7 @@ struct DerivedMesh { void (*drawFacesTex)(DerivedMesh *dm, DMSetDrawOptionsTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData); + void *userData, DMDrawFlag uvflag); /** Draw all faces with GLSL materials * o setMaterial is called for every different material nr @@ -423,7 +425,7 @@ struct DerivedMesh { void (*drawMappedFacesTex)(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData); + void *userData, DMDrawFlag uvflag); /** Draw mapped faces with GLSL materials * - setMaterial is called for every different material nr @@ -593,6 +595,8 @@ void DM_ensure_tessface(DerivedMesh *dm); void DM_update_tessface_data(DerivedMesh *dm); void DM_update_materials(DerivedMesh *dm, struct Object *ob); +struct MTFace *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr); + /** interpolates vertex data from the vertices indexed by src_indices in the * source mesh using the given weights and stores the result in the vertex * indexed by dest_index in the dest mesh @@ -647,6 +651,7 @@ void vDM_ColorBand_store(const struct ColorBand *coba, const char alert_color[4] * In use now by vertex/weight paint and particles */ DMCoNo *mesh_get_mapped_verts_nors(struct Scene *scene, struct Object *ob); #endif +void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int totcos); /* */ DerivedMesh *mesh_get_derived_final(struct Scene *scene, struct Object *ob, @@ -687,6 +692,9 @@ DerivedMesh *editbmesh_get_derived_cage(struct Scene *scene, struct Object *, DerivedMesh *editbmesh_get_derived_cage_and_final(struct Scene *scene, struct Object *, struct BMEditMesh *em, DerivedMesh **r_final, CustomDataMask dataMask); + +DerivedMesh *object_get_derived_final(struct Object *ob, const bool for_render); + float (*editbmesh_get_vertex_cos(struct BMEditMesh *em, int *r_numVerts))[3]; bool editbmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, DerivedMesh *dm); void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct BMEditMesh *em, diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 0af45a147a4..46a0c36a5f2 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -42,7 +42,7 @@ extern "C" { * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 271 -#define BLENDER_SUBVERSION 1 +#define BLENDER_SUBVERSION 6 /* 262 was the last editmesh release but it has compatibility code for bmesh data */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 5 @@ -69,10 +69,12 @@ 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 update_defaults); -int BKE_read_file_from_memfile(struct bContext *C, struct MemFile *memfile, - struct ReportList *reports); +bool BKE_read_file_from_memory( + struct bContext *C, const void *filebuf, + int filelength, struct ReportList *reports, bool update_defaults); +bool 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); diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 104e80e815c..d48753590bb 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -81,7 +81,11 @@ unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool /* radial control */ struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, bool secondary); -/* unified strength and size */ +/* unified strength size and color */ + +float *BKE_brush_color_get(const struct Scene *scene, struct Brush *brush); +float *BKE_brush_secondary_color_get(const struct Scene *scene, struct Brush *brush); +void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float color[3]); int BKE_brush_size_get(const struct Scene *scene, struct Brush *brush); void BKE_brush_size_set(struct Scene *scene, struct Brush *brush, int value); diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h index dffc2b665c2..b0ade7bacdf 100644 --- a/source/blender/blenkernel/BKE_cdderivedmesh.h +++ b/source/blender/blenkernel/BKE_cdderivedmesh.h @@ -58,7 +58,13 @@ struct DerivedMesh *CDDM_from_bmesh(struct BMesh *bm, const bool use_mdisps); DerivedMesh *CDDM_from_editbmesh(struct BMEditMesh *em, const bool use_mdisps, const bool use_tessface); /* merge verts */ -DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap); +/* Enum for merge_mode of CDDM_merge_verts. + * Refer to cdderivedmesh.c for details. */ +enum { + CDDM_MERGE_VERTS_DUMP_IF_MAPPED, + CDDM_MERGE_VERTS_DUMP_IF_EQUAL, +}; +DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode); /* creates a CDDerivedMesh from the given curve object */ struct DerivedMesh *CDDM_from_curve(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index e30c8ecee2b..877e376b343 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -234,7 +234,6 @@ int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBas struct Main *CTX_data_main(const bContext *C); struct Scene *CTX_data_scene(const bContext *C); struct ToolSettings *CTX_data_tool_settings(const bContext *C); -struct FreestyleLineStyle *CTX_data_linestyle_from_scene(struct Scene *scene); const char *CTX_data_mode_string(const bContext *C); int CTX_data_mode_enum(const bContext *C); diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 0f9f8cb2f08..5de7d9936e6 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -84,9 +84,12 @@ void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_rot[3], fl bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]); bool BKE_curve_center_median(struct Curve *cu, float cent[3]); bool BKE_curve_center_bounds(struct Curve *cu, float cent[3]); +void BKE_curve_transform_ex(struct Curve *cu, float mat[4][4], bool do_keys, const float unit_scale); +void BKE_curve_transform(struct Curve *cu, float mat[4][4], bool do_keys); void BKE_curve_translate(struct Curve *cu, float offset[3], const bool do_keys); void BKE_curve_material_index_remove(struct Curve *cu, int index); void BKE_curve_material_index_clear(struct Curve *cu); +int BKE_curve_material_index_validate(struct Curve *cu); ListBase *BKE_curve_nurbs_get(struct Curve *cu); @@ -110,6 +113,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_free(struct ListBase *bev); 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, const bool for_render, const bool use_render_resolution); diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h index 355e817f621..168f700d132 100644 --- a/source/blender/blenkernel/BKE_editmesh_bvh.h +++ b/source/blender/blenkernel/BKE_editmesh_bvh.h @@ -43,9 +43,16 @@ struct Scene; typedef struct BMBVHTree BMBVHTree; -BMBVHTree *BKE_bmbvh_new_from_editmesh(struct BMEditMesh *em, int flag, const float (*cos_cage)[3], const bool cos_cage_free); -BMBVHTree *BKE_bmbvh_new(struct BMesh *bm, struct BMLoop *(*looptris)[3], int looptris_tot, int flag, - const float (*cos_cage)[3], const bool cos_cage_free); +BMBVHTree *BKE_bmbvh_new_from_editmesh( + struct BMEditMesh *em, int flag, + const float (*cos_cage)[3], const bool cos_cage_free); +BMBVHTree *BKE_bmbvh_new_ex( + struct BMesh *bm, struct BMLoop *(*looptris)[3], int looptris_tot, int flag, + const float (*cos_cage)[3], const bool cos_cage_free, + bool (*test_fn)(struct BMFace *, void *user_data), void *user_data); +BMBVHTree *BKE_bmbvh_new( + struct BMesh *bm, struct BMLoop *(*looptris)[3], int looptris_tot, 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], const float radius, diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 3cf944fa236..2ab3d84dea5 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -121,13 +121,29 @@ void IDP_ClearProperty(IDProperty *prop); void IDP_UnlinkProperty(struct IDProperty *prop); #define IDP_Int(prop) ((prop)->data.val) -#define IDP_Float(prop) (*(float *)&(prop)->data.val) -#define IDP_Double(prop) (*(double *)&(prop)->data.val) -#define IDP_String(prop) ((char *) (prop)->data.pointer) #define IDP_Array(prop) ((prop)->data.pointer) -#define IDP_IDPArray(prop) ((IDProperty *) (prop)->data.pointer) +/* C11 const correctness for casts */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +# define IDP_Float(prop) _Generic((prop), \ + IDProperty *: (*(float *)&(prop)->data.val), \ + const IDProperty *: (*(const float *)&(prop)->data.val)) +# define IDP_Double(prop) _Generic((prop), \ + IDProperty *: (*(double *)&(prop)->data.val), \ + const IDProperty *: (*(const double *)&(prop)->data.val)) +# define IDP_String(prop) _Generic((prop), \ + IDProperty *: ((char *) (prop)->data.pointer), \ + const IDProperty *: ((const char *) (prop)->data.pointer)) +# define IDP_IDPArray(prop) _Generic((prop), \ + IDProperty *: ((IDProperty *) (prop)->data.pointer), \ + const IDProperty *: ((const IDProperty *) (prop)->data.pointer)) +#else +# define IDP_Float(prop) (*(float *)&(prop)->data.val) +# define IDP_Double(prop) (*(double *)&(prop)->data.val) +# define IDP_String(prop) ((char *) (prop)->data.pointer) +# define IDP_IDPArray(prop) ((IDProperty *) (prop)->data.pointer) +#endif -#ifdef DEBUG +#ifndef NDEBUG /* for printout only */ void IDP_spit(IDProperty *prop); #endif diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 8d8d3702634..5fb1053b53f 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -84,6 +84,7 @@ void BKE_lattice_minmax(struct Lattice *lt, float min[3], float max[3]); void BKE_lattice_center_median(struct Lattice *lt, float cent[3]); void BKE_lattice_center_bounds(struct Lattice *lt, float cent[3]); void BKE_lattice_translate(struct Lattice *lt, float offset[3], bool do_keys); +void BKE_lattice_transform(struct Lattice *lt, float mat[4][4], bool do_keys); int BKE_lattice_index_from_uvw(struct Lattice *lt, const int u, const int v, const int w); void BKE_lattice_index_to_uvw(struct Lattice *lt, const int index, int *r_u, int *r_v, int *r_w); diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 0372931dc49..1d37f9e64e1 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -71,7 +71,7 @@ void id_clear_lib_data(struct Main *bmain, struct ID *id); struct ListBase *which_libbase(struct Main *mainlib, short type); -#define MAX_LIBARRAY 41 +#define MAX_LIBARRAY 43 int set_listbasepointers(struct Main *main, struct ListBase **lb); void BKE_libblock_free(struct Main *bmain, void *idv); @@ -104,6 +104,7 @@ 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_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void set_free_windowmanager_cb(void (*func)(struct bContext *, struct wmWindowManager *) ); diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h index 8bc8cc44d92..ae10ba4caab 100644 --- a/source/blender/blenkernel/BKE_linestyle.h +++ b/source/blender/blenkernel/BKE_linestyle.h @@ -35,6 +35,10 @@ #include "DNA_linestyle_types.h" +#ifdef __cplusplus +extern "C" { +#endif + #define LS_MODIFIER_TYPE_COLOR 1 #define LS_MODIFIER_TYPE_ALPHA 2 #define LS_MODIFIER_TYPE_THICKNESS 3 @@ -43,34 +47,45 @@ struct Main; struct Object; struct ColorBand; +struct bContext; + +FreestyleLineStyle *BKE_linestyle_new(const char *name, struct Main *main); +void BKE_linestyle_free(FreestyleLineStyle *linestyle); +FreestyleLineStyle *BKE_linestyle_copy(FreestyleLineStyle *linestyle); + +FreestyleLineStyle *BKE_linestyle_active_from_scene(struct Scene *scene); + +LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type); +LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type); +LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type); +LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type); + +LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m); +LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m); +LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m); +LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m); -FreestyleLineStyle *BKE_new_linestyle(const char *name, struct Main *main); -void BKE_free_linestyle(FreestyleLineStyle *linestyle); -FreestyleLineStyle *BKE_copy_linestyle(FreestyleLineStyle *linestyle); +int BKE_linestyle_color_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier); +int BKE_linestyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier); +int BKE_linestyle_thickness_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier); +int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier); -LineStyleModifier *BKE_add_linestyle_color_modifier(FreestyleLineStyle *linestyle, const char *name, int type); -LineStyleModifier *BKE_add_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, const char *name, int type); -LineStyleModifier *BKE_add_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, const char *name, int type); -LineStyleModifier *BKE_add_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, const char *name, int type); +void BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction); +void BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction); +void BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction); +void BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction); -LineStyleModifier *BKE_copy_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m); -LineStyleModifier *BKE_copy_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m); -LineStyleModifier *BKE_copy_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m); -LineStyleModifier *BKE_copy_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m); +void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase); +char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, struct ColorBand *color_ramp); -int BKE_remove_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier); -int BKE_remove_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier); -int BKE_remove_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier); -int BKE_remove_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier); +void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob); -void BKE_move_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction); -void BKE_move_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction); -void BKE_move_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction); -void BKE_move_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction); +bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes); -void BKE_list_modifier_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase); -char *BKE_path_from_ID_to_color_ramp(FreestyleLineStyle *linestyle, struct ColorBand *color_ramp); +void BKE_linestyle_default_shader(const struct bContext *C, FreestyleLineStyle *linestyle); -void BKE_unlink_linestyle_target_object(FreestyleLineStyle *linestyle, struct Object *ob); +#ifdef __cplusplus +} +#endif #endif /* __BKE_LINESTYLE_H__ */ diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 82b03127237..ec654ea4b71 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -87,6 +87,8 @@ typedef struct Main { ListBase nodetree; ListBase brush; ListBase particle; + ListBase palettes; + ListBase paintcurves; ListBase wm; ListBase gpencil; ListBase movieclip; diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index 89d310753fc..2f20505bea3 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -86,6 +86,9 @@ short find_material_index(struct Object *ob, struct Material *ma); bool object_add_material_slot(struct Object *ob); bool object_remove_material_slot(struct Object *ob); +void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma); +void BKE_texpaint_slots_refresh_object(struct Scene *scene, 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); diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index 56ea44fa6e9..c021960e730 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -63,6 +63,7 @@ bool BKE_mball_minmax_ex(struct MetaBall *mb, float min[3], float max[3], float obmat[4][4], const short flag); bool BKE_mball_center_median(struct MetaBall *mb, float r_cent[3]); bool BKE_mball_center_bounds(struct MetaBall *mb, float r_cent[3]); +void BKE_mball_transform(struct MetaBall *mb, float mat[4][4]); void BKE_mball_translate(struct MetaBall *mb, const float offset[3]); struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 587dea5095c..b2b9e37f500 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -133,6 +133,7 @@ struct Mesh *BKE_mesh_new_from_object(struct Main *bmain, struct Scene *sce, str /* 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_transform(struct Mesh *me, float mat[4][4], bool do_keys); void BKE_mesh_translate(struct Mesh *me, const float offset[3], const bool do_keys); void BKE_mesh_ensure_navmesh(struct Mesh *me); @@ -212,6 +213,10 @@ 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]); +void BKE_mesh_calc_volume(struct MVert *mverts, int numVerts, + struct MFace *mfaces, int numFaces, + float *r_vol, float *r_com); + /* tessface */ void BKE_mesh_loops_to_mface_corners( struct CustomData *fdata, struct CustomData *ldata, @@ -283,6 +288,7 @@ void BKE_mesh_calc_relative_deform( int BKE_mesh_validate(struct Mesh *me, const int do_verbose); void BKE_mesh_cd_validate(struct Mesh *me); +int BKE_mesh_validate_material_indices(struct Mesh *me); bool BKE_mesh_validate_arrays( struct Mesh *me, diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index c81133a85fa..cb96538ad81 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -342,7 +342,7 @@ struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char /* copy/free funcs, need to manage ID users */ void ntreeFreeTree_ex(struct bNodeTree *ntree, const bool do_id_user); void ntreeFreeTree(struct bNodeTree *ntree); -struct bNodeTree *ntreeCopyTree_ex(struct bNodeTree *ntree, const bool do_id_user); +struct bNodeTree *ntreeCopyTree_ex(struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user); struct bNodeTree *ntreeCopyTree(struct bNodeTree *ntree); void ntreeSwitchID_ex(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to, const bool do_id_user); void ntreeSwitchID(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to); @@ -585,6 +585,9 @@ void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufu void node_type_internal_links(struct bNodeType *ntype, void (*update_internal_links)(struct bNodeTree *, struct bNode *)); void node_type_compatibility(struct bNodeType *ntype, short compatibility); +/* ************** GENERIC NODE FUNCTIONS *************** */ +bool BKE_node_is_connected_to_output(struct bNodeTree *ntree, struct bNode *node); + /* ************** COMMON NODES *************** */ #define NODE_UNDEFINED -2 /* node type is not registered */ @@ -749,6 +752,8 @@ struct ShadeResult; #define SH_NODE_UVMAP 187 #define SH_NODE_SEPXYZ 188 #define SH_NODE_COMBXYZ 189 +#define SH_NODE_OUTPUT_LINESTYLE 190 +#define SH_NODE_UVALONGSTROKE 191 /* custom defines options for Material node */ #define SH_NODE_MAT_DIFF 1 @@ -891,6 +896,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria #define CMP_NODE_GLARE 301 #define CMP_NODE_TONEMAP 302 #define CMP_NODE_LENSDIST 303 +#define CMP_NODE_SUNBEAMS 304 #define CMP_NODE_COLORCORRECTION 312 #define CMP_NODE_MASK_BOX 313 diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index c0da816ca59..1bfd26d4f8c 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -103,6 +103,8 @@ void BKE_object_make_local(struct Object *ob); bool BKE_object_is_libdata(struct Object *ob); bool BKE_object_obdata_is_libdata(struct Object *ob); +void BKE_object_obdata_size_init(struct Object *ob, const float scale); + void BKE_object_scale_to_mat3(struct Object *ob, float mat[3][3]); void BKE_object_rot_to_mat3(struct Object *ob, float mat[3][3], bool use_drot); void BKE_object_mat3_to_rot(struct Object *ob, float mat[3][3], bool use_compat); @@ -124,14 +126,18 @@ void BKE_object_where_is_calc_mat4(struct Scene *scene, struct Object *ob, float /* possibly belong in own moduke? */ struct BoundBox *BKE_boundbox_alloc_unit(void); void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], const float max[3]); -bool BKE_boundbox_ray_hit_check(struct BoundBox *bb, const float ray_start[3], const float ray_normal[3], - float *r_lambda); +bool BKE_boundbox_ray_hit_check( + const struct BoundBox *bb, + const float ray_start[3], const float ray_normal[3], + float *r_lambda); +void BKE_boundbox_calc_center_aabb(const struct BoundBox *bb, float r_cent[3]); +void BKE_boundbox_calc_size_aabb(const struct BoundBox *bb, float r_size[3]); struct BoundBox *BKE_object_boundbox_get(struct Object *ob); void BKE_object_dimensions_get(struct Object *ob, float vec[3]); void BKE_object_dimensions_set(struct Object *ob, const float value[3]); void BKE_object_empty_draw_type_set(struct Object *ob, const int value); -void BKE_object_boundbox_flag(struct Object *ob, int flag, int set); +void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set); void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden); bool BKE_object_minmax_dupli(struct Scene *scene, struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden); diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 43813300850..a81da8c18af 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -40,11 +40,15 @@ struct CurveMapping; struct MDisps; struct MeshElemMap; struct GridPaintMask; +struct Main; struct MFace; struct MultireModifierData; struct MVert; struct Object; struct Paint; +struct PaintCurve; +struct Palette; +struct PaletteColor; struct PBVH; struct Scene; struct Sculpt; @@ -52,6 +56,7 @@ struct StrokeCache; struct Tex; struct ImagePool; struct UnifiedPaintSettings; +struct wmOperator; enum OverlayFlags; @@ -91,6 +96,19 @@ OverlayControlFlags BKE_paint_get_overlay_flags(void); void BKE_paint_reset_overlay_invalid(OverlayControlFlags flag); void BKE_paint_set_overlay_override(enum OverlayFlags flag); +/* palettes */ +void BKE_palette_free(struct Palette *palette); +struct Palette *BKE_palette_add(struct Main *bmain, const char *name); +struct PaletteColor *BKE_palette_color_add(struct Palette *palette); +void BKE_palette_color_delete(struct Palette *palette); +bool BKE_palette_is_empty(const struct Palette *palette); +void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color); +void BKE_palette_cleanup(struct Palette *palette); + +/* paint curves */ +struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name); +void BKE_paint_curve_free(struct PaintCurve *pc); + void BKE_paint_init(struct Paint *p, const char col[3]); void BKE_paint_free(struct Paint *p); void BKE_paint_copy(struct Paint *src, struct Paint *tar); @@ -100,6 +118,9 @@ struct Paint *BKE_paint_get_active_from_context(const struct bContext *C); PaintMode BKE_paintmode_get_active_from_context(const struct bContext *C); struct Brush *BKE_paint_brush(struct Paint *paint); void BKE_paint_brush_set(struct Paint *paint, struct Brush *br); +struct Palette *BKE_paint_palette(struct Paint *paint); +void BKE_paint_palette_set(struct Paint *p, struct Palette *palette); +void BKE_paint_curve_set(struct Brush *br, struct PaintCurve *pc); /* testing face select mode * Texture paint could be removed since selected faces are not used @@ -117,7 +138,10 @@ bool paint_is_bmesh_face_hidden(struct BMFace *f); /* paint masks */ float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level, unsigned x, unsigned y); + +/* stroke related */ void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, const float mouse_pos[2]); + /* Session data (mode-specific) */ typedef struct SculptSession { @@ -146,7 +170,7 @@ typedef struct SculptSession { struct PBVH *pbvh; bool show_diffuse_color; - /* Paiting on deformed mesh */ + /* Painting on deformed mesh */ bool modifiers_active; /* object is deformed with some modifiers */ float (*orig_cos)[3]; /* coords of undeformed mesh */ float (*deform_cos)[3]; /* coords of deformed mesh but without stroke displacement */ diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h index 86be3bfe770..c946f3ac9e8 100644 --- a/source/blender/blenkernel/BKE_rigidbody.h +++ b/source/blender/blenkernel/BKE_rigidbody.h @@ -69,6 +69,9 @@ void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw); /* 'validate' (i.e. make new or replace old) Physics-Engine objects */ void BKE_rigidbody_validate_sim_world(struct Scene *scene, struct RigidBodyWorld *rbw, bool rebuild); +void BKE_rigidbody_calc_volume(struct Object *ob, float *r_vol); +void BKE_rigidbody_calc_center_of_mass(struct Object *ob, float r_com[3]); + /* -------------- */ /* Utilities */ diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index a10a3f3f59f..1bfe0eeea0b 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -48,6 +48,7 @@ struct RenderData; struct SceneRenderLayer; struct Scene; struct Text; +struct UnitSettings; struct Main; #define SCE_COPY_NEW 0 @@ -84,6 +85,7 @@ typedef struct SceneBaseIter { struct ListBase *duplilist; struct DupliObject *dupob; float omat[4][4]; + struct Object *dupli_refob; int phase; } SceneBaseIter; @@ -129,6 +131,7 @@ int get_render_shadow_samples(struct RenderData *r, int samples); float get_render_aosss_error(struct RenderData *r, float error); bool BKE_scene_use_new_shading_nodes(struct Scene *scene); +bool BKE_scene_uses_blender_internal(struct Scene *scene); void BKE_scene_disable_color_management(struct Scene *scene); bool BKE_scene_check_color_management_enabled(const struct Scene *scene); @@ -137,6 +140,8 @@ bool BKE_scene_check_rigidbody_active(const struct Scene *scene); int BKE_scene_num_threads(const struct Scene *scene); int BKE_render_num_threads(const struct RenderData *r); +double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 4cbd7e966f2..188b8e22815 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -53,6 +53,8 @@ struct wmNotifier; struct wmWindow; struct wmWindowManager; +#include "BLI_compiler_attrs.h" + #include "RNA_types.h" /* spacetype has everything stored to get an editor working, it gets initialized via @@ -280,6 +282,11 @@ struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type); struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa); struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min); +unsigned int BKE_screen_view3d_layer_active_ex( + const struct View3D *v3d, const struct Scene *scene, bool use_localvd) ATTR_NONNULL(2); +unsigned int BKE_screen_view3d_layer_active( + const struct View3D *v3d, const struct Scene *scene) ATTR_NONNULL(2); + void BKE_screen_view3d_sync(struct View3D *v3d, struct Scene *scene); void BKE_screen_view3d_scene_sync(struct bScreen *sc); void BKE_screen_view3d_main_sync(ListBase *screen_lb, struct Scene *scene); diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index de52c72a136..13cc5d2e84f 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -308,7 +308,7 @@ void BKE_sequencer_offset_animdata(struct Scene *scene, struct Sequence *seq, in void BKE_sequencer_dupe_animdata(struct Scene *scene, const char *name_src, const char *name_dst); bool BKE_sequence_base_shuffle(struct ListBase *seqbasep, struct Sequence *test, struct Scene *evil_scene); bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, struct Scene *evil_scene); -bool BKE_sequence_base_isolated_sel_check(struct ListBase *seqbase); +bool BKE_sequence_base_isolated_sel_check(struct ListBase *seqbase, bool one_only); void BKE_sequencer_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render); struct Sequence *BKE_sequence_dupli_recursive(struct Scene *scene, struct Scene *scene_to, struct Sequence *seq, int dupe_flag); int BKE_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str); diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index 59de43af907..070cd4a9cf0 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -31,52 +31,6 @@ * \ingroup bke */ -/* mesh util */ - -//TODO: move this somewhere else -#include "BKE_customdata.h" -struct DerivedMesh; -struct Object; -struct DerivedMesh *object_get_derived_final(struct Object *ob, bool for_render); - - -/* SpaceTransform stuff */ -/* - * TODO: move this somewhere else - * - * this structs encapsulates all needed data to convert between 2 coordinate spaces - * (where conversion can be represented by a matrix multiplication) - * - * This is used to reduce the number of arguments to pass to functions that need to perform - * this kind of operation and make it easier for the coder, as he/she doenst needs to recode - * the matrix calculation. - * - * A SpaceTransform is initialized using: - * SPACE_TRANSFORM_SETUP( &data, ob1, ob2 ) - * - * After that the following calls can be used: - * space_transform_apply (&data, co); //converts a coordinate in ob1 coords space to the corresponding ob2 coords - * space_transform_invert(&data, co); //converts a coordinate in ob2 coords space to the corresponding ob1 coords - * - * //Same Concept as space_transform_apply and space_transform_invert, but no is normalized after conversion - * space_transform_apply_normal (&data, &no); - * space_transform_invert_normal(&data, &no); - * - */ -struct Object; - -typedef struct SpaceTransform { - float local2target[4][4]; - float target2local[4][4]; - -} SpaceTransform; - -void space_transform_from_matrixs(struct SpaceTransform *data, float local[4][4], float target[4][4]); -void space_transform_apply(const struct SpaceTransform *data, float co[3]); -void space_transform_invert(const struct SpaceTransform *data, float co[3]); - -#define SPACE_TRANSFORM_SETUP(data, local, target) space_transform_from_matrixs(data, (local)->obmat, (target)->obmat) - /* Shrinkwrap stuff */ #include "BKE_bvhutils.h" @@ -100,6 +54,7 @@ struct MDeformVert; struct ShrinkwrapModifierData; struct MDeformVert; struct BVHTree; +struct SpaceTransform; typedef struct ShrinkwrapCalcData { @@ -115,7 +70,7 @@ typedef struct ShrinkwrapCalcData { int vgroup; //Vertex group num struct DerivedMesh *target; //mesh we are shrinking to - SpaceTransform local2target; //transform to move between local and target space + struct SpaceTransform local2target; //transform to move between local and target space float keepDist; //Distance to keep above target surface (units are in local space) @@ -136,7 +91,7 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object */ bool BKE_shrinkwrap_project_normal( char options, const float vert[3], const float dir[3], - const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, + const struct SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata); /* diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index 4f77e4f5a23..1e79eaa8431 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -85,6 +85,7 @@ void txt_delete_char (struct Text *text); void txt_delete_word (struct Text *text); void txt_delete_selected (struct Text *text); void txt_sel_all (struct Text *text); +void txt_sel_clear (struct Text *text); void txt_sel_line (struct Text *text); char *txt_sel_to_buf (struct Text *text); void txt_insert_buf (struct Text *text, const char *in_buffer); diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h index 598817298b8..b351bc6fe3e 100644 --- a/source/blender/blenkernel/BKE_unit.h +++ b/source/blender/blenkernel/BKE_unit.h @@ -37,7 +37,7 @@ extern "C" { size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad); /* replace units with values, used before python button evaluation */ -int bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type); +bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type); /* make string keyboard-friendly: 10µm --> 10um */ void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int system, int type); @@ -49,7 +49,7 @@ double bUnit_ClosestScalar(double value, int system, int type); double bUnit_BaseScalar(int system, int type); /* return true is the unit system exists */ -int bUnit_IsValid(int system, int type); +bool bUnit_IsValid(int system, int type); /* loop over scales, coudl add names later */ //double bUnit_Iter(void **unit, char **name, int system, int type); diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index 6cda0a1bc33..623fb50b62c 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -119,7 +119,7 @@ static void _ehash_insert(EHash *eh, EHEntry *entry) eh->buckets[hash] = entry; eh->numEntries++; - if (eh->numEntries > (numBuckets * 3)) { + if (UNLIKELY(eh->numEntries > (numBuckets * 3))) { EHEntry **oldBuckets = eh->buckets; eh->curSize = kHashSizes[++eh->curSizeIdx]; @@ -1274,7 +1274,7 @@ CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGV CCGFace *f = NULL, *fNew; int j, k, topologyChanged = 0; - if (numVerts > ss->lenTempArrays) { + if (UNLIKELY(numVerts > ss->lenTempArrays)) { ss->lenTempArrays = (numVerts < ss->lenTempArrays * 2) ? ss->lenTempArrays * 2 : numVerts; ss->tempVerts = MEM_reallocN(ss->tempVerts, sizeof(*ss->tempVerts) * ss->lenTempArrays); ss->tempEdges = MEM_reallocN(ss->tempEdges, sizeof(*ss->tempEdges) * ss->lenTempArrays); diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index a70238da34e..52ded77b117 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -37,12 +37,14 @@ #include "DNA_cloth_types.h" #include "DNA_key_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BLI_blenlib.h" +#include "BLI_bitmap.h" #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_linklist.h" @@ -500,11 +502,36 @@ void DM_update_materials(DerivedMesh *dm, Object *ob) dm->mat = MEM_callocN(totmat * sizeof(*dm->mat), "DerivedMesh.mat"); - for (i = 1; i < totmat; i++) { - dm->mat[i] = give_current_material(ob, i); + /* we leave last material as empty - rationale here is being able to index + * the materials by using the mf->mat_nr directly and leaving the last + * material as NULL in case no materials exist on mesh, so indexing will not fail */ + for (i = 0; i < totmat - 1; i++) { + dm->mat[i] = give_current_material(ob, i + 1); } } +MTFace *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr) +{ + MTFace *tf_base; + + BLI_assert(mat_nr < dm->totmat); + + if (dm->mat[mat_nr] && dm->mat[mat_nr]->texpaintslot && + dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname) + { + tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, + dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname); + /* This can fail if we have changed the name in the UV layer list and have assigned the old name in the material + * texture slot.*/ + if (!tf_base) + tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE); + } + else { + tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE); + } + + return tf_base; +} void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask) { @@ -1107,7 +1134,7 @@ static void weightpaint_color(unsigned char r_col[4], DMWeightColorInfo *dm_wcin static void calc_weightpaint_vert_color( unsigned char r_col[4], - MDeformVert *dv, + const MDeformVert *dv, DMWeightColorInfo *dm_wcinfo, const int defbase_tot, const int defbase_act, const bool *defbase_sel, const int defbase_sel_tot, @@ -1122,7 +1149,7 @@ static void calc_weightpaint_vert_color( bool was_a_nonzero = false; unsigned int i; - MDeformWeight *dw = dv->dw; + const MDeformWeight *dw = dv->dw; for (i = dv->totweight; i != 0; i--, dw++) { /* in multipaint, get the average if auto normalize is inactive * get the sum if it is active */ @@ -1995,9 +2022,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D previewmd = modifiers_getLastPreview(scene, md, required_mode); /* even if the modifier doesn't need the data, to make a preview it may */ if (previewmd) { - if (do_mod_wmcol) { - previewmask = CD_MASK_MDEFORMVERT; - } + previewmask = CD_MASK_MDEFORMVERT; } } @@ -2473,6 +2498,28 @@ DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em) return getEditDerivedBMesh(em, obedit, NULL); } +/***/ + +/* get derived mesh from an object, using editbmesh if available. */ +DerivedMesh *object_get_derived_final(Object *ob, const bool for_render) +{ + Mesh *me = ob->data; + BMEditMesh *em = me->edit_btmesh; + + if (for_render) { + /* TODO(sergey): use proper derived render here in the future. */ + return ob->derivedFinal; + } + + if (em) { + DerivedMesh *dm = em->derivedFinal; + return dm; + } + + return ob->derivedFinal; +} + + /* UNUSED */ #if 0 @@ -2533,6 +2580,46 @@ DMCoNo *mesh_get_mapped_verts_nors(Scene *scene, Object *ob) #endif +/* same as above but for vert coords */ +typedef struct { + float (*vertexcos)[3]; + BLI_bitmap *vertex_visit; +} MappedUserData; + +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; + + if (BLI_BITMAP_TEST(mappedData->vertex_visit, index) == 0) { + /* 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_ENABLE(mappedData->vertex_visit, index); + } +} + +void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int totcos) +{ + float (*vertexcos)[3]; + + if (dm->foreachMappedVert) { + MappedUserData userData; + memset(r_cos, 0, sizeof(r_cos) * totcos); + userData.vertexcos = r_cos; + userData.vertex_visit = BLI_BITMAP_NEW(totcos, "vertexcos flags"); + dm->foreachMappedVert(dm, make_vertexcos__mapFunc, &userData, DM_FOREACH_NOP); + MEM_freeN(userData.vertex_visit); + } + else { + int i; + for (i = 0; i < totcos; i++) { + dm->getVertCo(dm, i, vertexcos[i]); + } + } +} + /* ******************* GLSL ******************** */ typedef struct { @@ -3090,7 +3177,7 @@ static void navmesh_drawColored(DerivedMesh *dm) static void navmesh_DM_drawFacesTex(DerivedMesh *dm, DMSetDrawOptionsTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag UNUSED(flag)) { (void) setDrawOptions; (void) compareDrawOptions; diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 8f1382dacc3..c6dcca576fb 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -315,7 +315,7 @@ bActionGroup *action_groups_add_new(bAction *act, const char name[]) void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve) { /* sanity checks */ - if (ELEM3(NULL, act, agrp, fcurve)) + if (ELEM(NULL, act, agrp, fcurve)) return; /* if no channels anywhere, just add to two lists at the same time */ @@ -417,7 +417,7 @@ void action_groups_remove_channel(bAction *act, FCurve *fcu) bActionGroup *BKE_action_group_find_name(bAction *act, const char name[]) { /* sanity checks */ - if (ELEM3(NULL, act, act->groups.first, name) || (name[0] == 0)) + if (ELEM(NULL, act, act->groups.first, name) || (name[0] == 0)) return NULL; /* do string comparisons */ @@ -526,7 +526,7 @@ bPoseChannel *BKE_pose_channel_active(Object *ob) bArmature *arm = (ob) ? ob->data : NULL; bPoseChannel *pchan; - if (ELEM3(NULL, ob, ob->pose, arm)) { + if (ELEM(NULL, ob, ob->pose, arm)) { return NULL; } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 995b2ac5321..5ee82bb5842 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -405,7 +405,7 @@ void action_move_fcurves_by_basepath(bAction *srcAct, bAction *dstAct, const cha FCurve *fcu, *fcn = NULL; /* sanity checks */ - if (ELEM3(NULL, srcAct, dstAct, basepath)) { + if (ELEM(NULL, srcAct, dstAct, basepath)) { if (G.debug & G_DEBUG) { printf("ERROR: action_partition_fcurves_by_basepath(%p, %p, %p) has insufficient info to work with\n", (void *)srcAct, (void *)dstAct, (void *)basepath); @@ -1062,7 +1062,7 @@ KS_Path *BKE_keyingset_find_path(KeyingSet *ks, ID *id, const char group_name[], KS_Path *ksp; /* sanity checks */ - if (ELEM3(NULL, ks, rna_path, id)) + if (ELEM(NULL, ks, rna_path, id)) return NULL; /* loop over paths in the current KeyingSet, finding the first one where all settings match @@ -2338,6 +2338,17 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData /* 3. free temporary evaluation data that's not used elsewhere */ BLI_freelistN(&estrips); + + /* Tag ID as updated so render engines will recognize changes in data + * which is animated but doesn't have actions. + */ + if (ptr->id.data != NULL) { + ID *id = ptr->id.data; + if (!(id->flag & LIB_ANIM_NO_RECALC)) { + id->flag |= LIB_ID_RECALC; + DAG_id_type_tag(G.main, GS(id->name)); + } + } } /* NLA Evaluation function (mostly for use through do_animdata) @@ -2392,7 +2403,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) /* Overview of how this system works: * 1) Depsgraph sorts data as necessary, so that data is in an order that means - * that all dependencies are resolved before dependants. + * that all dependencies are resolved before dependents. * 2) All normal animation is evaluated, so that drivers have some basis values to * work with * a. NLA stacks are done first, as the Active Actions act as 'tweaking' tracks diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 95f8426872d..16b5574709e 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -574,7 +574,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB if (do_scale) { /* correct for scaling when this matrix is used in scaled space */ - mul_serie_m4(result_array[a].mat, iscalemat, result_array[a].mat, scalemat, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(result_array[a].mat, iscalemat, result_array[a].mat, scalemat); } } } @@ -622,8 +622,7 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info invert_m4_m4(tmat, b_bone_rest[a].mat); - mul_serie_m4(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat, - NULL, NULL, NULL); + mul_m4_series(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat); if (use_quaternion) mat4_to_dquat(&b_bone_dual_quats[a], bone->arm_mat, b_bone_mats[a + 1].mat); @@ -1042,7 +1041,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float if (!use_quaternion) /* quaternion already is scale corrected */ mul_m3_fl(smat, armature_weight / contrib); - mul_serie_m3(defMats[i], tmpmat, pre, smat, post, NULL, NULL, NULL, NULL); + mul_m3_series(defMats[i], post, smat, pre, tmpmat); } } @@ -1881,7 +1880,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos */ /* only happens on reload file, but violates depsgraph still... fix! */ - if (ELEM3(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { + if (ELEM(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]*/ diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 9be9db77d39..fff8265a158 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -170,7 +170,7 @@ static void clear_global(void) static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src) { strcpy(path_dst, path_src); - BLI_clean(path_dst); + BLI_path_native_slash(path_dst); return !STREQ(path_dst, path_src); } @@ -182,7 +182,7 @@ static void clean_paths(Main *main) BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL); for (scene = main->scene.first; scene; scene = scene->id.next) { - BLI_clean(scene->r.pic); + BLI_path_native_slash(scene->r.pic); } } @@ -479,7 +479,9 @@ 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 update_defaults) +bool BKE_read_file_from_memory( + bContext *C, const void *filebuf, int filelength, + ReportList *reports, bool update_defaults) { BlendFileData *bfd; @@ -496,7 +498,9 @@ int BKE_read_file_from_memory(bContext *C, const void *filebuf, int filelength, } /* memfile is the undo buffer */ -int BKE_read_file_from_memfile(bContext *C, MemFile *memfile, ReportList *reports) +bool BKE_read_file_from_memfile( + bContext *C, MemFile *memfile, + ReportList *reports) { BlendFileData *bfd; diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index dc2d0924bba..3cd26dacebd 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -107,7 +107,7 @@ typedef struct BPathRemap_Data { int count_failed; } BPathRemap_Data; -static bool makeFilesRelative_visit_cb(void *userdata, char *path_dst, const char *path_src) +static bool bpath_relative_convert_visit_cb(void *userdata, char *path_dst, const char *path_src) { BPathRemap_Data *data = (BPathRemap_Data *)userdata; @@ -133,6 +133,7 @@ static bool makeFilesRelative_visit_cb(void *userdata, char *path_dst, const cha void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *reports) { BPathRemap_Data data = {NULL}; + const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY; if (basedir[0] == '\0') { printf("%s: basedir='', this is a bug\n", __func__); @@ -142,14 +143,14 @@ void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *re data.basedir = basedir; data.reports = reports; - BKE_bpath_traverse_main(bmain, makeFilesRelative_visit_cb, 0, (void *)&data); + BKE_bpath_traverse_main(bmain, bpath_relative_convert_visit_cb, flag, (void *)&data); BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO, "Total files %d | Changed %d | Failed %d", data.count_tot, data.count_changed, data.count_failed); } -static bool makeFilesAbsolute_visit_cb(void *userdata, char *path_dst, const char *path_src) +static bool bpath_absolute_convert_visit_cb(void *userdata, char *path_dst, const char *path_src) { BPathRemap_Data *data = (BPathRemap_Data *)userdata; @@ -176,6 +177,7 @@ static bool makeFilesAbsolute_visit_cb(void *userdata, char *path_dst, const cha void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *reports) { BPathRemap_Data data = {NULL}; + const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY; if (basedir[0] == '\0') { printf("%s: basedir='', this is a bug\n", __func__); @@ -185,7 +187,7 @@ void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *re data.basedir = basedir; data.reports = reports; - BKE_bpath_traverse_main(bmain, makeFilesAbsolute_visit_cb, 0, (void *)&data); + BKE_bpath_traverse_main(bmain, bpath_absolute_convert_visit_cb, flag, (void *)&data); BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO, "Total files %d | Changed %d | Failed %d", @@ -422,7 +424,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int Image *ima; 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)) { + if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) { if (!ima->packedfile) { BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 967e89e0dd1..76b0cad337f 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -83,6 +83,7 @@ static void brush_defaults(Brush *brush) brush->plane_trim = 0.5f; brush->clone.alpha = 0.5f; brush->normal_weight = 0.0f; + brush->fill_threshold = 0.2f; brush->flag |= BRUSH_ALPHA_PRESSURE; /* BRUSH PAINT TOOL SETTINGS */ @@ -90,6 +91,8 @@ static void brush_defaults(Brush *brush) brush->rgb[1] = 1.0f; brush->rgb[2] = 1.0f; + zero_v3(brush->secondary_rgb); + /* BRUSH STROKE SETTINGS */ brush->flag |= (BRUSH_SPACE | BRUSH_SPACE_ATTEN); brush->spacing = 10; /* how far each brush dot should be spaced as a percentage of brush diameter */ @@ -161,6 +164,9 @@ Brush *BKE_brush_copy(Brush *brush) if (brush->mask_mtex.tex) id_us_plus((ID *)brush->mask_mtex.tex); + if (brush->paint_curve) + id_us_plus((ID *)brush->paint_curve); + if (brush->icon_imbuf) brushn->icon_imbuf = IMB_dupImBuf(brush->icon_imbuf); @@ -180,11 +186,9 @@ Brush *BKE_brush_copy(Brush *brush) /* not brush itself */ void BKE_brush_free(Brush *brush) { - if (brush->mtex.tex) - brush->mtex.tex->id.us--; - - if (brush->mask_mtex.tex) - brush->mask_mtex.tex->id.us--; + id_us_min((ID *)brush->mtex.tex); + id_us_min((ID *)brush->mask_mtex.tex); + id_us_min((ID *)brush->paint_curve); if (brush->icon_imbuf) IMB_freeImBuf(brush->icon_imbuf); @@ -192,6 +196,9 @@ void BKE_brush_free(Brush *brush) BKE_previewimg_free(&(brush->preview)); curvemapping_free(brush->curve); + + if (brush->gradient) + MEM_freeN(brush->gradient); } static void extern_local_brush(Brush *brush) @@ -199,6 +206,7 @@ static void extern_local_brush(Brush *brush) id_lib_extern((ID *)brush->mtex.tex); id_lib_extern((ID *)brush->mask_mtex.tex); id_lib_extern((ID *)brush->clone.image); + id_lib_extern((ID *)brush->paint_curve); } void BKE_brush_make_local(Brush *brush) @@ -742,10 +750,23 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool); } + CLAMP(intensity, 0.0f, 1.0f); + + switch (br->mask_pressure) { + case BRUSH_MASK_PRESSURE_CUTOFF: + intensity = ((1.0f - intensity) < ups->size_pressure_value) ? 1.0f : 0.0f; + break; + case BRUSH_MASK_PRESSURE_RAMP: + intensity = ups->size_pressure_value + intensity * (1.0f - ups->size_pressure_value); + break; + default: + break; + } + return intensity; } -/* Unified Size and Strength */ +/* Unified Size / Strength / Color */ /* XXX: be careful about setting size and unprojected radius * because they depend on one another @@ -760,6 +781,29 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br, * In any case, a better solution is needed to prevent * inconsistency. */ + +float *BKE_brush_color_get(const struct Scene *scene, struct Brush *brush) +{ + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; + return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->rgb : brush->rgb; +} + +float *BKE_brush_secondary_color_get(const struct Scene *scene, struct Brush *brush) +{ + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; + return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->secondary_rgb : brush->secondary_rgb; +} + +void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float color[3]) +{ + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; + + if (ups->flag & UNIFIED_PAINT_COLOR) + copy_v3_v3(ups->rgb, color); + else + copy_v3_v3(brush->rgb, color); +} + void BKE_brush_size_set(Scene *scene, Brush *brush, int size) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; @@ -886,39 +930,27 @@ void BKE_brush_scale_size(int *r_brush_size, void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], float jitterpos[2]) { - int use_jitter = (brush->flag & BRUSH_ABSOLUTE_JITTER) ? - (brush->jitter_absolute != 0) : (brush->jitter != 0); + float rand_pos[2]; + float spread; + int diameter; - /* jitter-ed brush gives weird and unpredictable result for this - * kinds of stroke, so manually disable jitter usage (sergey) */ - use_jitter &= (brush->flag & (BRUSH_DRAG_DOT | BRUSH_ANCHORED)) == 0; + do { + rand_pos[0] = BLI_rng_get_float(brush_rng) - 0.5f; + rand_pos[1] = BLI_rng_get_float(brush_rng) - 0.5f; + } while (len_squared_v2(rand_pos) > (0.5f * 0.5f)); - if (use_jitter) { - float rand_pos[2]; - float spread; - int diameter; - do { - rand_pos[0] = BLI_rng_get_float(brush_rng) - 0.5f; - rand_pos[1] = BLI_rng_get_float(brush_rng) - 0.5f; - } while (len_squared_v2(rand_pos) > (0.5f * 0.5f)); - - - if (brush->flag & BRUSH_ABSOLUTE_JITTER) { - diameter = 2 * brush->jitter_absolute; - spread = 1.0; - } - else { - diameter = 2 * BKE_brush_size_get(scene, brush); - spread = brush->jitter; - } - /* find random position within a circle of diameter 1 */ - jitterpos[0] = pos[0] + 2 * rand_pos[0] * diameter * spread; - jitterpos[1] = pos[1] + 2 * rand_pos[1] * diameter * spread; + if (brush->flag & BRUSH_ABSOLUTE_JITTER) { + diameter = 2 * brush->jitter_absolute; + spread = 1.0; } else { - copy_v2_v2(jitterpos, pos); + diameter = 2 * BKE_brush_size_get(scene, brush); + spread = brush->jitter; } + /* find random position within a circle of diameter 1 */ + jitterpos[0] = pos[0] + 2 * rand_pos[0] * diameter * spread; + jitterpos[1] = pos[1] + 2 * rand_pos[1] * diameter * spread; } void BKE_brush_randomize_texture_coordinates(UnifiedPaintSettings *ups, bool mask) diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index f85a91b66cb..4ad577a7bda 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -77,288 +77,6 @@ static float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, con return FLT_MAX; } - -/* - * Function adapted from David Eberly's distance tools (LGPL) - * http://www.geometrictools.com/LibFoundation/Distance/Distance.html - */ -float nearest_point_in_tri_surface_squared( - const float v0[3], const float v1[3], const float v2[3], - const float p[3], int *v, int *e, float nearest[3]) -{ - float diff[3]; - float e0[3]; - float e1[3]; - float A00; - float A01; - float A11; - float B0; - float B1; - float C; - float Det; - float S; - float T; - float sqrDist; - int lv = -1, le = -1; - - sub_v3_v3v3(diff, v0, p); - sub_v3_v3v3(e0, v1, v0); - sub_v3_v3v3(e1, v2, v0); - - A00 = dot_v3v3(e0, e0); - A01 = dot_v3v3(e0, e1); - A11 = dot_v3v3(e1, e1); - B0 = dot_v3v3(diff, e0); - B1 = dot_v3v3(diff, e1); - C = dot_v3v3(diff, diff); - Det = fabsf(A00 * A11 - A01 * A01); - S = A01 * B1 - A11 * B0; - T = A01 * B0 - A00 * B1; - - if (S + T <= Det) { - if (S < 0.0f) { - if (T < 0.0f) { /* Region 4 */ - if (B0 < 0.0f) { - T = 0.0f; - if (-B0 >= A00) { - S = 1.0f; - sqrDist = A00 + 2.0f * B0 + C; - lv = 1; - } - else { - if (fabsf(A00) > FLT_EPSILON) - S = -B0 / A00; - else - S = 0.0f; - sqrDist = B0 * S + C; - le = 0; - } - } - else { - S = 0.0f; - if (B1 >= 0.0f) { - T = 0.0f; - sqrDist = C; - lv = 0; - } - else if (-B1 >= A11) { - T = 1.0f; - sqrDist = A11 + 2.0f * B1 + C; - lv = 2; - } - else { - if (fabsf(A11) > FLT_EPSILON) - T = -B1 / A11; - else - T = 0.0f; - sqrDist = B1 * T + C; - le = 1; - } - } - } - else { /* Region 3 */ - S = 0.0f; - if (B1 >= 0.0f) { - T = 0.0f; - sqrDist = C; - lv = 0; - } - else if (-B1 >= A11) { - T = 1.0f; - sqrDist = A11 + 2.0f * B1 + C; - lv = 2; - } - else { - if (fabsf(A11) > FLT_EPSILON) - T = -B1 / A11; - else - T = 0.0; - sqrDist = B1 * T + C; - le = 1; - } - } - } - else if (T < 0.0f) { /* Region 5 */ - T = 0.0f; - if (B0 >= 0.0f) { - S = 0.0f; - sqrDist = C; - lv = 0; - } - else if (-B0 >= A00) { - S = 1.0f; - sqrDist = A00 + 2.0f * B0 + C; - lv = 1; - } - else { - if (fabsf(A00) > FLT_EPSILON) - S = -B0 / A00; - else - S = 0.0f; - sqrDist = B0 * S + C; - le = 0; - } - } - else { /* Region 0 */ - /* Minimum at interior lv */ - float invDet; - if (fabsf(Det) > FLT_EPSILON) - invDet = 1.0f / Det; - else - invDet = 0.0f; - S *= invDet; - T *= invDet; - sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) + - T * (A01 * S + A11 * T + 2.0f * B1) + C; - } - } - else { - float tmp0, tmp1, numer, denom; - - if (S < 0.0f) { /* Region 2 */ - tmp0 = A01 + B0; - tmp1 = A11 + B1; - if (tmp1 > tmp0) { - numer = tmp1 - tmp0; - denom = A00 - 2.0f * A01 + A11; - if (numer >= denom) { - S = 1.0f; - T = 0.0f; - sqrDist = A00 + 2.0f * B0 + C; - lv = 1; - } - else { - if (fabsf(denom) > FLT_EPSILON) - S = numer / denom; - else - S = 0.0f; - T = 1.0f - S; - sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) + - T * (A01 * S + A11 * T + 2.0f * B1) + C; - le = 2; - } - } - else { - S = 0.0f; - if (tmp1 <= 0.0f) { - T = 1.0f; - sqrDist = A11 + 2.0f * B1 + C; - lv = 2; - } - else if (B1 >= 0.0f) { - T = 0.0f; - sqrDist = C; - lv = 0; - } - else { - if (fabsf(A11) > FLT_EPSILON) - T = -B1 / A11; - else - T = 0.0f; - sqrDist = B1 * T + C; - le = 1; - } - } - } - else if (T < 0.0f) { /* Region 6 */ - tmp0 = A01 + B1; - tmp1 = A00 + B0; - if (tmp1 > tmp0) { - numer = tmp1 - tmp0; - denom = A00 - 2.0f * A01 + A11; - if (numer >= denom) { - T = 1.0f; - S = 0.0f; - sqrDist = A11 + 2.0f * B1 + C; - lv = 2; - } - else { - if (fabsf(denom) > FLT_EPSILON) - T = numer / denom; - else - T = 0.0f; - S = 1.0f - T; - sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) + - T * (A01 * S + A11 * T + 2.0f * B1) + C; - le = 2; - } - } - else { - T = 0.0f; - if (tmp1 <= 0.0f) { - S = 1.0f; - sqrDist = A00 + 2.0f * B0 + C; - lv = 1; - } - else if (B0 >= 0.0f) { - S = 0.0f; - sqrDist = C; - lv = 0; - } - else { - if (fabsf(A00) > FLT_EPSILON) - S = -B0 / A00; - else - S = 0.0f; - sqrDist = B0 * S + C; - le = 0; - } - } - } - else { /* Region 1 */ - numer = A11 + B1 - A01 - B0; - if (numer <= 0.0f) { - S = 0.0f; - T = 1.0f; - sqrDist = A11 + 2.0f * B1 + C; - lv = 2; - } - else { - denom = A00 - 2.0f * A01 + A11; - if (numer >= denom) { - S = 1.0f; - T = 0.0f; - sqrDist = A00 + 2.0f * B0 + C; - lv = 1; - } - else { - if (fabsf(denom) > FLT_EPSILON) - S = numer / denom; - else - S = 0.0f; - T = 1.0f - S; - sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) + - T * (A01 * S + A11 * T + 2.0f * B1) + C; - le = 2; - } - } - } - } - - /* Account for numerical round-off error */ - if (sqrDist < FLT_EPSILON) - sqrDist = 0.0f; - - { - float w[3], x[3], y[3], z[3]; - copy_v3_v3(w, v0); - copy_v3_v3(x, e0); - mul_v3_fl(x, S); - copy_v3_v3(y, e1); - mul_v3_fl(y, T); - add_v3_v3v3(z, w, x); - add_v3_v3v3(z, z, y); - //sub_v3_v3v3(d, p, z); - copy_v3_v3(nearest, z); - //d = p - ( v0 + S * e0 + T * e1 ); - } - *v = lv; - *e = le; - - return sqrDist; -} - - /* * BVH from meshes callbacks */ @@ -380,9 +98,10 @@ static void mesh_faces_nearest_point(void *userdata, int index, const float co[3 do { float nearest_tmp[3], dist_sq; - int vertex, edge; - - dist_sq = nearest_point_in_tri_surface_squared(t0, t1, t2, co, &vertex, &edge, nearest_tmp); + + closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2); + dist_sq = len_squared_v3v3(co, nearest_tmp); + if (dist_sq < nearest->dist_sq) { nearest->index = index; nearest->dist_sq = dist_sq; @@ -413,9 +132,10 @@ static void editmesh_faces_nearest_point(void *userdata, int index, const float { float nearest_tmp[3], dist_sq; - int vertex, edge; - dist_sq = nearest_point_in_tri_surface_squared(t0, t1, t2, co, &vertex, &edge, nearest_tmp); + closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2); + dist_sq = len_squared_v3v3(co, nearest_tmp); + if (dist_sq < nearest->dist_sq) { nearest->index = index; nearest->dist_sq = dist_sq; diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index b20ba40c0dd..6ce3abe7a32 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -201,7 +201,7 @@ void BKE_camera_params_init(CameraParams *params) /* fallback for non camera objects */ params->clipsta = 0.1f; - params->clipsta = 100.0f; + params->clipend = 100.0f; } void BKE_camera_params_from_object(CameraParams *params, Object *ob) @@ -473,7 +473,7 @@ 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_squared_to_plane_v3(co, data->plane_tx[i]); + float nd = dist_signed_squared_to_plane_v3(co, data->plane_tx[i]); if (nd < data->dist_vals_sq[i]) { data->dist_vals_sq[i] = nd; } diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index f39b4e20b70..08052127fbf 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -49,6 +49,7 @@ #include "BKE_editmesh.h" #include "BKE_curve.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -668,7 +669,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, DMSetDrawOptionsTex drawParams, DMSetDrawOptions drawParamsMapped, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag uvflag) { CDDerivedMesh *cddm = (CDDerivedMesh *) dm; MVert *mv = cddm->mvert; @@ -679,6 +680,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, MCol *mcol; int i, orig; int colType, startFace = 0; + bool use_tface = (uvflag & DM_DRAW_USE_ACTIVE_UV) != 0; /* double lookup */ const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); @@ -717,14 +719,35 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, cdDM_update_normals_from_pbvh(dm); if (GPU_buffer_legacy(dm)) { + int mat_nr_cache = -1; + MTFace *tf_base = DM_get_tessface_data_layer(dm, CD_MTFACE); + MTFace *tf_stencil_base = NULL; + MTFace *tf_stencil = NULL; + + if (uvflag & DM_DRAW_USE_TEXPAINT_UV) { + int stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE); + tf_stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil); + } + DEBUG_VBO("Using legacy code. cdDM_drawFacesTex_common\n"); for (i = 0; i < dm->numTessFaceData; i++, mf++) { MVert *mvert; DMDrawOption draw_option; unsigned char *cp = NULL; + if (uvflag & DM_DRAW_USE_TEXPAINT_UV) { + if (mf->mat_nr != mat_nr_cache) { + tf_base = DM_paint_uvlayer_active_get(dm, mf->mat_nr); + + mat_nr_cache = mf->mat_nr; + } + } + + tf = tf_base ? tf_base + i : NULL; + tf_stencil = tf_stencil_base ? tf_stencil_base + i : NULL; + if (drawParams) { - draw_option = drawParams(tf ? &tf[i] : NULL, (mcol != NULL), mf->mat_nr); + draw_option = drawParams(use_tface ? tf : NULL, (mcol != NULL), mf->mat_nr); } else { if (index_mf_to_mpoly) { @@ -777,21 +800,24 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, } glBegin(mf->v4 ? GL_QUADS : GL_TRIANGLES); - if (tf) glTexCoord2fv(tf[i].uv[0]); + if (tf) glTexCoord2fv(tf->uv[0]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf->uv[0]); if (cp) glColor3ub(cp[3], cp[2], cp[1]); mvert = &mv[mf->v1]; if (lnors) glNormal3sv((const GLshort *)lnors[0][0]); else if (mf->flag & ME_SMOOTH) glNormal3sv(mvert->no); glVertex3fv(mvert->co); - if (tf) glTexCoord2fv(tf[i].uv[1]); + if (tf) glTexCoord2fv(tf->uv[1]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf->uv[1]); if (cp) glColor3ub(cp[7], cp[6], cp[5]); mvert = &mv[mf->v2]; if (lnors) glNormal3sv((const GLshort *)lnors[0][1]); else if (mf->flag & ME_SMOOTH) glNormal3sv(mvert->no); glVertex3fv(mvert->co); - if (tf) glTexCoord2fv(tf[i].uv[2]); + if (tf) glTexCoord2fv(tf->uv[2]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf->uv[2]); if (cp) glColor3ub(cp[11], cp[10], cp[9]); mvert = &mv[mf->v3]; if (lnors) glNormal3sv((const GLshort *)lnors[0][2]); @@ -799,7 +825,8 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, glVertex3fv(mvert->co); if (mf->v4) { - if (tf) glTexCoord2fv(tf[i].uv[3]); + if (tf) glTexCoord2fv(tf->uv[3]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf->uv[3]); if (cp) glColor3ub(cp[15], cp[14], cp[13]); mvert = &mv[mf->v4]; if (lnors) glNormal3sv((const GLshort *)lnors[0][3]); @@ -818,7 +845,10 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */ GPU_vertex_setup(dm); GPU_normal_setup(dm); - GPU_uv_setup(dm); + if (uvflag & DM_DRAW_USE_TEXPAINT_UV) + GPU_texpaint_uv_setup(dm); + else + GPU_uv_setup(dm); if (mcol) { GPU_color_setup(dm, colType); } @@ -838,7 +868,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, next_actualFace = dm->drawObject->triangle_to_mface[i + 1]; if (drawParams) { - draw_option = drawParams(tf ? &tf[actualFace] : NULL, (mcol != NULL), mf[actualFace].mat_nr); + draw_option = drawParams(use_tface && tf ? &tf[actualFace] : NULL, (mcol != NULL), mf[actualFace].mat_nr); } else { if (index_mf_to_mpoly) { @@ -894,9 +924,9 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, static void cdDM_drawFacesTex(DerivedMesh *dm, DMSetDrawOptionsTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag uvflag) { - cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData); + cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, uvflag); } static void cdDM_drawMappedFaces(DerivedMesh *dm, @@ -1122,9 +1152,9 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, static void cdDM_drawMappedFacesTex(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag flag) { - cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData); + cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag); } static void cddm_draw_attrib_vertex(DMVertexAttribs *attribs, MVert *mvert, int a, int index, int vert, @@ -2541,25 +2571,200 @@ void CDDM_calc_normals_tessface(DerivedMesh *dm) #if 1 /** + * Poly compare with vtargetmap + * Function used by #CDDM_merge_verts. + * The function compares poly_source after applying vtargetmap, with poly_target. + * The two polys are identical if they share the same vertices in the same order, or in reverse order, + * but starting position loopstart may be different. + * The function is called with direct_reverse=1 for same order (i.e. same normal), + * and may be called again with direct_reverse=-1 for reverse order. + * \return 1 if polys are identical, 0 if polys are different. + */ +static int cddm_poly_compare(MLoop *mloop_array, MPoly *mpoly_source, MPoly *mpoly_target, const int *vtargetmap, const int direct_reverse) +{ + int vert_source, first_vert_source, vert_target; + int i_loop_source; + int i_loop_target, i_loop_target_start, i_loop_target_offset, i_loop_target_adjusted; + bool compare_completed = false; + bool same_loops = false; + + MLoop *mloop_source, *mloop_target; + + BLI_assert(direct_reverse == 1 || direct_reverse == -1); + + i_loop_source = 0; + mloop_source = mloop_array + mpoly_source->loopstart; + vert_source = mloop_source->v; + + if (vtargetmap[vert_source] != -1) { + vert_source = vtargetmap[vert_source]; + } + else { + /* All source loop vertices should be mapped */ + BLI_assert(false); + } + + /* Find same vertex within mpoly_target's loops */ + mloop_target = mloop_array + mpoly_target->loopstart; + for (i_loop_target = 0; i_loop_target < mpoly_target->totloop; i_loop_target++, mloop_target++) { + if (mloop_target->v == vert_source) { + break; + } + } + + /* If same vertex not found, then polys cannot be equal */ + if (i_loop_target >= mpoly_target->totloop) { + return false; + } + + /* Now mloop_source and m_loop_target have one identical vertex */ + /* mloop_source is at position 0, while m_loop_target has advanced to find identical vertex */ + /* Go around the loop and check that all vertices match in same order */ + /* Skipping source loops when consecutive source vertices are mapped to same target vertex */ + + i_loop_target_start = i_loop_target; + i_loop_target_offset = 0; + first_vert_source = vert_source; + + compare_completed = false; + same_loops = false; + + while (!compare_completed) { + + vert_target = mloop_target->v; + + /* First advance i_loop_source, until it points to different vertex, after mapping applied */ + do { + i_loop_source++; + + if (i_loop_source == mpoly_source->totloop) { + /* End of loops for source, must match end of loop for target. */ + if (i_loop_target_offset == mpoly_target->totloop - 1) { + compare_completed = true; + same_loops = true; + break; /* Polys are identical */ + } + else { + compare_completed = true; + same_loops = false; + break; /* Polys are different */ + } + } + + mloop_source++; + vert_source = mloop_source->v; + + if (vtargetmap[vert_source] != -1) { + vert_source = vtargetmap[vert_source]; + } + else { + /* All source loop vertices should be mapped */ + BLI_assert(false); + } + + } while (vert_source == vert_target); + + if (compare_completed) { + break; + } + + /* Now advance i_loop_target as well */ + i_loop_target_offset++; + + if (i_loop_target_offset == mpoly_target->totloop) { + /* End of loops for target only, that means no match */ + /* except if all remaining source vertices are mapped to first target */ + for (; i_loop_source < mpoly_source->totloop; i_loop_source++, mloop_source++) { + vert_source = vtargetmap[mloop_source->v]; + if (vert_source != first_vert_source) { + compare_completed = true; + same_loops = false; + break; + } + } + if (!compare_completed) { + same_loops = true; + } + break; + } + + /* Adjust i_loop_target for cycling around and for direct/reverse order defined by delta = +1 or -1 */ + i_loop_target_adjusted = (i_loop_target_start + direct_reverse * i_loop_target_offset) % mpoly_target->totloop; + if (i_loop_target_adjusted < 0) { + i_loop_target_adjusted += mpoly_target->totloop; + } + mloop_target = mloop_array + mpoly_target->loopstart + i_loop_target_adjusted; + vert_target = mloop_target->v; + + if (vert_target != vert_source) { + same_loops = false; /* Polys are different */ + break; + } + } + return same_loops; +} + +/* Utility stuff for using GHash with polys */ + +typedef struct PolyKey { + int poly_index; /* index of the MPoly within the derived mesh */ + int totloops; /* number of loops in the poly */ + unsigned int hash_sum; /* Sum of all vertices indices */ + unsigned int hash_xor; /* Xor of all vertices indices */ +} PolyKey; + + +static unsigned int poly_gset_hash_fn(const void *key) +{ + const PolyKey *pk = key; + return pk->hash_sum; +} + +static int poly_gset_compare_fn(const void *k1, const void *k2) +{ + const PolyKey *pk1 = k1; + const PolyKey *pk2 = k2; + if ((pk1->hash_sum == pk2->hash_sum) && + (pk1->hash_xor == pk2->hash_xor) && + (pk1->totloops == pk2->totloops)) + { + /* Equality - note that this does not mean equality of polys */ + return 0; + } + else { + return 1; + } +} + +/** * Merge Verts * + * This frees dm, and returns a new one. + * * \param vtargetmap The table that maps vertices to target vertices. a value of -1 * indicates a vertex is a target, and is to be kept. * This array is aligned with 'dm->numVertData' * - * \param tot_vtargetmap The number of non '-1' values in vtargetmap. - * (not the size ) - * - * this frees dm, and returns a new one. + * \param tot_vtargetmap The number of non '-1' values in vtargetmap. (not the size) * - * note, CDDM_recalc_tessellation has to run on the returned DM if you want to access tessfaces. + * \param merge_mode enum with two modes. + * - #CDDM_MERGE_VERTS_DUMP_IF_MAPPED + * When called by the Mirror Modifier, + * In this mode it skips any faces that have all vertices merged (to avoid creating pairs + * of faces sharing the same set of vertices) + * - #CDDM_MERGE_VERTS_DUMP_IF_EQUAL + * When called by the Array Modifier, + * In this mode, faces where all vertices are merged are double-checked, + * to see whether all target vertices actually make up a poly already. + * Indeed it could be that all of a poly's vertices are merged, + * but merged to vertices that do not make up a single poly, + * in which case the original poly should not be dumped. + * Actually this later behavior could apply to the Mirror Modifier as well, but the additional checks are + * costly and not necessary in the case of mirror, because each vertex is only merged to its own mirror. * - * Note: This function is currently only used by the Mirror modifier, so it - * skips any faces that have all vertices merged (to avoid creating pairs - * of faces sharing the same set of vertices). If used elsewhere, it may - * be necessary to make this functionality optional. + * \note #CDDM_recalc_tessellation has to run on the returned DM if you want to access tessfaces. */ -DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap) +DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode) { // #define USE_LOOPS CDDerivedMesh *cddm = (CDDerivedMesh *)dm; @@ -2600,7 +2805,10 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int EdgeHash *ehash = BLI_edgehash_new_ex(__func__, totedge); int i, j, c; - + + PolyKey *poly_keys; + GSet *poly_gset = NULL; + STACK_INIT(oldv, totvert_final); STACK_INIT(olde, totedge); STACK_INIT(oldl, totloop); @@ -2642,10 +2850,9 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int med = cddm->medge; c = 0; for (i = 0; i < totedge; i++, med++) { - - if (LIKELY(med->v1 != med->v2)) { - const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1; - const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2; + const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1; + const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2; + if (LIKELY(v1 != v2)) { void **eh_p = BLI_edgehash_lookup_p(ehash, v1, v2); if (eh_p) { @@ -2664,13 +2871,49 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int } } + if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_EQUAL) { + /* In this mode, we need to determine, whenever a poly' vertices are all mapped */ + /* if the targets already make up a poly, in which case the new poly is dropped */ + /* This poly equality check is rather complex. We use a BLI_ghash to speed it up with a first level check */ + PolyKey *mpgh; + poly_keys = MEM_mallocN(sizeof(PolyKey) * totpoly, __func__); + poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly); + /* Duplicates allowed because our compare function is not pure equality */ + BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES); + + mp = cddm->mpoly; + mpgh = poly_keys; + for (i = 0; i < totpoly; i++, mp++, mpgh++) { + mpgh->poly_index = i; + mpgh->totloops = mp->totloop; + ml = cddm->mloop + mp->loopstart; + mpgh->hash_sum = mpgh->hash_xor = 0; + for (j = 0; j < mp->totloop; j++, ml++) { + mpgh->hash_sum += ml->v; + mpgh->hash_xor ^= ml->v; + } + BLI_gset_insert(poly_gset, mpgh); + } + + if (cddm->pmap) { + MEM_freeN(cddm->pmap); + MEM_freeN(cddm->pmap_mem); + } + /* Can we optimise by reusing an old pmap ? How do we know an old pmap is stale ? */ + /* When called by MOD_array.c, the cddm has just been created, so it has no valid pmap. */ + BKE_mesh_vert_poly_map_create(&cddm->pmap, &cddm->pmap_mem, + cddm->mpoly, cddm->mloop, + totvert, totpoly, totloop); + } /* done preparing for fast poly compare */ + + mp = cddm->mpoly; for (i = 0; i < totpoly; i++, mp++) { MPoly *mp_new; ml = cddm->mloop + mp->loopstart; - /* skip faces with all vertices merged */ + /* check faces with all vertices merged */ { bool all_vertices_merged = true; @@ -2682,16 +2925,86 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int } if (UNLIKELY(all_vertices_merged)) { - continue; + if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_MAPPED) { + /* In this mode, all vertices merged is enough to dump face */ + continue; + } + else if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_EQUAL) { + /* Additional condition for face dump: target vertices must make up an identical face */ + /* The test has 2 steps: (1) first step is fast ghash lookup, but not failproof */ + /* (2) second step is thorough but more costly poly compare */ + int i_poly, v_target, v_prev; + bool found = false; + PolyKey pkey; + + /* Use poly_gset for fast (although not 100% certain) identification of same poly */ + /* First, make up a poly_summary structure */ + ml = cddm->mloop + mp->loopstart; + pkey.hash_sum = pkey.hash_xor = 0; + pkey.totloops = 0; + v_prev = vtargetmap[(ml + mp->totloop -1)->v]; /* since it loops around, the prev of first is the last */ + for (j = 0; j < mp->totloop; j++, ml++) { + v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */ + if (v_target == v_prev) { + /* consecutive vertices in loop map to the same target: discard */ + /* but what about last to first ? */ + continue; + } + pkey.hash_sum += v_target; + pkey.hash_xor ^= v_target; + pkey.totloops++; + v_prev = v_target; + } + if (BLI_gset_haskey(poly_gset, &pkey)) { + + /* There might be a poly that matches this one. + * We could just leave it there and say there is, and do a "continue". + * ... but we are checking whether there is an exact poly match. + * It's not so costly in terms of CPU since it's very rare, just a lot of complex code. + */ + + /* Consider current loop again */ + ml = cddm->mloop + mp->loopstart; + /* Consider the target of the loop's first vert */ + v_target = vtargetmap[ml->v]; + /* Now see if v_target belongs to a poly that shares all vertices with source poly, + * in same order, or reverse order */ + + for (i_poly = 0; i_poly < cddm->pmap[v_target].count; i_poly++) { + MPoly *target_poly = cddm->mpoly + *(cddm->pmap[v_target].indices + i_poly); + + if (cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, +1) || + cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, -1)) + { + found = true; + break; + } + } + if (found) { + /* Current poly's vertices are mapped to a poly that is strictly identical */ + /* Current poly is dumped */ + continue; + } + } + } } } + + /* Here either the poly's vertices were not all merged + * or they were all merged, but targets do not make up an identical poly, + * the poly is retained. + */ ml = cddm->mloop + mp->loopstart; c = 0; for (j = 0; j < mp->totloop; j++, ml++) { + unsigned int v1, v2; + med = cddm->medge + ml->e; - if (LIKELY(med->v1 != med->v2)) { + v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1; + v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2; + if (LIKELY(v1 != v2)) { #ifdef USE_LOOPS newl[j + mp->loopstart] = STACK_SIZE(mloop); #endif @@ -2711,6 +3024,14 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int mp_new->loopstart = STACK_SIZE(mloop) - c; STACK_PUSH(oldp, i); + } /* end of the loop that tests polys */ + + + if (poly_gset) { + // printf("hash quality %.6f\n", BLI_gset_calc_quality(poly_gset)); + + BLI_gset_free(poly_gset, NULL); + MEM_freeN(poly_keys); } /*create new cddm*/ diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index b27655c8c19..d80529ee780 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -3375,7 +3375,7 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra unit_m4(ct->matrix); if (target != NULL) { - space_transform_from_matrixs(&transform, cob->matrix, ct->tar->obmat); + BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->obmat); switch (scon->shrinkType) { case MOD_SHRINKWRAP_NEAREST_SURFACE: @@ -3397,7 +3397,7 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra break; } - space_transform_apply(&transform, co); + BLI_space_transform_apply(&transform, co); BLI_bvhtree_find_nearest(treeData.tree, co, &nearest, treeData.nearest_callback, &treeData); @@ -3405,7 +3405,7 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra if (dist != 0.0f) { interp_v3_v3v3(co, co, nearest.co, (dist - scon->dist) / dist); /* linear interpolation */ } - space_transform_invert(&transform, co); + BLI_space_transform_invert(&transform, co); break; } case MOD_SHRINKWRAP_PROJECT: @@ -3909,7 +3909,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, imat); invert_m4(imat); - mul_serie_m4(cob->matrix, obmat, mat, imat, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(cob->matrix, obmat, mat, imat); translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); } else { @@ -3943,19 +3943,31 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase if (len > FLT_EPSILON) { CameraParams params; + int width, height; float pos[2], rmat[4][4]; + BKE_movieclip_get_size(clip, NULL, &width, &height); + marker = BKE_tracking_marker_get(track, framenr); add_v2_v2v2(pos, marker->pos, track->offset); + if (data->flag & FOLLOWTRACK_USE_UNDISTORTION) { + /* Undistortion need to happen in pixel space. */ + pos[0] *= width; + pos[1] *= height; + + BKE_tracking_undistort_v2(tracking, pos, pos); + + /* Normalize pixel coordinates back. */ + pos[0] /= width; + pos[1] /= height; + } + /* aspect correction */ if (data->frame_method != FOLLOWTRACK_FRAME_STRETCH) { - int width, height; float w_src, h_src, w_dst, h_dst, asp_src, asp_dst; - BKE_movieclip_get_size(clip, NULL, &width, &height); - /* apply clip display aspect */ w_src = width * clip->aspx; h_src = height * clip->aspy; @@ -4187,7 +4199,7 @@ static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase invert_m4_m4(imat, mat); - mul_serie_m4(cob->matrix, cammat, imat, camimat, parmat, obmat, NULL, NULL, NULL); + mul_m4_series(cob->matrix, cammat, imat, camimat, parmat, obmat); } } } diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 47b29b49689..de285f87444 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -48,7 +48,6 @@ #include "BKE_context.h" #include "BKE_main.h" #include "BKE_screen.h" -#include "BKE_freestyle.h" #include "RNA_access.h" @@ -1091,16 +1090,3 @@ int CTX_data_visible_pose_bones(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "visible_pose_bones", list); } - -FreestyleLineStyle *CTX_data_linestyle_from_scene(Scene *scene) -{ - SceneRenderLayer *actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay); - FreestyleConfig *config = &actsrl->freestyleConfig; - FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config); - - if (lineset) { - return lineset->linestyle; - } - - return NULL; -} diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index 7ca5d6b4f28..911bb19a594 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -40,7 +40,6 @@ #include "BLI_utildefines.h" #include "BLI_math.h" -#include "BLI_bitmap.h" #include "BKE_crazyspace.h" #include "BKE_DerivedMesh.h" @@ -49,11 +48,6 @@ #include "BKE_mesh.h" #include "BKE_editmesh.h" -typedef struct { - float (*vertexcos)[3]; - BLI_bitmap *vertex_visit; -} MappedUserData; - BLI_INLINE void tan_calc_quat_v3( float r_quat[4], const float co_1[3], const float co_2[3], const float co_3[3]) @@ -88,20 +82,6 @@ static void set_crazy_vertex_quat( sub_qt_qtqt(r_quat, q2, q1); } -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; - - if (BLI_BITMAP_TEST(mappedData->vertex_visit, index) == 0) { - /* 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_ENABLE(mappedData->vertex_visit, index); - } -} - static int modifiers_disable_subsurf_temporary(Object *ob) { ModifierData *md; @@ -124,8 +104,6 @@ float (*BKE_crazyspace_get_mapped_editverts(Scene *scene, Object *obedit))[3] DerivedMesh *dm; float (*vertexcos)[3]; int nverts = me->edit_btmesh->bm->totvert; - BLI_bitmap *vertex_visit; - MappedUserData userData; /* disable subsurf temporal, get mapped cos, and enable it */ if (modifiers_disable_subsurf_temporary(obedit)) { @@ -134,22 +112,17 @@ float (*BKE_crazyspace_get_mapped_editverts(Scene *scene, Object *obedit))[3] } /* now get the cage */ - dm = editbmesh_get_derived_cage(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH); + vertexcos = MEM_mallocN(sizeof(*vertexcos) * nverts, "vertexcos map"); - vertexcos = MEM_callocN(sizeof(*vertexcos) * nverts, "vertexcos map"); - vertex_visit = BLI_BITMAP_NEW(nverts, "vertexcos flags"); + dm = editbmesh_get_derived_cage(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH); - userData.vertexcos = vertexcos; - userData.vertex_visit = vertex_visit; - dm->foreachMappedVert(dm, make_vertexcos__mapFunc, &userData, DM_FOREACH_NOP); + mesh_get_mapped_verts_coords(dm, vertexcos, nverts); dm->release(dm); /* set back the flag, no new cage needs to be built, transform does it */ modifiers_disable_subsurf_temporary(obedit); - MEM_freeN(vertex_visit); - return vertexcos; } diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 0abe956b599..9275b626b49 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -52,6 +52,7 @@ #include "BKE_animsys.h" #include "BKE_curve.h" +#include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_font.h" #include "BKE_global.h" @@ -642,8 +643,9 @@ void BKE_nurb_test2D(Nurb *nu) } } -/* if use_radius is truth, minmax will take points' radius into account, - * which will make boundbox closer to bevelled curve. +/** + * if use_radius is truth, minmax will take points' radius into account, + * which will make boundbox closer to beveled curve. */ void BKE_nurb_minmax(Nurb *nu, bool use_radius, float min[3], float max[3]) { @@ -2498,6 +2500,22 @@ static void bevlist_firstlast_direction_calc_from_bpoint(Nurb *nu, BevList *bl) } } +void BKE_curve_bevelList_free(ListBase *bev) +{ + BevList *bl, *blnext; + for (bl = bev->first; bl != NULL; bl = blnext) { + blnext = bl->next; + if (bl->seglen != NULL) { + MEM_freeN(bl->seglen); + } + if (bl->segbevcount != NULL) { + MEM_freeN(bl->segbevcount); + } + MEM_freeN(bl); + } + bev->first = bev->last = NULL; +} + void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) { /* @@ -2506,21 +2524,29 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) * - separate in individual blocks with BoundBox * - AutoHole detection */ - Curve *cu; + + /* this function needs an object, because of tflag and upflag */ + Curve *cu = ob->data; Nurb *nu; BezTriple *bezt, *prevbezt; BPoint *bp; BevList *bl, *blnew, *blnext; BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0; + const float treshold = 0.00001f; float min, inp; + float *seglen; struct BevelSort *sortdata, *sd, *sd1; - int a, b, nr, poly, resolu = 0, len = 0; + int a, b, nr, poly, resolu = 0, len = 0, segcount; + int *segbevcount; bool do_tilt, do_radius, do_weight; bool is_editmode = false; ListBase *bev; - /* this function needs an object, because of tflag and upflag */ - cu = ob->data; + /* segbevcount alsp requires seglen. */ + const bool need_seglen = + ELEM(cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) || + ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE); + bev = &ob->curve_cache->bev; @@ -2529,7 +2555,7 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) /* STEP 1: MAKE POLYS */ - BLI_freelistN(&(ob->curve_cache->bev)); + BKE_curve_bevelList_free(&ob->curve_cache->bev); nu = nurbs->first; if (cu->editnurb && ob->type != OB_FONT) { is_editmode = 1; @@ -2559,9 +2585,15 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) else resolu = nu->resolu; + segcount = SEGMENTSU(nu); + if (nu->type == CU_POLY) { len = nu->pntsu; bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList2"); + if (need_seglen) { + bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelList2_seglen"); + bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelList2_segbevcount"); + } BLI_addtail(bev, bl); bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1; @@ -2569,7 +2601,11 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) bl->dupe_nr = 0; bl->charidx = nu->charidx; bevp = bl->bevpoints; + bevp->offset = 0; bp = nu->bp; + seglen = bl->seglen; + segbevcount = bl->segbevcount; + BLI_assert(segcount >= len); while (len--) { copy_v3_v3(bevp->vec, bp->vec); @@ -2577,23 +2613,53 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) bevp->radius = bp->radius; bevp->weight = bp->weight; bevp->split_tag = true; - bevp++; bp++; + if (seglen != NULL) { + *seglen = len_v3v3(bevp->vec, bp->vec); + bevp++; + bevp->offset = *seglen; + if (*seglen > treshold) *segbevcount = 1; + else *segbevcount = 0; + seglen++; + segbevcount++; + } + else { + bevp++; + } } if ((nu->flagu & CU_NURB_CYCLIC) == 0) { bevlist_firstlast_direction_calc_from_bpoint(nu, bl); + if (seglen != NULL) { + *seglen = len_v3v3(bevp->vec, nu->bp->vec); + bl->bevpoints->offset = *seglen; + *segbevcount = 1; + } } } else if (nu->type == CU_BEZIER) { /* in case last point is not cyclic */ - len = resolu * (nu->pntsu + (nu->flagu & CU_NURB_CYCLIC) - 1) + 1; + len = segcount * resolu + 1; + bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelBPoints"); + if (need_seglen) { + bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelBPoints_seglen"); + bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelBPoints_segbevcount"); + } BLI_addtail(bev, bl); bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1; bl->charidx = nu->charidx; + bevp = bl->bevpoints; + seglen = bl->seglen; + segbevcount = bl->segbevcount; + + bevp->offset = 0; + if (seglen != NULL) { + *seglen = 0; + *segbevcount = 0; + } a = nu->pntsu - 1; bezt = nu->bezt; @@ -2609,6 +2675,8 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) sub_v3_v3v3(bevp->dir, prevbezt->vec[2], prevbezt->vec[1]); normalize_v3(bevp->dir); + BLI_assert(segcount >= a); + while (a--) { if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) { @@ -2621,6 +2689,14 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) bevp++; bl->nr++; bl->dupe_nr = 1; + if (seglen != NULL) { + *seglen = len_v3v3(prevbezt->vec[1], bezt->vec[1]); + bevp->offset = *seglen; + seglen++; + /* match segbevcount to the cleaned up bevel lists (see STEP 2) */ + if (bevp->offset > treshold) *segbevcount = 1; + segbevcount++; + } } else { /* always do all three, to prevent data hanging around */ @@ -2658,8 +2734,28 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) else if (prevbezt->h2 == 0 || prevbezt->h2 == HD_VECT) bevp->split_tag = true; } + + /* seglen */ + if (seglen != NULL) { + *seglen = 0; + *segbevcount = 0; + for (j = 0; j < resolu; j++) { + bevp0 = bevp; + bevp++; + bevp->offset = len_v3v3(bevp0->vec, bevp->vec); + /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */ + if (bevp->offset > treshold) { + *seglen += bevp->offset; + *segbevcount += 1; + } + } + seglen++; + segbevcount++; + } + else { + bevp += resolu; + } bl->nr += resolu; - bevp += resolu; } prevbezt = bezt; bezt++; @@ -2679,15 +2775,22 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) } else if (nu->type == CU_NURBS) { if (nu->pntsv == 1) { - len = (resolu * SEGMENTSU(nu)); + len = (resolu * segcount); bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList3"); + if (need_seglen) { + bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelList3_seglen"); + bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelList3_segbevcount"); + } BLI_addtail(bev, bl); bl->nr = len; bl->dupe_nr = 0; bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1; bl->charidx = nu->charidx; + bevp = bl->bevpoints; + seglen = bl->seglen; + segbevcount = bl->segbevcount; BKE_nurb_makeCurve(nu, &bevp->vec[0], do_tilt ? &bevp->alfa : NULL, @@ -2695,6 +2798,31 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) do_weight ? &bevp->weight : NULL, resolu, sizeof(BevPoint)); + /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */ + if (seglen != NULL) { + nr = segcount; + bevp0 = bevp; + bevp++; + while (nr) { + int j; + *seglen = 0; + *segbevcount = 0; + /* We keep last bevel segment zero-length. */ + for (j = 0; j < ((nr == 1) ? (resolu - 1) : resolu); j++) { + bevp->offset = len_v3v3(bevp0->vec, bevp->vec); + if (bevp->offset > treshold) { + *seglen += bevp->offset; + *segbevcount += 1; + } + bevp0 = bevp; + bevp++; + } + seglen++; + segbevcount++; + nr--; + } + } + if ((nu->flagu & CU_NURB_CYCLIC) == 0) { bevlist_firstlast_direction_calc_from_bpoint(nu, bl); } @@ -2715,15 +2843,24 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) } else { bevp0 = bl->bevpoints; + bevp0->offset = 0; bevp1 = bevp0 + 1; } nr--; while (nr--) { - if (fabsf(bevp0->vec[0] - bevp1->vec[0]) < 0.00001f) { - if (fabsf(bevp0->vec[1] - bevp1->vec[1]) < 0.00001f) { - if (fabsf(bevp0->vec[2] - bevp1->vec[2]) < 0.00001f) { - bevp0->dupe_tag = true; - bl->dupe_nr++; + if (seglen != NULL) { + if (fabsf(bevp1->offset) < treshold) { + bevp0->dupe_tag = true; + bl->dupe_nr++; + } + } + else { + if (fabsf(bevp0->vec[0] - bevp1->vec[0]) < 0.00001f) { + if (fabsf(bevp0->vec[1] - bevp1->vec[1]) < 0.00001f) { + if (fabsf(bevp0->vec[2] - bevp1->vec[2]) < 0.00001f) { + bevp0->dupe_tag = true; + bl->dupe_nr++; + } } } } @@ -2740,6 +2877,8 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */ blnew = MEM_mallocN(sizeof(BevList) + nr * sizeof(BevPoint), "makeBevelList4"); memcpy(blnew, bl, sizeof(BevList)); + blnew->segbevcount = bl->segbevcount; + blnew->seglen = bl->seglen; blnew->nr = 0; BLI_remlink(bev, bl); BLI_insertlinkbefore(bev, blnext, blnew); /* to make sure bevlijst is tuned with nurblist */ @@ -3070,7 +3209,13 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n madd_v3_v3v3fl(p2_h2, p2, dvec_b, 1.0f / 3.0f); } - if (skip_align || (!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) { + if (skip_align || + /* when one handle is free, alignming makes no sense, see: T35952 */ + (ELEM(HD_FREE, bezt->h1, bezt->h2)) || + /* also when no handles are aligned, skip this step */ + (!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && + !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) + { /* handles need to be updated during animation and applying stuff like hooks, * but in such situations it's quite difficult to distinguish in which order * align handles should be aligned so skip them for now */ @@ -3168,6 +3313,31 @@ void BKE_nurb_handles_calc(Nurb *nu) /* first, if needed, set handle flags */ calchandlesNurb_intern(nu, false); } +/** + * Workaround #BKE_nurb_handles_calc logic + * that makes unselected align to the selected handle. + */ +static void nurbList_handles_swap_select(Nurb *nu) +{ + BezTriple *bezt; + int i; + + for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) { + if ((bezt->f1 & SELECT) != (bezt->f3 & SELECT)) { + bezt->f1 ^= SELECT; + bezt->f3 ^= SELECT; + } + } +} + +/* internal use only (weak) */ +static void nurb_handles_calc__align_selected(Nurb *nu) +{ + nurbList_handles_swap_select(nu); + BKE_nurb_handles_calc(nu); + nurbList_handles_swap_select(nu); +} + /* 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) @@ -3365,7 +3535,9 @@ void BKE_nurbList_handles_set(ListBase *editnurb, const char code) } bezt++; } - BKE_nurb_handles_calc(nu); + + /* like BKE_nurb_handles_calc but moves selected */ + nurb_handles_calc__align_selected(nu); } nu = nu->next; } @@ -3409,7 +3581,9 @@ void BKE_nurbList_handles_set(ListBase *editnurb, const char code) bezt++; } - BKE_nurb_handles_calc(nu); + + /* like BKE_nurb_handles_calc but moves selected */ + nurb_handles_calc__align_selected(nu); } } } @@ -4143,7 +4317,50 @@ bool BKE_curve_center_bounds(Curve *cu, float cent[3]) return false; } -void BKE_curve_translate(Curve *cu, float offset[3], const bool do_keys) + +void BKE_curve_transform_ex(Curve *cu, float mat[4][4], bool do_keys, float unit_scale) +{ + Nurb *nu; + BPoint *bp; + BezTriple *bezt; + int i; + + for (nu = cu->nurb.first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + i = nu->pntsu; + for (bezt = nu->bezt; i--; bezt++) { + mul_m4_v3(mat, bezt->vec[0]); + mul_m4_v3(mat, bezt->vec[1]); + mul_m4_v3(mat, bezt->vec[2]); + bezt->radius *= unit_scale; + } + BKE_nurb_handles_calc(nu); + } + else { + i = nu->pntsu * nu->pntsv; + for (bp = nu->bp; i--; bp++) + mul_m4_v3(mat, bp->vec); + } + } + + if (do_keys && cu->key) { + KeyBlock *kb; + for (kb = cu->key->block.first; kb; kb = kb->next) { + float *fp = kb->data; + for (i = kb->totelem; i--; fp += 3) { + mul_m4_v3(mat, fp); + } + } + } +} + +void BKE_curve_transform(Curve *cu, float mat[4][4], bool do_keys) +{ + float unit_scale = mat4_to_scale(mat); + BKE_curve_transform_ex(cu, mat, do_keys, unit_scale); +} + +void BKE_curve_translate(Curve *cu, float offset[3], bool do_keys) { ListBase *nurb_lb = BKE_curve_nurbs_get(cu); Nurb *nu; @@ -4230,6 +4447,45 @@ void BKE_curve_material_index_clear(Curve *cu) } } +int BKE_curve_material_index_validate(Curve *cu) +{ + const int curvetype = BKE_curve_type_get(cu); + bool is_valid = true; + + if (curvetype == OB_FONT) { + CharInfo *info = cu->strinfo; + const int max_idx = max_ii(0, cu->totcol); /* OB_FONT use 1 as first mat index, not 0!!! */ + int i; + for (i = cu->len_wchar - 1; i >= 0; i--, info++) { + if (info->mat_nr > max_idx) { + info->mat_nr = 0; + is_valid = false; + } + } + } + else { + Nurb *nu; + const int max_idx = max_ii(0, cu->totcol - 1); + for (nu = cu->nurb.first; nu; nu = nu->next) { + if (nu->mat_nr > max_idx) { + nu->mat_nr = 0; + if (curvetype == OB_CURVE) { + nu->charidx = 0; + } + is_valid = false; + } + } + } + + if (!is_valid) { + DAG_id_tag_update(&cu->id, OB_RECALC_DATA); + return true; + } + else { + return false; + } +} + void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect) { r_rect->xmin = cu->xof + tb->x; diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index d072088ac8e..528ff2d7b19 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -559,7 +559,7 @@ void defgroup_unique_name(bDeformGroup *dg, Object *ob) static bool is_char_sep(const char c) { - return ELEM4(c, '.', ' ', '-', '_'); + return ELEM(c, '.', ' ', '-', '_'); } /* based on BLI_split_dirfile() / os.path.splitext(), "a.b.c" -> ("a.b", ".c") */ @@ -614,6 +614,7 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[ char replace[MAX_VGROUP_NAME] = ""; /* The replacement string */ char number[MAX_VGROUP_NAME] = ""; /* The number extension string */ char *index = NULL; + bool is_set = false; /* always copy the name, since this can be called with an uninitialized string */ BLI_strncpy(name, from_name, MAX_VGROUP_NAME); @@ -640,6 +641,7 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[ /* first case; separator . - _ with extensions r R l L */ if (is_char_sep(name[len - 2])) { + is_set = true; switch (name[len - 1]) { case 'l': prefix[len - 1] = 0; @@ -657,10 +659,14 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[ prefix[len - 1] = 0; strcpy(replace, "L"); break; + default: + is_set = false; } } + /* case; beginning with r R l L, with separator after it */ - else if (is_char_sep(name[1])) { + if (!is_set && is_char_sep(name[1])) { + is_set = true; switch (name[0]) { case 'l': strcpy(replace, "r"); @@ -682,40 +688,43 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[ BLI_strncpy(suffix, name + 1, sizeof(suffix)); prefix[0] = 0; break; + default: + is_set = false; } } - else if (len > 5) { + + if (!is_set && len > 5) { /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */ - index = BLI_strcasestr(prefix, "right"); - if (index == prefix || index == prefix + len - 5) { - if (index[0] == 'r') + if (((index = BLI_strcasestr(prefix, "right")) == prefix) || + (index == prefix + len - 5)) + { + is_set = true; + if (index[0] == 'r') { strcpy(replace, "left"); + } else { - if (index[1] == 'I') - strcpy(replace, "LEFT"); - else - strcpy(replace, "Left"); + strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left"); } *index = 0; BLI_strncpy(suffix, index + 5, sizeof(suffix)); } - else { - index = BLI_strcasestr(prefix, "left"); - if (index == prefix || index == prefix + len - 4) { - if (index[0] == 'l') - strcpy(replace, "right"); - else { - if (index[1] == 'E') - strcpy(replace, "RIGHT"); - else - strcpy(replace, "Right"); - } - *index = 0; - BLI_strncpy(suffix, index + 4, sizeof(suffix)); + else if (((index = BLI_strcasestr(prefix, "left")) == prefix) || + (index == prefix + len - 4)) + { + is_set = true; + if (index[0] == 'l') { + strcpy(replace, "right"); + } + else { + strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right"); } + *index = 0; + BLI_strncpy(suffix, index + 4, sizeof(suffix)); } } + (void)is_set; /* quiet warning */ + BLI_snprintf(name, MAX_VGROUP_NAME, "%s%s%s%s", prefix, replace, suffix, number); } diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 24b580672d1..93bb4849718 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -59,8 +59,10 @@ #include "DNA_movieclip_types.h" #include "DNA_mask_types.h" +#include "BKE_anim.h" #include "BKE_animsys.h" #include "BKE_action.h" +#include "BKE_DerivedMesh.h" #include "BKE_effect.h" #include "BKE_fcurve.h" #include "BKE_global.h" @@ -79,6 +81,8 @@ #include "BKE_screen.h" #include "BKE_tracking.h" +#include "GPU_buffers.h" + #include "atomic_ops.h" #include "depsgraph_private.h" @@ -524,7 +528,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O if (ct->tar->type == OB_MESH) node3->customdata_mask |= CD_MASK_MDEFORMVERT; } - else if (ELEM3(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) + else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) dag_add_relation(dag, node3, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name); else dag_add_relation(dag, node3, node, DAG_RL_OB_DATA, cti->name); @@ -688,6 +692,29 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Taper"); } if (ob->type == OB_FONT) { + /* Really rather dirty hack. needs to support font family to work + * reliably on render export. + * + * This totally mimics behavior of regular verts duplication with + * parenting. The only tricky thing here is to get list of objects + * used for the custom "font". + * + * This shouldn't harm so much because this code only runs on DAG + * rebuild and this feature is not that commonly used. + * + * - sergey - + */ + if (cu->family[0] != '\n') { + ListBase *duplilist; + DupliObject *dob; + duplilist = object_duplilist(G.main->eval_ctx, scene, ob); + for (dob = duplilist->first; dob; dob = dob->next) { + node2 = dag_get_node(dag, dob->ob); + dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Object Font"); + } + free_object_duplilist(duplilist); + } + if (cu->textoncurve) { node2 = dag_get_node(dag, cu->textoncurve); /* Text on curve requires path to be evaluated for the target curve. */ @@ -803,7 +830,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O continue; /* special case for camera tracking -- it doesn't use targets to define relations */ - if (ELEM3(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { + if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { int depends_on_camera = 0; if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) { @@ -843,7 +870,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); else { - if (ELEM3(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { + if (ELEM(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); if (obt->type == OB_MESH) node2->customdata_mask |= CD_MASK_MDEFORMVERT; @@ -1386,7 +1413,7 @@ static bool check_object_needs_evaluation(Object *object) if (object->type == OB_MESH) { return object->derivedFinal == NULL; } - else if (ELEM5(object->type, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { + else if (ELEM(object->type, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { return object->curve_cache == NULL; } @@ -1400,7 +1427,7 @@ static bool check_object_tagged_for_update(Object *object) return true; } - if (ELEM6(object->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { + if (ELEM(object->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { ID *data_id = object->data; return (data_id->flag & (LIB_ID_RECALC_DATA | LIB_ID_RECALC)) != 0; } @@ -1747,7 +1774,8 @@ static unsigned int flush_layer_node(Scene *sce, DagNode *node, int curtime) } /* node was checked to have lasttime != curtime, and is of type ID_OB */ -static void flush_pointcache_reset(Main *bmain, Scene *scene, DagNode *node, int curtime, int reset) +static void flush_pointcache_reset(Main *bmain, Scene *scene, DagNode *node, + int curtime, unsigned int lay, bool reset) { DagAdjList *itA; Object *ob; @@ -1761,14 +1789,17 @@ static void flush_pointcache_reset(Main *bmain, Scene *scene, DagNode *node, int if (reset || (ob->recalc & OB_RECALC_ALL)) { if (BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH)) { - ob->recalc |= OB_RECALC_DATA; - lib_id_recalc_data_tag(bmain, &ob->id); + /* Don't tag nodes which are on invisible layer. */ + if (itA->node->lay & lay) { + ob->recalc |= OB_RECALC_DATA; + lib_id_recalc_data_tag(bmain, &ob->id); + } } - flush_pointcache_reset(bmain, scene, itA->node, curtime, 1); + flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, true); } else - flush_pointcache_reset(bmain, scene, itA->node, curtime, 0); + flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, false); } } } @@ -1885,10 +1916,12 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho lib_id_recalc_data_tag(bmain, &ob->id); } - flush_pointcache_reset(bmain, sce, itA->node, lasttime, 1); + flush_pointcache_reset(bmain, sce, itA->node, lasttime, + lay, true); } else - flush_pointcache_reset(bmain, sce, itA->node, lasttime, 0); + flush_pointcache_reset(bmain, sce, itA->node, lasttime, + lay, false); } } } @@ -1983,7 +2016,7 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob) if (cti) { /* special case for camera tracking -- it doesn't use targets to define relations */ - if (ELEM3(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { + if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { ob->recalc |= OB_RECALC_OB; } else if (cti->get_constraint_targets) { @@ -2272,7 +2305,7 @@ static void dag_group_on_visible_update(Group *group) 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)) { + if (ELEM(go->ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { go->ob->recalc |= OB_RECALC_DATA; go->ob->id.flag |= LIB_DOIT; lib_id_recalc_tag(G.main, &go->ob->id); @@ -2319,7 +2352,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time) oblay = (node) ? node->lay : ob->lay; if ((oblay & lay) & ~scene->lay_updated) { - if (ELEM6(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { ob->recalc |= OB_RECALC_DATA; lib_id_recalc_tag(bmain, &ob->id); } @@ -2472,6 +2505,14 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id) BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); } + if (ELEM(idtype, ID_MA, ID_TE)) { + obt = sce->basact ? sce->basact->object : NULL; + if (obt && obt->mode & OB_MODE_TEXTURE_PAINT) { + BKE_texpaint_slots_refresh_object(sce, obt); + GPU_drawobject_free(obt->derivedFinal); + } + } + if (idtype == ID_MC) { MovieClip *clip = (MovieClip *) id; @@ -2481,7 +2522,7 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id) bConstraint *con; for (con = obt->constraints.first; con; con = con->next) { bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - if (ELEM3(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, + if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { obt->recalc |= OB_RECALC_OB; @@ -2502,6 +2543,23 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id) } } + /* Not pretty to iterate all the nodes here, but it's as good as it + * could be with the current depsgraph design/ + */ + if (idtype == ID_IM) { + FOREACH_NODETREE(bmain, ntree, parent_id) { + if (ntree->type == NTREE_SHADER) { + bNode *node; + for (node = ntree->nodes.first; node; node = node->next) { + if (node->id == id) { + lib_id_recalc_tag(bmain, &ntree->id); + break; + } + } + } + } FOREACH_NODETREE_END + } + if (idtype == ID_MSK) { if (sce->nodetree) { bNode *node; @@ -2742,7 +2800,7 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) if (ob->type == OB_FONT) { Curve *cu = ob->data; - if (ELEM4((struct VFont *)id, cu->vfont, cu->vfontb, cu->vfonti, cu->vfontbi)) { + if (ELEM((struct VFont *)id, cu->vfont, cu->vfontb, cu->vfonti, cu->vfontbi)) { ob->recalc |= (flag & OB_RECALC_ALL); } } diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index cf894e72324..98f0025921d 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -122,7 +122,7 @@ bool BKE_displist_has_faces(ListBase *lb) DispList *dl; for (dl = lb->first; dl; dl = dl->next) { - if (ELEM3(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { + if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { return true; } } @@ -653,8 +653,8 @@ static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dis bevels_to_filledpoly(cu, dispbase); } else { - /* TODO, investigate passing zup instead of NULL */ - BKE_displist_fill(dispbase, dispbase, NULL, false); + const float z_up[3] = {0.0f, 0.0f, 1.0f}; + BKE_displist_fill(dispbase, dispbase, z_up, false); } } @@ -715,21 +715,20 @@ void BKE_displist_make_mball(EvaluationContext *eval_ctx, Scene *scene, Object * if (!ob || ob->type != OB_MBALL) return; - if (ob->curve_cache) { - BKE_displist_free(&(ob->curve_cache->disp)); - } - else { - ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall"); - } + if (ob == BKE_mball_basis_find(scene, ob)) { + 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(eval_ctx, scene, ob, &ob->curve_cache->disp); - BKE_mball_texspace_calc(ob); + BKE_mball_polygonize(eval_ctx, scene, ob, &ob->curve_cache->disp); + BKE_mball_texspace_calc(ob); - object_deform_mball(ob, &ob->curve_cache->disp); - } + object_deform_mball(ob, &ob->curve_cache->disp); + /* NOP for MBALLs anyway... */ boundbox_displist_object(ob); } } @@ -767,7 +766,7 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob, if (mti->type == eModifierTypeType_Constructive) return pretessellatePoint; - if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) { + if (ELEM(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) { pretessellatePoint = md; /* this modifiers are moving point of tessellation automatically @@ -1357,31 +1356,57 @@ static void fillBevelCap(Nurb *nu, DispList *dlb, float *prev_fp, ListBase *disp BLI_addtail(dispbase, dl); } +static void calc_bevfac_segment_mapping(BevList *bl, float bevfac, float spline_length, int *r_bev, float *r_blend) +{ + float normlen, normsum = 0.0f; + float *seglen = bl->seglen; + int *segbevcount = bl->segbevcount; + int bevcount = 0, nr = bl->nr; + + float bev_fl = bevfac * (bl->nr - 1); + *r_bev = (int)bev_fl; + + while (bevcount < nr - 1) { + normlen = *seglen / spline_length; + if (normsum + normlen > bevfac) { + bev_fl = bevcount + (bevfac - normsum) / normlen * *segbevcount; + *r_bev = (int) bev_fl; + *r_blend = bev_fl - *r_bev; + break; + } + normsum += normlen; + bevcount += *segbevcount; + segbevcount++; + seglen++; + } +} -static void calc_bevfac_spline_mapping(BevList *bl, float bevfac, float spline_length, const float *bevp_array, +static void calc_bevfac_spline_mapping(BevList *bl, float bevfac, + float spline_length, int *r_bev, float *r_blend) { const float len_target = bevfac * spline_length; - float len = 0.0f; - float len_step = 0.0f; - int i; - for (i = 0; i < bl->nr - 1; i++) { - float len_next; - len_step = bevp_array[i]; - len_next = len + len_step; + BevPoint *bevp = bl->bevpoints; + float len_next = 0.0f, len = 0.0f; + int i = 0, nr = bl->nr; + + while (nr--) { + bevp++; + len_next = len + bevp->offset; if (len_next > len_target) { break; } len = len_next; + i++; } *r_bev = i; - *r_blend = (len_target - len) / len_step; + *r_blend = (len_target - len) / bevp->offset; } -static void calc_bevfac_mapping_default( - BevList *bl, - int *r_start, float *r_firstblend, int *r_steps, float *r_lastblend) +static void calc_bevfac_mapping_default(BevList *bl, + int *r_start, float *r_firstblend, + int *r_steps, float *r_lastblend) { *r_start = 0; *r_steps = bl->nr; @@ -1389,19 +1414,11 @@ static void calc_bevfac_mapping_default( *r_lastblend = 1.0f; } -static void calc_bevfac_mapping( - Curve *cu, BevList *bl, Nurb *nu, const bool use_render_resolution, +static void calc_bevfac_mapping(Curve *cu, BevList *bl, Nurb *nu, int *r_start, float *r_firstblend, int *r_steps, float *r_lastblend) { - const int resolu = (nu->type == CU_POLY) ? - 1 : (use_render_resolution && (cu->resolu_ren != 0)) ? - cu->resolu_ren : cu->resolu; - const int segcount = ((nu->type == CU_POLY) ? bl->nr : nu->pntsu) - 1; - - float l, startf, endf, tmpf, total_length = 0.0f; - float *bevp_array = NULL; - float *segments = NULL; - int end = 0, i, j; + float tmpf, total_length = 0.0f; + int end = 0, i; if ((BKE_nurb_check_valid_u(nu) == false) || /* not essential, but skips unnecessary calculation */ @@ -1412,57 +1429,12 @@ static void calc_bevfac_mapping( return; } - if ((cu->bevfac1_mapping != CU_BEVFAC_MAP_RESOLU) || - (cu->bevfac2_mapping != CU_BEVFAC_MAP_RESOLU)) + if (ELEM(cu->bevfac1_mapping, + CU_BEVFAC_MAP_SEGMENT, + CU_BEVFAC_MAP_SPLINE)) { - BezTriple *bezt, *bezt_prev; - BevPoint *bevp, *bevp_prev; - int bevp_i; - - bevp_array = MEM_mallocN(sizeof(*bevp_array) * (bl->nr - 1), "bevp_dists"); - segments = MEM_callocN(sizeof(*segments) * segcount, "bevp_segmentlengths"); - bevp_prev = bl->bevpoints; - bevp = bevp_prev + 1; - - if (nu->type == CU_BEZIER) { - bezt_prev = nu->bezt; - bezt = bezt_prev + 1; - for (i = 0, bevp_i = 0; i < segcount; i++, bezt_prev++, bezt++) { - float seglen = 0.0f; - if (bezt_prev->h2 == HD_VECT && bezt->h1 == HD_VECT) { - seglen = len_v3v3(bevp->vec, bevp_prev->vec); - BLI_assert(bevp_i < bl->nr - 1); - bevp_array[bevp_i++] = seglen; - - bevp_prev = bevp++; - } - else { - for (j = 0; j < resolu; j++, bevp_prev = bevp++) { - l = len_v3v3(bevp->vec, bevp_prev->vec); - seglen += l; - BLI_assert(bevp_i < bl->nr - 1); - bevp_array[bevp_i++] = l; - } - } - BLI_assert(i < segcount); - segments[i] = seglen; - total_length += seglen; - seglen = 0.0f; - } - } - else { - float seglen = 0.0f; - for (i = 1, j = 0; i < bl->nr; i++, bevp_prev = bevp++) { - BLI_assert(i - 1 < bl->nr); - bevp_array[i - 1] = len_v3v3(bevp->vec, bevp_prev->vec); - total_length += bevp_array[i - 1]; - seglen += bevp_array[i - 1]; - if ((i % resolu) == 0 || (bl->nr - 1) == i) { - BLI_assert(j < segcount); - segments[j++] = seglen; - seglen = 0.0f; - } - } + for (i = 0; i < SEGMENTSU(nu); i++) { + total_length += bl->seglen[i]; } } @@ -1471,31 +1443,18 @@ static void calc_bevfac_mapping( { const float start_fl = cu->bevfac1 * (bl->nr - 1); *r_start = (int)start_fl; - *r_firstblend = 1.0f - (start_fl - (*r_start)); break; } case CU_BEVFAC_MAP_SEGMENT: { - float sum = 0.0f; - const float start_fl = cu->bevfac1 * (bl->nr - 1); - *r_start = (int)start_fl; - - for (i = 0; i < segcount; i++) { - l = segments[i] / total_length; - if (sum + l > cu->bevfac1) { - startf = i * resolu + (cu->bevfac1 - sum) / l * resolu; - *r_start = (int) startf; - *r_firstblend = 1.0f - (startf - *r_start); - break; - } - sum += l; - } + calc_bevfac_segment_mapping(bl, cu->bevfac1, total_length, r_start, r_firstblend); + *r_firstblend = 1.0f - *r_firstblend; break; } case CU_BEVFAC_MAP_SPLINE: { - calc_bevfac_spline_mapping(bl, cu->bevfac1, total_length, bevp_array, r_start, r_firstblend); + calc_bevfac_spline_mapping(bl, cu->bevfac1, total_length, r_start, r_firstblend); *r_firstblend = 1.0f - *r_firstblend; break; } @@ -1513,27 +1472,13 @@ static void calc_bevfac_mapping( } case CU_BEVFAC_MAP_SEGMENT: { - float sum = 0.0f; - const float end_fl = cu->bevfac2 * (bl->nr - 1); - end = (int)end_fl; - + calc_bevfac_segment_mapping(bl, cu->bevfac2, total_length, &end, r_lastblend); *r_steps = end - *r_start + 2; - for (i = 0; i < segcount; i++) { - l = segments[i] / total_length; - if (sum + l > cu->bevfac2) { - endf = i * resolu + (cu->bevfac2 - sum) / l * resolu; - end = (int)endf; - *r_lastblend = (endf - end); - *r_steps = end - *r_start + 2; - break; - } - sum += l; - } break; } case CU_BEVFAC_MAP_SPLINE: { - calc_bevfac_spline_mapping(bl, cu->bevfac2, total_length, bevp_array, &end, r_lastblend); + calc_bevfac_spline_mapping(bl, cu->bevfac2, total_length, &end, r_lastblend); *r_steps = end - *r_start + 2; break; } @@ -1551,13 +1496,6 @@ static void calc_bevfac_mapping( *r_steps = bl->nr - *r_start; *r_lastblend = 1.0f; } - - if (bevp_array) { - MEM_freeN(bevp_array); - } - if (segments) { - MEM_freeN(segments); - } } static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispbase, @@ -1567,7 +1505,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba Curve *cu = ob->data; /* we do allow duplis... this is only displist on curve level */ - if (!ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return; + if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return; if (ob->type == OB_SURF) { BKE_displist_make_surf(scene, ob, dispbase, r_dm_final, for_render, for_orco, use_render_resolution); @@ -1576,7 +1514,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba ListBase dlbev; ListBase nubase = {NULL, NULL}; - BLI_freelistN(&(ob->curve_cache->bev)); + BKE_curve_bevelList_free(&ob->curve_cache->bev); /* We only re-evlauate path if evaluation is not happening for orco. * If the calculation happens for orco, we should never free data which @@ -1668,8 +1606,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba continue; } - calc_bevfac_mapping(cu, bl, nu, use_render_resolution, - &start, &firstblend, &steps, &lastblend); + calc_bevfac_mapping(cu, bl, nu, &start, &firstblend, &steps, &lastblend); } for (dlb = dlbev.first; dlb; dlb = dlb->next) { @@ -1810,7 +1747,7 @@ void BKE_displist_make_curveTypes(Scene *scene, Object *ob, const bool for_orco) /* The same check for duplis as in do_makeDispListCurveTypes. * Happens when curve used for constraint/bevel was converted to mesh. * check there is still needed for render displist and orco displists. */ - if (!ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) + if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return; BKE_object_free_derived_caches(ob); @@ -1831,7 +1768,7 @@ void BKE_displist_make_curveTypes_forRender(Scene *scene, Object *ob, ListBase * const bool use_render_resolution) { if (ob->curve_cache == NULL) { - ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall"); + ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); } do_makeDispListCurveTypes(scene, ob, dispbase, r_dm_final, true, for_orco, use_render_resolution); @@ -1840,7 +1777,7 @@ void BKE_displist_make_curveTypes_forRender(Scene *scene, Object *ob, ListBase * 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"); + ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); } do_makeDispListCurveTypes(scene, ob, dispbase, NULL, 1, 1, 1); @@ -1895,8 +1832,8 @@ void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3]) /* this is confusing, there's also min_max_object, appplying the obmat... */ static void boundbox_displist_object(Object *ob) { - if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - /* Curver's BB is already calculated as a part of modifier stack, + if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + /* Curve's BB is already calculated as a part of modifier stack, * here we only calculate object BB based on final display list. */ diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 11737bccef2..4719013e2f8 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -2942,9 +2942,10 @@ static void mesh_faces_nearest_point_dp(void *userdata, int index, const float c do { float nearest_tmp[3], dist_sq; - int vertex, edge; - - dist_sq = nearest_point_in_tri_surface_squared(t0, t1, t2, co, &vertex, &edge, nearest_tmp); + + closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2); + dist_sq = len_squared_v3v3(co, nearest_tmp); + if (dist_sq < nearest->dist_sq) { nearest->index = index; nearest->dist_sq = dist_sq; diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index e74adea529b..ce7804d9878 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -910,7 +910,7 @@ static void emDM_drawFacesTex_common(DerivedMesh *dm, static void emDM_drawFacesTex(DerivedMesh *dm, DMSetDrawOptionsTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag UNUSED(flag)) { emDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData); } @@ -918,7 +918,7 @@ static void emDM_drawFacesTex(DerivedMesh *dm, static void emDM_drawMappedFacesTex(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag UNUSED(flag)) { emDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData); } diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c index 76ea340ecbd..442ab26ffc8 100644 --- a/source/blender/blenkernel/intern/editmesh_bvh.c +++ b/source/blender/blenkernel/intern/editmesh_bvh.c @@ -53,13 +53,17 @@ struct BMBVHTree { int flag; }; -BMBVHTree *BKE_bmbvh_new_from_editmesh(BMEditMesh *em, int flag, const float (*cos_cage)[3], const bool cos_cage_free) +BMBVHTree *BKE_bmbvh_new_from_editmesh( + BMEditMesh *em, int flag, + const float (*cos_cage)[3], const bool cos_cage_free) { return BKE_bmbvh_new(em->bm, em->looptris, em->tottri, flag, cos_cage, cos_cage_free); } -BMBVHTree *BKE_bmbvh_new(BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag, const float (*cos_cage)[3], -const bool cos_cage_free) +BMBVHTree *BKE_bmbvh_new_ex( + BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag, + const float (*cos_cage)[3], const bool cos_cage_free, + bool (*test_fn)(BMFace *, void *user_data), void *user_data) { /* could become argument */ const float epsilon = FLT_EPSILON * 2.0f; @@ -69,6 +73,10 @@ const bool cos_cage_free) int i; int tottri; + /* avoid testing every tri */ + BMFace *f_test, *f_test_prev; + bool test_fn_ret; + /* BKE_editmesh_tessface_calc() must be called already */ BLI_assert(looptris_tot != 0 || bm->totface == 0); @@ -83,18 +91,22 @@ const bool cos_cage_free) bmtree->cos_cage_free = cos_cage_free; bmtree->flag = flag; - if (flag & (BMBVH_RESPECT_SELECT)) { + if (test_fn) { + /* callback must do... */ + BLI_assert(!(flag & (BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN))); + + f_test_prev = NULL; + test_fn_ret = false; + tottri = 0; for (i = 0; i < looptris_tot; i++) { - if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_SELECT)) { - tottri++; + f_test = looptris[i][0]->f; + if (f_test != f_test_prev) { + test_fn_ret = test_fn(f_test, user_data); + f_test_prev = f_test; } - } - } - else if (flag & (BMBVH_RESPECT_HIDDEN)) { - tottri = 0; - for (i = 0; i < looptris_tot; i++) { - if (!BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) { + + if (test_fn_ret) { tottri++; } } @@ -105,17 +117,19 @@ const bool cos_cage_free) bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8); - for (i = 0; i < looptris_tot; i++) { + f_test_prev = NULL; + test_fn_ret = false; - if (flag & BMBVH_RESPECT_SELECT) { + for (i = 0; i < looptris_tot; i++) { + if (test_fn) { /* note, the arrays wont align now! take care */ - if (!BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_SELECT)) { - continue; + f_test = looptris[i][0]->f; + if (f_test != f_test_prev) { + test_fn_ret = test_fn(f_test, user_data); + f_test_prev = f_test; } - } - else if (flag & BMBVH_RESPECT_HIDDEN) { - /* note, the arrays wont align now! take care */ - if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) { + + if (!test_fn_ret) { continue; } } @@ -139,6 +153,38 @@ const bool cos_cage_free) return bmtree; } +static bool bm_face_is_select(BMFace *f, void *UNUSED(user_data)) +{ + return (BM_elem_flag_test(f, BM_ELEM_SELECT) != 0); +} + +static bool bm_face_is_not_hidden(BMFace *f, void *UNUSED(user_data)) +{ + return (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == 0); +} + +BMBVHTree *BKE_bmbvh_new( + BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag, + const float (*cos_cage)[3], const bool cos_cage_free) +{ + bool (*test_fn)(BMFace *, void *user_data); + + if (flag & BMBVH_RESPECT_SELECT) { + test_fn = bm_face_is_select; + } + else if (flag & BMBVH_RESPECT_HIDDEN) { + test_fn = bm_face_is_not_hidden; + } + else { + test_fn = NULL; + } + + flag &= ~(BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN); + + return BKE_bmbvh_new_ex(bm, looptris, looptris_tot, flag, cos_cage, cos_cage_free, test_fn, NULL); +} + + void BKE_bmbvh_free(BMBVHTree *bmtree) { BLI_bvhtree_free(bmtree->tree); diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index e28152dbc1a..4859aa8f791 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -935,7 +935,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected if (pd->flag & PFIELD_DO_LOCATION) { madd_v3_v3fl(total_force, force, 1.0f/point->vel_to_sec); - if (ELEM3(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW)==0 && pd->f_flow != 0.0f) { + if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW)==0 && pd->f_flow != 0.0f) { madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff); } } diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index a8de9b69fbe..09c1dcf701d 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -276,7 +276,7 @@ int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix, int matches = 0; /* sanity checks */ - if (ELEM4(NULL, dst, src, dataPrefix, dataName)) + if (ELEM(NULL, dst, src, dataPrefix, dataName)) return 0; else if ((dataPrefix[0] == 0) || (dataName[0] == 0)) return 0; @@ -522,17 +522,28 @@ bool calc_fcurve_bounds(FCurve *fcu, float *xmin, float *xmax, float *ymin, floa /* only loop over keyframes to find extents for values if needed */ if (ymin || ymax) { - BezTriple *bezt; + BezTriple *bezt, *prevbezt = NULL; - for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) { - if ((do_sel_only == false) || BEZSELECTED(bezt)) { + for (bezt = fcu->bezt, i = 0; i < fcu->totvert; prevbezt = bezt, bezt++, i++) { + if ((do_sel_only == false) || BEZSELECTED(bezt)) { + /* keyframe itself */ + yminv = min_ff(yminv, bezt->vec[1][1]); + ymaxv = max_ff(ymaxv, bezt->vec[1][1]); + if (include_handles) { - yminv = min_ffff(yminv, bezt->vec[1][1], bezt->vec[0][1], bezt->vec[2][1]); - ymaxv = max_ffff(ymaxv, bezt->vec[1][1], bezt->vec[0][1], bezt->vec[2][1]); - } - else { - yminv = min_ff(yminv, bezt->vec[1][1]); - ymaxv = max_ff(ymaxv, bezt->vec[1][1]); + /* left handle - only if applicable + * NOTE: for the very first keyframe, the left handle actually has no bearings on anything + */ + if (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ)) { + yminv = min_ff(yminv, bezt->vec[0][1]); + ymaxv = max_ff(ymaxv, bezt->vec[0][1]); + } + + /* right handle - only if applicable */ + if (bezt->ipo == BEZT_IPO_BEZ) { + yminv = min_ff(yminv, bezt->vec[2][1]); + ymaxv = max_ff(ymaxv, bezt->vec[2][1]); + } } foundvert = true; diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c index 445acc850e6..4aa1b49ea13 100644 --- a/source/blender/blenkernel/intern/freestyle.c +++ b/source/blender/blenkernel/intern/freestyle.c @@ -187,7 +187,7 @@ FreestyleLineSet *BKE_freestyle_lineset_add(FreestyleConfig *config, const char BLI_addtail(&config->linesets, (void *)lineset); BKE_freestyle_lineset_set_active_index(config, lineset_index); - lineset->linestyle = BKE_new_linestyle("LineStyle", NULL); + lineset->linestyle = BKE_linestyle_new("LineStyle", NULL); lineset->flags |= FREESTYLE_LINESET_ENABLED; lineset->selection = FREESTYLE_SEL_VISIBILITY | FREESTYLE_SEL_EDGE_TYPES | FREESTYLE_SEL_IMAGE_BORDER; lineset->qi = FREESTYLE_QI_VISIBLE; diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index c381084cfd2..e226e9d9797 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -506,7 +506,7 @@ void gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active) bGPDlayer *gpl; /* error checking */ - if (ELEM3(NULL, gpd, gpd->layers.first, active)) + if (ELEM(NULL, gpd, gpd->layers.first, active)) return; /* loop over layers deactivating all */ diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index 2e201a0b8e8..1b7a03ec80e 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -73,6 +73,8 @@ static IDType idtypes[] = { { ID_NT, "NodeTree", "node_groups", IDTYPE_FLAGS_ISLINKABLE }, { ID_OB, "Object", "objects", IDTYPE_FLAGS_ISLINKABLE }, { ID_PA, "ParticleSettings", "particles", 0 }, + { ID_PAL, "Palettes", "palettes", IDTYPE_FLAGS_ISLINKABLE }, + { ID_PC, "PaintCurve", "paint_curves", IDTYPE_FLAGS_ISLINKABLE }, { ID_SCE, "Scene", "scenes", IDTYPE_FLAGS_ISLINKABLE }, { ID_SCR, "Screen", "screens", 0 }, { ID_SEQ, "Sequence", "sequences", 0 }, /* not actually ID data */ diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 3188676fb6c..4dbd15a3774 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -64,7 +64,7 @@ static char idp_size_table[] = { /** \name IDP Array API * \{ */ -#define GETPROP(prop, i) (((IDProperty *)(prop)->data.pointer) + (i)) +#define GETPROP(prop, i) &(IDP_IDPArray(prop)[i]) /* --------- property array type -------------*/ @@ -251,7 +251,7 @@ void IDP_ResizeArray(IDProperty *prop, int newlen) * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ newsize = newlen; - newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;\ + newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; if (is_grow == false) idp_resize_group_array(prop, newlen, prop->data.pointer); @@ -821,7 +821,7 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is case IDP_INT: return (IDP_Int(prop1) == IDP_Int(prop2)); case IDP_FLOAT: -#if defined(DEBUG) && defined(WITH_PYTHON) +#if !defined(NDEBUG) && defined(WITH_PYTHON) { float p1 = IDP_Float(prop1); float p2 = IDP_Float(prop2); diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index db5c212d1db..805c1250c5d 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -1257,7 +1257,7 @@ static bool do_add_image_extension(char *string, const char imtype, const ImageF extension = extension_test; } #endif - else if (ELEM5(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) { + else if (ELEM(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) { if (!BLI_testextensie(string, extension_test = ".png")) extension = extension_test; } @@ -1900,7 +1900,7 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf) ibuf->ftype = RADHDR; } #endif - else if (ELEM5(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) { + else if (ELEM(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) { ibuf->ftype = PNG; if (imtype == R_IMF_IMTYPE_PNG) { diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index 6682b1a9b2d..4d80256426d 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -1804,6 +1804,7 @@ static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothMo return 1; } + int implicit_solver(Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors) { unsigned int i=0; @@ -1888,10 +1889,8 @@ int implicit_solver(Object *ob, float frame, ClothModifierData *clmd, ListBase * //if (do_extra_solve) // cloth_calc_helper_forces(ob, clmd, initial_cos, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale); - for (i = 0; i < numverts; i++) { - - if (do_extra_solve) { - + if (do_extra_solve) { + for (i = 0; i < numverts; i++) { if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED)) continue; diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 7385322ddeb..51cf26063c7 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -1308,8 +1308,8 @@ static void icu_to_fcurves(ID *id, ListBase *groups, ListBase *list, IpoCurve *i * - they were degrees/10 * - we need radians for RNA to do the right thing */ - if ( ((icu->blocktype == ID_OB) && ELEM3(icu->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) || - ((icu->blocktype == ID_PO) && ELEM3(icu->adrcode, AC_EUL_X, AC_EUL_Y, AC_EUL_Z)) ) + if ( ((icu->blocktype == ID_OB) && ELEM(icu->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) || + ((icu->blocktype == ID_PO) && ELEM(icu->adrcode, AC_EUL_X, AC_EUL_Y, AC_EUL_Z)) ) { const float fac = (float)M_PI / 18.0f; //10.0f * M_PI/180.0f; @@ -1341,7 +1341,7 @@ static void icu_to_fcurves(ID *id, ListBase *groups, ListBase *list, IpoCurve *i DriverVar *dvar = fcu->driver->variables.first; DriverTarget *dtar = &dvar->targets[0]; - if (ELEM3(dtar->transChan, DTAR_TRANSCHAN_ROTX, DTAR_TRANSCHAN_ROTY, DTAR_TRANSCHAN_ROTZ)) { + if (ELEM(dtar->transChan, DTAR_TRANSCHAN_ROTX, DTAR_TRANSCHAN_ROTY, DTAR_TRANSCHAN_ROTZ)) { const float fac = (float)M_PI / 18.0f; dst->vec[0][0] *= fac; @@ -1388,7 +1388,7 @@ static void ipo_to_animato(ID *id, Ipo *ipo, char actname[], char constname[], S IpoCurve *icu; /* sanity check */ - if (ELEM3(NULL, ipo, anim, drivers)) + if (ELEM(NULL, ipo, anim, drivers)) return; if (G.debug & G_DEBUG) printf("ipo_to_animato\n"); diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index ea55f32ea05..3f12e3efcc7 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -729,7 +729,8 @@ void curve_deform_verts(Scene *scene, Object *cuOb, Object *target, DerivedMesh Curve *cu; int a; CurveDeform cd; - int use_vgroups; + MDeformVert *dvert = NULL; + int defgrp_index = -1; const bool is_neg_axis = (defaxis > 2); if (cuOb->type != OB_CURVE) @@ -750,75 +751,63 @@ void curve_deform_verts(Scene *scene, Object *cuOb, Object *target, DerivedMesh cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f; } - /* 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 - * deformverts + /* Check whether to use vertex groups (only possible if target is a Mesh or Lattice). + * We want either a Mesh/Lattice with no derived data, or derived data with deformverts. */ - if (target->type == OB_MESH) { - /* if there's derived data without deformverts, don't use vgroups */ - if (dm) { - use_vgroups = (dm->getVertData(dm, 0, CD_MDEFORMVERT) != NULL); - } - else { - Mesh *me = target->data; - use_vgroups = (me->dvert != NULL); + if (vgroup && vgroup[0] && ELEM(target->type, OB_MESH, OB_LATTICE)) { + defgrp_index = defgroup_name_index(target, vgroup); + + if (defgrp_index != -1) { + /* if there's derived data without deformverts, don't use vgroups */ + if (dm) { + dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + } + else if (target->type == OB_LATTICE) { + dvert = ((Lattice *)target->data)->dvert; + } + else { + dvert = ((Mesh *)target->data)->dvert; + } } } - else { - use_vgroups = false; - } - - if (vgroup && vgroup[0] && use_vgroups) { - Mesh *me = target->data; - const int defgrp_index = defgroup_name_index(target, vgroup); - if (defgrp_index != -1 && (me->dvert || dm)) { - MDeformVert *dvert = me->dvert; - float vec[3]; - float weight; - + if (dvert) { + MDeformVert *dvert_iter; + float vec[3]; - if (cu->flag & CU_DEFORM_BOUNDS_OFF) { - dvert = me->dvert; - for (a = 0; a < numVerts; a++, dvert++) { - if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); - weight = defvert_find_weight(dvert, defgrp_index); - - if (weight > 0.0f) { - mul_m4_v3(cd.curvespace, vertexCos[a]); - copy_v3_v3(vec, vertexCos[a]); - calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); - interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); - mul_m4_v3(cd.objectspace, vertexCos[a]); - } + if (cu->flag & CU_DEFORM_BOUNDS_OFF) { + for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) { + const float weight = defvert_find_weight(dvert_iter, defgrp_index); + + if (weight > 0.0f) { + mul_m4_v3(cd.curvespace, vertexCos[a]); + copy_v3_v3(vec, vertexCos[a]); + calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); + interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); + mul_m4_v3(cd.objectspace, vertexCos[a]); } } - else { - /* set mesh min/max bounds */ - INIT_MINMAX(cd.dmin, cd.dmax); - - for (a = 0; a < numVerts; a++, dvert++) { - if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); - - if (defvert_find_weight(dvert, defgrp_index) > 0.0f) { - mul_m4_v3(cd.curvespace, vertexCos[a]); - minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]); - } + } + else { + /* set mesh min/max bounds */ + INIT_MINMAX(cd.dmin, cd.dmax); + + for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) { + if (defvert_find_weight(dvert_iter, defgrp_index) > 0.0f) { + mul_m4_v3(cd.curvespace, vertexCos[a]); + minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]); } - - dvert = me->dvert; - for (a = 0; a < numVerts; a++, dvert++) { - if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); - - weight = defvert_find_weight(dvert, defgrp_index); - - if (weight > 0.0f) { - /* already in 'cd.curvespace', prev for loop */ - copy_v3_v3(vec, vertexCos[a]); - calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); - interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); - mul_m4_v3(cd.objectspace, vertexCos[a]); - } + } + + for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) { + const float weight = defvert_find_weight(dvert_iter, defgrp_index); + + if (weight > 0.0f) { + /* already in 'cd.curvespace', prev for loop */ + copy_v3_v3(vec, vertexCos[a]); + calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); + interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight); + mul_m4_v3(cd.objectspace, vertexCos[a]); } } } @@ -1166,6 +1155,28 @@ void BKE_lattice_center_bounds(Lattice *lt, float cent[3]) mid_v3_v3v3(cent, min, max); } +void BKE_lattice_transform(Lattice *lt, float mat[4][4], bool do_keys) +{ + BPoint *bp = lt->def; + int i = lt->pntsu * lt->pntsv * lt->pntsw; + + while (i--) { + mul_m4_v3(mat, bp->vec); + bp++; + } + + if (do_keys && lt->key) { + KeyBlock *kb; + + for (kb = lt->key->block.first; kb; kb = kb->next) { + float *fp = kb->data; + for (i = kb->totelem; i--; fp += 3) { + mul_m4_v3(mat, fp); + } + } + } +} + void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys) { int i, numVerts; diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 1f3327b0dc4..515287de336 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -104,6 +104,7 @@ #include "BKE_mask.h" #include "BKE_node.h" #include "BKE_object.h" +#include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_packedFile.h" #include "BKE_speaker.h" @@ -382,7 +383,7 @@ bool id_copy(ID *id, ID **newid, bool test) if (!test) *newid = (ID *)BKE_mask_copy((Mask *)id); return true; case ID_LS: - if (!test) *newid = (ID *)BKE_copy_linestyle((FreestyleLineStyle *)id); + if (!test) *newid = (ID *)BKE_linestyle_copy((FreestyleLineStyle *)id); return true; } @@ -515,6 +516,10 @@ ListBase *which_libbase(Main *mainlib, short type) return &(mainlib->mask); case ID_LS: return &(mainlib->linestyle); + case ID_PAL: + return &(mainlib->palettes); + case ID_PC: + return &(mainlib->paintcurves); } return NULL; } @@ -596,6 +601,8 @@ int set_listbasepointers(Main *main, ListBase **lb) lb[a++] = &(main->text); lb[a++] = &(main->sound); lb[a++] = &(main->group); + lb[a++] = &(main->palettes); + lb[a++] = &(main->paintcurves); lb[a++] = &(main->brush); lb[a++] = &(main->script); lb[a++] = &(main->particle); @@ -731,6 +738,12 @@ static ID *alloc_libblock_notest(short type) case ID_LS: id = MEM_callocN(sizeof(FreestyleLineStyle), "Freestyle Line Style"); break; + case ID_PAL: + id = MEM_callocN(sizeof(Palette), "Palette"); + break; + case ID_PC: + id = MEM_callocN(sizeof(PaintCurve), "Paint Curve"); + break; } return id; } @@ -1005,7 +1018,13 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user) BKE_mask_free(bmain, (Mask *)id); break; case ID_LS: - BKE_free_linestyle((FreestyleLineStyle *)id); + BKE_linestyle_free((FreestyleLineStyle *)id); + break; + case ID_PAL: + BKE_palette_free((Palette *)id); + break; + case ID_PC: + BKE_paint_curve_free((PaintCurve *)id); break; } @@ -1131,14 +1150,17 @@ void BKE_main_unlock(struct Main *bmain) } /* ***************** ID ************************ */ - - -ID *BKE_libblock_find_name(const short type, const char *name) /* type: "OB" or "MA" etc */ +ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) { - ListBase *lb = which_libbase(G.main, type); + ListBase *lb = which_libbase(bmain, type); BLI_assert(lb != NULL); return BLI_findstring(lb, name, offsetof(ID, name) + 2); } +ID *BKE_libblock_find_name(const short type, const char *name) +{ + return BKE_libblock_find_name_ex(G.main, type, name); +} + void id_sort_by_name(ListBase *lb, ID *id) { diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index d92fa328e87..45695844101 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -43,6 +43,8 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BKE_context.h" +#include "BKE_freestyle.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_linestyle.h" @@ -51,6 +53,8 @@ #include "BKE_colortools.h" #include "BKE_animsys.h" +#include "RNA_access.h" + static const char *modifier_name[LS_MODIFIER_NUM] = { NULL, "Along Stroke", @@ -99,12 +103,12 @@ static void default_linestyle_settings(FreestyleLineStyle *linestyle) BLI_listbase_clear(&linestyle->thickness_modifiers); BLI_listbase_clear(&linestyle->geometry_modifiers); - BKE_add_linestyle_geometry_modifier(linestyle, NULL, LS_MODIFIER_SAMPLING); + BKE_linestyle_geometry_modifier_add(linestyle, NULL, LS_MODIFIER_SAMPLING); linestyle->caps = LS_CAPS_BUTT; } -FreestyleLineStyle *BKE_new_linestyle(const char *name, struct Main *main) +FreestyleLineStyle *BKE_linestyle_new(const char *name, struct Main *main) { FreestyleLineStyle *linestyle; @@ -118,7 +122,7 @@ FreestyleLineStyle *BKE_new_linestyle(const char *name, struct Main *main) return linestyle; } -void BKE_free_linestyle(FreestyleLineStyle *linestyle) +void BKE_linestyle_free(FreestyleLineStyle *linestyle) { LineStyleModifier *m; @@ -137,33 +141,33 @@ void BKE_free_linestyle(FreestyleLineStyle *linestyle) BKE_free_animdata(&linestyle->id); while ((m = (LineStyleModifier *)linestyle->color_modifiers.first)) - BKE_remove_linestyle_color_modifier(linestyle, m); + BKE_linestyle_color_modifier_remove(linestyle, m); while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first)) - BKE_remove_linestyle_alpha_modifier(linestyle, m); + BKE_linestyle_alpha_modifier_remove(linestyle, m); while ((m = (LineStyleModifier *)linestyle->thickness_modifiers.first)) - BKE_remove_linestyle_thickness_modifier(linestyle, m); + BKE_linestyle_thickness_modifier_remove(linestyle, m); while ((m = (LineStyleModifier *)linestyle->geometry_modifiers.first)) - BKE_remove_linestyle_geometry_modifier(linestyle, m); + BKE_linestyle_geometry_modifier_remove(linestyle, m); } -FreestyleLineStyle *BKE_copy_linestyle(FreestyleLineStyle *linestyle) +FreestyleLineStyle *BKE_linestyle_copy(FreestyleLineStyle *linestyle) { FreestyleLineStyle *new_linestyle; LineStyleModifier *m; int a; - new_linestyle = BKE_new_linestyle(linestyle->id.name + 2, NULL); - BKE_free_linestyle(new_linestyle); + new_linestyle = BKE_linestyle_new(linestyle->id.name + 2, NULL); + BKE_linestyle_free(new_linestyle); for (a = 0; a < MAX_MTEX; a++) { if (linestyle->mtex[a]) { - new_linestyle->mtex[a] = MEM_mallocN(sizeof(MTex), "BKE_copy_linestyle"); + new_linestyle->mtex[a] = MEM_mallocN(sizeof(MTex), "BKE_linestyle_copy"); memcpy(new_linestyle->mtex[a], linestyle->mtex[a], sizeof(MTex)); id_us_plus((ID *)new_linestyle->mtex[a]->tex); } } if (linestyle->nodetree) { - linestyle->nodetree = ntreeCopyTree(linestyle->nodetree); + new_linestyle->nodetree = ntreeCopyTree(linestyle->nodetree); } new_linestyle->r = linestyle->r; @@ -198,17 +202,29 @@ FreestyleLineStyle *BKE_copy_linestyle(FreestyleLineStyle *linestyle) new_linestyle->texstep = linestyle->texstep; new_linestyle->pr_texture = linestyle->pr_texture; for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) - BKE_copy_linestyle_color_modifier(new_linestyle, m); + BKE_linestyle_color_modifier_copy(new_linestyle, m); for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next) - BKE_copy_linestyle_alpha_modifier(new_linestyle, m); + BKE_linestyle_alpha_modifier_copy(new_linestyle, m); for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next) - BKE_copy_linestyle_thickness_modifier(new_linestyle, m); + BKE_linestyle_thickness_modifier_copy(new_linestyle, m); for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next) - BKE_copy_linestyle_geometry_modifier(new_linestyle, m); + BKE_linestyle_geometry_modifier_copy(new_linestyle, m); return new_linestyle; } +FreestyleLineStyle *BKE_linestyle_active_from_scene(Scene *scene) +{ + SceneRenderLayer *actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay); + FreestyleConfig *config = &actsrl->freestyleConfig; + FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config); + + if (lineset) { + return lineset->linestyle; + } + return NULL; +} + static LineStyleModifier *new_modifier(const char *name, int type, size_t size) { LineStyleModifier *m; @@ -255,7 +271,7 @@ static LineStyleModifier *alloc_color_modifier(const char *name, int type) return new_modifier(name, type, size); } -LineStyleModifier *BKE_add_linestyle_color_modifier(FreestyleLineStyle *linestyle, const char *name, int type) +LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type) { LineStyleModifier *m; @@ -289,7 +305,7 @@ LineStyleModifier *BKE_add_linestyle_color_modifier(FreestyleLineStyle *linestyl return m; } -LineStyleModifier *BKE_copy_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m) +LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m) { LineStyleModifier *new_m; @@ -344,7 +360,7 @@ LineStyleModifier *BKE_copy_linestyle_color_modifier(FreestyleLineStyle *linesty return new_m; } -int BKE_remove_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m) +int BKE_linestyle_color_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *m) { if (BLI_findindex(&linestyle->color_modifiers, m) == -1) return -1; @@ -389,7 +405,7 @@ static LineStyleModifier *alloc_alpha_modifier(const char *name, int type) return new_modifier(name, type, size); } -LineStyleModifier *BKE_add_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, const char *name, int type) +LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type) { LineStyleModifier *m; @@ -435,7 +451,7 @@ LineStyleModifier *BKE_add_linestyle_alpha_modifier(FreestyleLineStyle *linestyl return m; } -LineStyleModifier *BKE_copy_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m) +LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m) { LineStyleModifier *new_m; @@ -493,7 +509,7 @@ LineStyleModifier *BKE_copy_linestyle_alpha_modifier(FreestyleLineStyle *linesty return new_m; } -int BKE_remove_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m) +int BKE_linestyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *m) { if (BLI_findindex(&linestyle->alpha_modifiers, m) == -1) return -1; @@ -542,7 +558,7 @@ static LineStyleModifier *alloc_thickness_modifier(const char *name, int type) return new_modifier(name, type, size); } -LineStyleModifier *BKE_add_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, const char *name, int type) +LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type) { LineStyleModifier *m; @@ -604,7 +620,7 @@ LineStyleModifier *BKE_add_linestyle_thickness_modifier(FreestyleLineStyle *line return m; } -LineStyleModifier *BKE_copy_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m) +LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m) { LineStyleModifier *new_m; @@ -681,7 +697,7 @@ LineStyleModifier *BKE_copy_linestyle_thickness_modifier(FreestyleLineStyle *lin return new_m; } -int BKE_remove_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m) +int BKE_linestyle_thickness_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *m) { if (BLI_findindex(&linestyle->thickness_modifiers, m) == -1) return -1; @@ -756,7 +772,7 @@ static LineStyleModifier *alloc_geometry_modifier(const char *name, int type) return new_modifier(name, type, size); } -LineStyleModifier *BKE_add_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, const char *name, int type) +LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type) { LineStyleModifier *m; @@ -874,7 +890,7 @@ LineStyleModifier *BKE_add_linestyle_geometry_modifier(FreestyleLineStyle *lines return m; } -LineStyleModifier *BKE_copy_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m) +LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m) { LineStyleModifier *new_m; @@ -1008,7 +1024,7 @@ LineStyleModifier *BKE_copy_linestyle_geometry_modifier(FreestyleLineStyle *line return new_m; } -int BKE_remove_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m) +int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *m) { if (BLI_findindex(&linestyle->geometry_modifiers, m) == -1) return -1; @@ -1025,27 +1041,27 @@ static void move_modifier(ListBase *lb, LineStyleModifier *modifier, int directi BLI_insertlinkafter(lb, modifier->next, modifier); } -void BKE_move_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction) +void BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction) { move_modifier(&linestyle->color_modifiers, modifier, direction); } -void BKE_move_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction) +void BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction) { move_modifier(&linestyle->alpha_modifiers, modifier, direction); } -void BKE_move_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction) +void BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction) { move_modifier(&linestyle->thickness_modifiers, modifier, direction); } -void BKE_move_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction) +void BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction) { move_modifier(&linestyle->geometry_modifiers, modifier, direction); } -void BKE_list_modifier_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase) +void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase) { LineStyleModifier *m; ColorBand *color_ramp; @@ -1076,7 +1092,7 @@ void BKE_list_modifier_color_ramps(FreestyleLineStyle *linestyle, ListBase *list } } -char *BKE_path_from_ID_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand *color_ramp) +char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand *color_ramp) { LineStyleModifier *m; bool found = false; @@ -1107,11 +1123,11 @@ char *BKE_path_from_ID_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand *c return BLI_sprintfN("color_modifiers[\"%s\"].color_ramp", name_esc); } } - printf("BKE_path_from_ID_to_color_ramp: No color ramps correspond to the given pointer.\n"); + printf("BKE_linestyle_path_to_color_ramp: No color ramps correspond to the given pointer.\n"); return NULL; } -void BKE_unlink_linestyle_target_object(FreestyleLineStyle *linestyle, struct Object *ob) +void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob) { LineStyleModifier *m; @@ -1137,3 +1153,64 @@ void BKE_unlink_linestyle_target_object(FreestyleLineStyle *linestyle, struct Ob } } } + +bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes) +{ + if (use_shading_nodes) { + if (linestyle && linestyle->use_nodes && linestyle->nodetree) { + bNode *node; + + for (node = linestyle->nodetree->nodes.first; node; node = node->next) { + if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) { + return true; + } + } + } + } + else { + if (linestyle && (linestyle->flag & LS_TEXTURE)) { + return (linestyle->mtex[0] != NULL); + } + } + return false; +} + +void BKE_linestyle_default_shader(const bContext *C, FreestyleLineStyle *linestyle) +{ + bNode *uv_along_stroke, *input_texure, *output_linestyle; + bNodeSocket *fromsock, *tosock; + bNodeTree *ntree; + + BLI_assert(linestyle->nodetree == NULL); + + ntree = ntreeAddTree(NULL, "stroke_shader", "ShaderNodeTree"); + + linestyle->nodetree = ntree; + + uv_along_stroke = nodeAddStaticNode(C, ntree, SH_NODE_UVALONGSTROKE); + uv_along_stroke->locx = 0.0f; + uv_along_stroke->locy = 300.0f; + uv_along_stroke->custom1 = 0; // use_tips + + input_texure = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE); + input_texure->locx = 200.0f; + input_texure->locy = 300.0f; + + output_linestyle = nodeAddStaticNode(C, ntree, SH_NODE_OUTPUT_LINESTYLE); + output_linestyle->locx = 400.0f; + output_linestyle->locy = 300.0f; + output_linestyle->custom1 = MA_RAMP_BLEND; + output_linestyle->custom2 = 0; // use_clamp + + nodeSetActive(ntree, input_texure); + + fromsock = BLI_findlink(&uv_along_stroke->outputs, 0); // UV + tosock = BLI_findlink(&input_texure->inputs, 0); // UV + nodeAddLink(ntree, uv_along_stroke, fromsock, input_texure, tosock); + + fromsock = BLI_findlink(&input_texure->outputs, 0); // Color + tosock = BLI_findlink(&output_linestyle->inputs, 0); // Color + nodeAddLink(ntree, input_texure, fromsock, output_linestyle, tosock); + + ntreeUpdateTree(CTX_data_main(C), ntree); +} diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 4147750c356..1c40446c217 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -1212,7 +1212,7 @@ void BKE_mask_point_parent_matrix_get(MaskSplinePoint *point, float ctime, float } 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); + mul_m3_series(parent_matrix, mask_from_clip_matrix, H, mask_to_clip_matrix); } } } diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index 35207595103..4dc8ed21463 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -326,7 +326,7 @@ static void maskrasterize_spline_differentiate_point_outset(float (*diff_feather * are to any of the triangle edges. */ static bool layer_bucket_isect_test( - MaskRasterLayer *layer, unsigned int face_index, + const MaskRasterLayer *layer, unsigned int face_index, const unsigned int bucket_x, const unsigned int bucket_y, const float bucket_size_x, const float bucket_size_y, const float bucket_max_rad_squared) diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 971db1997de..eeca60f7ef4 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -63,6 +63,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" +#include "BKE_scene.h" #include "BKE_node.h" #include "BKE_curve.h" @@ -111,6 +112,9 @@ void BKE_material_free_ex(Material *ma, bool do_id_user) MEM_freeN(ma->nodetree); } + if (ma->texpaintslot) + MEM_freeN(ma->texpaintslot); + if (ma->gpumaterial.first) GPU_material_free(ma); } @@ -269,7 +273,8 @@ Material *localize_material(Material *ma) if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col); if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec); - + + man->texpaintslot = NULL; man->preview = NULL; if (ma->nodetree) @@ -467,7 +472,7 @@ Material ***give_matarar(Object *ob) me = ob->data; return &(me->mat); } - else if (ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { + else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { cu = ob->data; return &(cu->mat); } @@ -488,7 +493,7 @@ short *give_totcolp(Object *ob) me = ob->data; return &(me->totcol); } - else if (ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { + else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { cu = ob->data; return &(cu->totcol); } @@ -1291,7 +1296,7 @@ bool object_remove_material_slot(Object *ob) } /* check indices from mesh */ - if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { material_data_index_remove_id((ID *)ob->data, actcol - 1); if (ob->curve_cache) { BKE_displist_free(&ob->curve_cache->disp); @@ -1301,6 +1306,124 @@ bool object_remove_material_slot(Object *ob) return true; } +static bool get_mtex_slot_valid_texpaint(struct MTex *mtex) +{ + return (mtex && (mtex->texco == TEXCO_UV) && + mtex->tex && (mtex->tex->type == TEX_IMAGE) && + mtex->tex->ima); +} + +void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma) +{ + MTex **mtex; + short count = 0; + short index = 0, i; + + bool use_nodes = BKE_scene_use_new_shading_nodes(scene); + bool is_bi = BKE_scene_uses_blender_internal(scene); + + if (!ma) + return; + + if (ma->texpaintslot) { + MEM_freeN(ma->texpaintslot); + ma->tot_slots = 0; + ma->texpaintslot = NULL; + } + + if (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_IMAGE) { + ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; + return; + } + + if (use_nodes || ma->use_nodes) { + bNode *node, *active_node; + + if (!(ma->nodetree)) { + ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; + return; + } + + for (node = ma->nodetree->nodes.first; node; node = node->next) { + if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) + count++; + } + + if (count == 0) { + ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; + return; + } + ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); + + active_node = nodeGetActiveTexture(ma->nodetree); + + for (node = ma->nodetree->nodes.first; node; node = node->next) { + if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) { + if (active_node == node) + ma->paint_active_slot = index; + ma->texpaintslot[index++].ima = (Image *)node->id; + } + } + } + else if (is_bi) { + for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) { + if (get_mtex_slot_valid_texpaint(*mtex)) { + count++; + } + } + + if (count == 0) { + ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; + return; + } + + ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); + + for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) { + if (get_mtex_slot_valid_texpaint(*mtex)) { + ma->texpaintslot[index].ima = (*mtex)->tex->ima; + ma->texpaintslot[index].uvname = (*mtex)->uvname; + ma->texpaintslot[index].index = i; + + index++; + } + } + } + else { + ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; + return; + } + + + ma->tot_slots = count; + + + if (ma->paint_active_slot >= count) { + ma->paint_active_slot = count - 1; + } + + if (ma->paint_clone_slot >= count) { + ma->paint_clone_slot = count - 1; + } + + return; +} + +void BKE_texpaint_slots_refresh_object(Scene *scene, struct Object *ob) +{ + int i; + + for (i = 1; i < ob->totcol + 1; i++) { + Material *ma = give_current_material(ob, i); + BKE_texpaint_slot_refresh_cache(scene, ma); + } +} + /* r_col = current value, col = new value, (fac == 0) is no change */ void ramp_blend(int type, float r_col[3], const float fac, const float col[3]) @@ -1573,7 +1696,7 @@ void copy_matcopybuf(Material *ma) matcopybuf.mtex[a] = MEM_dupallocN(mtex); } } - matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, false); + matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, G.main, false); matcopybuf.preview = NULL; BLI_listbase_clear(&matcopybuf.gpumaterial); matcopied = 1; @@ -1626,7 +1749,7 @@ void paste_matcopybuf(Material *ma) } } - ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, false); + ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, G.main, false); } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 43b19f0c869..453c6df6e3b 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -491,10 +491,7 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object) BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.'); - /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */ - if (F_ERROR == BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL)) - return; - + BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { if (ob->type == OB_MBALL) { if (ob != active_object) { @@ -537,23 +534,17 @@ Object *BKE_mball_basis_find(Scene *scene, Object *basis) BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.'); - /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */ - if (F_ERROR == BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL)) - return NULL; - + BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { - if (ob->type == OB_MBALL) { + if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) { if (ob != bob) { BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); - /* object ob has to be in same "group" ... it means, that it has to have - * same base of its name */ + /* object ob has to be in same "group" ... it means, that it has to have same base of its name */ if (strcmp(obname, basisname) == 0) { if (obnr < basisnr) { - if (!(ob->flag & OB_FROMDUPLI)) { - basis = ob; - basisnr = obnr; - } + basis = ob; + basisnr = obnr; } } } @@ -2227,10 +2218,7 @@ static void mball_count(EvaluationContext *eval_ctx, PROCESS *process, Scene *sc BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.'); process->totelem = 0; - /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */ - if (F_ERROR == BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL)) - return; - + BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { if (ob->type == OB_MBALL) { if (ob == bob) { @@ -2454,6 +2442,30 @@ bool BKE_mball_center_bounds(MetaBall *mb, float r_cent[3]) return 0; } +void BKE_mball_transform(MetaBall *mb, float mat[4][4]) +{ + MetaElem *me; + float quat[4]; + const float scale = mat4_to_scale(mat); + const float scale_sqrt = sqrtf(scale); + + mat4_to_quat(quat, mat); + + for (me = mb->elems.first; me; me = me->next) { + mul_m4_v3(mat, &me->x); + mul_qt_qtqt(me->quat, quat, me->quat); + me->rad *= scale; + /* hrmf, probably elems shouldn't be + * treating scale differently - campbell */ + if (!MB_TYPE_SIZE_SQUARED(me->type)) { + mul_v3_fl(&me->expx, scale); + } + else { + mul_v3_fl(&me->expx, scale_sqrt); + } + } +} + void BKE_mball_translate(MetaBall *mb, const float offset[3]) { MetaElem *ml; diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 2bf33b97a70..2e80379522c 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -115,16 +115,16 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2 int i, i1 = 0, i2 = 0, tot, j; for (i = 0; i < c1->totlayer; i++) { - if (ELEM7(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + if (ELEM(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, + CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) { i1++; } } for (i = 0; i < c2->totlayer; i++) { - if (ELEM7(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + if (ELEM(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, + CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) { i2++; } @@ -135,16 +135,16 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2 l1 = c1->layers; l2 = c2->layers; tot = i1; - i1 = 0; i2 = 0; + i1 = 0; i2 = 0; for (i = 0; i < tot; i++) { - while (i1 < c1->totlayer && !ELEM7(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + while (i1 < c1->totlayer && !ELEM(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, + CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) { i1++, l1++; } - while (i2 < c2->totlayer && !ELEM7(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + while (i2 < c2->totlayer && !ELEM(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, + CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) { i2++, l2++; } @@ -1869,6 +1869,27 @@ bool BKE_mesh_minmax(Mesh *me, float r_min[3], float r_max[3]) return (me->totvert != 0); } +void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys) +{ + int i; + MVert *mvert = me->mvert; + + for (i = 0; i < me->totvert; i++, mvert++) + mul_m4_v3(mat, mvert->co); + + if (do_keys && me->key) { + KeyBlock *kb; + for (kb = me->key->block.first; kb; kb = kb->next) { + float *fp = kb->data; + for (i = kb->totelem; i--; fp += 3) { + mul_m4_v3(mat, fp); + } + } + } + + /* don't update normals, caller can do this explicitly */ +} + void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) { int i = me->totvert; @@ -2041,7 +2062,7 @@ int BKE_mesh_mselect_find(Mesh *me, int index, int type) { int i; - BLI_assert(ELEM3(type, ME_VSEL, ME_ESEL, ME_FSEL)); + BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL)); for (i = 0; i < me->totselect; i++) { if ((me->mselect[i].index == index) && @@ -2059,7 +2080,7 @@ int BKE_mesh_mselect_find(Mesh *me, int index, int type) */ int BKE_mesh_mselect_active_get(Mesh *me, int type) { - BLI_assert(ELEM3(type, ME_VSEL, ME_ESEL, ME_FSEL)); + BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL)); if (me->totselect) { if (me->mselect[me->totselect - 1].type == type) { diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index cb0386b1203..4c9e44682c3 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -567,6 +567,10 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg copy_v3_v3(nor, lnor); } } + else { + /* We still have to clear the stack! */ + while (BLI_SMALLSTACK_POP(normal)); + } } ml_prev = ml_curr; @@ -574,8 +578,6 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg } } - BLI_SMALLSTACK_FREE(normal); - MEM_freeN(edge_to_loops); MEM_freeN(loop_to_poly); @@ -729,7 +731,7 @@ void BKE_mesh_loop_tangents(Mesh *mesh, const char *uvmap, float (*r_looptangent } BKE_mesh_loop_tangents_ex(mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents, - loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports); + loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports); } /** \} */ @@ -1096,6 +1098,125 @@ bool BKE_mesh_center_centroid(Mesh *me, float cent[3]) /* -------------------------------------------------------------------- */ +/** \name Mesh Volume Calculation + * \{ */ + +static bool mesh_calc_center_centroid_ex(MVert *mverts, int UNUSED(numVerts), + MFace *mfaces, int numFaces, + float center[3]) +{ + float totweight; + int f; + + zero_v3(center); + + if (numFaces == 0) + return false; + + totweight = 0.0f; + for (f = 0; f < numFaces; ++f) { + MFace *face = &mfaces[f]; + MVert *v1 = &mverts[face->v1]; + MVert *v2 = &mverts[face->v2]; + MVert *v3 = &mverts[face->v3]; + MVert *v4 = &mverts[face->v4]; + float area; + + area = area_tri_v3(v1->co, v2->co, v3->co); + madd_v3_v3fl(center, v1->co, area); + madd_v3_v3fl(center, v2->co, area); + madd_v3_v3fl(center, v3->co, area); + totweight += area; + + if (face->v4) { + area = area_tri_v3(v3->co, v4->co, v1->co); + madd_v3_v3fl(center, v3->co, area); + madd_v3_v3fl(center, v4->co, area); + madd_v3_v3fl(center, v1->co, area); + totweight += area; + } + } + if (totweight == 0.0f) + return false; + + mul_v3_fl(center, 1.0f / (3.0f * totweight)); + + return true; +} + +void BKE_mesh_calc_volume(MVert *mverts, int numVerts, + MFace *mfaces, int numFaces, + float *r_vol, float *r_com) +{ + float center[3]; + float totvol; + int f; + + if (r_vol) *r_vol = 0.0f; + if (r_com) zero_v3(r_com); + + if (numFaces == 0) + return; + + if (!mesh_calc_center_centroid_ex(mverts, numVerts, mfaces, numFaces, center)) + return; + + totvol = 0.0f; + for (f = 0; f < numFaces; ++f) { + MFace *face = &mfaces[f]; + MVert *v1 = &mverts[face->v1]; + MVert *v2 = &mverts[face->v2]; + MVert *v3 = &mverts[face->v3]; + MVert *v4 = &mverts[face->v4]; + float vol; + + vol = volume_tetrahedron_signed_v3(center, v1->co, v2->co, v3->co); + if (r_vol) { + totvol += vol; + } + if (r_com) { + /* averaging factor 1/4 is applied in the end */ + madd_v3_v3fl(r_com, center, vol); // XXX could extract this + madd_v3_v3fl(r_com, v1->co, vol); + madd_v3_v3fl(r_com, v2->co, vol); + madd_v3_v3fl(r_com, v3->co, vol); + } + + if (face->v4) { + vol = volume_tetrahedron_signed_v3(center, v3->co, v4->co, v1->co); + + if (r_vol) { + totvol += vol; + } + if (r_com) { + /* averaging factor 1/4 is applied in the end */ + madd_v3_v3fl(r_com, center, vol); // XXX could extract this + madd_v3_v3fl(r_com, v3->co, vol); + madd_v3_v3fl(r_com, v4->co, vol); + madd_v3_v3fl(r_com, v1->co, vol); + } + } + } + + /* Note: Depending on arbitrary centroid position, + * totvol can become negative even for a valid mesh. + * The true value is always the positive value. + */ + if (r_vol) { + *r_vol = fabsf(totvol); + } + if (r_com) { + /* Note: Factor 1/4 is applied once for all vertices here. + * This also automatically negates the vector if totvol is negative. + */ + if (totvol != 0.0f) + mul_v3_fl(r_com, 0.25f / totvol); + } +} + + +/* -------------------------------------------------------------------- */ + /** \name NGon Tessellation (NGon/Tessface Conversion) * \{ */ @@ -2110,11 +2231,10 @@ void BKE_mesh_calc_relative_deform( 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] - ); + transform_point_by_tri_v3( + 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; diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c index 65c576dd6a0..82065750791 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.c +++ b/source/blender/blenkernel/intern/mesh_mapping.c @@ -442,7 +442,7 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge, /* 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) && + if (!ELEM(bit, 0, poly_group_id, poly_group_id_overflowed) && !(bit_poly_group_mask & bit)) { bit_poly_group_mask |= bit; diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index 858fe83b43f..f3a9e894eb3 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -164,16 +164,20 @@ static int search_poly_cmp(const void *v1, const void *v2) { const SortPoly *sp1 = v1, *sp2 = v2; const int max_idx = sp1->numverts > sp2->numverts ? sp2->numverts : sp1->numverts; - int idx = 0; + int idx; /* Reject all invalid polys at end of list! */ if (sp1->invalid || sp2->invalid) - return sp1->invalid && sp2->invalid ? 0 : sp1->invalid ? 1 : -1; - /* Else, sort on first non-egal verts (remember verts of valid polys are sorted). */ - while (idx < max_idx && sp1->verts[idx] == sp2->verts[idx]) - idx++; - return sp1->verts[idx] > sp2->verts[idx] ? 1 : sp1->verts[idx] < sp2->verts[idx] ? -1 : - sp1->numverts > sp2->numverts ? 1 : sp1->numverts < sp2->numverts ? -1 : 0; + return sp1->invalid ? (sp2->invalid ? 0 : 1) : -1; + /* Else, sort on first non-equal verts (remember verts of valid polys are sorted). */ + for (idx = 0; idx < max_idx; idx++) { + const int v1 = sp1->verts[idx]; + const int v2 = sp2->verts[idx]; + if (v1 != v2) { + return (v1 > v2) ? 1 : -1; + } + } + return sp1->numverts > sp2->numverts ? 1 : sp1->numverts < sp2->numverts ? -1 : 0; } static int search_polyloop_cmp(const void *v1, const void *v2) @@ -255,7 +259,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, do_edge_recalc = do_fixes; } - for (i = 1; i < totvert; i++, mv++) { + for (i = 0; i < totvert; i++, mv++) { bool fix_normal = true; for (j = 0; j < 3; j++) { @@ -498,8 +502,9 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, PRINT_ERR("\tLoop %u has invalid vert reference (%u)\n", sp->loopstart + j, ml->v); sp->invalid = true; } - - mverts[ml->v].flag |= ME_VERT_TMP_TAG; + else { + mverts[ml->v].flag |= ME_VERT_TMP_TAG; + } *v = ml->v; } @@ -909,8 +914,6 @@ static bool mesh_validate_customdata(CustomData *data, CustomDataMask mask, return is_valid; } -#undef PRINT - /** * \returns is_valid. */ @@ -1052,8 +1055,36 @@ void BKE_mesh_cd_validate(Mesh *me) } } } -/** \} */ +/** + * Check all material indices of polygons are valid, invalid ones are set to 0. + * \returns is_valid. + */ +int BKE_mesh_validate_material_indices(Mesh *me) +{ + MPoly *mp; + const int max_idx = max_ii(0, me->totcol - 1); + const int totpoly = me->totpoly; + int i; + bool is_valid = true; + + for (mp = me->mpoly, i = 0; i < totpoly; i++, mp++) { + if (mp->mat_nr > max_idx) { + mp->mat_nr = 0; + is_valid = false; + } + } + + if (!is_valid) { + DAG_id_tag_update(&me->id, OB_RECALC_DATA); + return true; + } + else { + return false; + } +} + +/** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 1c42603cf4a..a9e853c873e 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -171,11 +171,14 @@ bool modifier_isPreview(ModifierData *md) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!(mti->flags & eModifierTypeFlag_UsesPreview)) + /* Constructive modifiers are highly likely to also modify data like vgroups or vcol! */ + if (!((mti->flags & eModifierTypeFlag_UsesPreview) || (mti->type == eModifierTypeType_Constructive))) { return false; + } - if (md->mode & eModifierMode_Realtime) + if (md->mode & eModifierMode_Realtime) { return true; + } return false; } @@ -350,6 +353,7 @@ int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *r_lastPossibleC /* Find the last modifier acting on the cage. */ for (i = 0; md; i++, md = md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); + bool supports_mapping; md->scene = scene; @@ -357,16 +361,17 @@ int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *r_lastPossibleC if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue; if (md->mode & eModifierMode_DisableTemporary) continue; + supports_mapping = modifier_supportsMapping(md); + if (r_lastPossibleCageIndex && supports_mapping) { + *r_lastPossibleCageIndex = i; + } + if (!(md->mode & eModifierMode_Realtime)) continue; if (!(md->mode & eModifierMode_Editmode)) continue; - if (!modifier_supportsMapping(md)) + if (!supports_mapping) break; - if (r_lastPossibleCageIndex) { - *r_lastPossibleCageIndex = i; - } - if (md->mode & eModifierMode_OnCage) cageIndex = i; } @@ -409,13 +414,12 @@ bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode md->scene = scene; - if ((md->mode & required_mode) != required_mode) return 0; - if (mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return 0; - if (md->mode & eModifierMode_DisableTemporary) return 0; - if (required_mode & eModifierMode_Editmode) - if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) return 0; + if ((md->mode & required_mode) != required_mode) return false; + if (mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return false; + if (md->mode & eModifierMode_DisableTemporary) return false; + if ((required_mode & eModifierMode_Editmode) && !(mti->flags & eModifierTypeFlag_SupportsEditmode)) return false; - return 1; + return true; } CDMaskLink *modifiers_calcDataMasks(struct Scene *scene, Object *ob, ModifierData *md, diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 1d5bbbe1aeb..246ef8a33f5 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -112,7 +112,7 @@ static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden, /* assumed to be at hi_level (or * null) */ - BLI_bitmap *prev_hidden) + const BLI_bitmap *prev_hidden) { BLI_bitmap *subd; int hi_gridsize = BKE_ccg_gridsize(hi_level); diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index d0114d52a06..19e45142960 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -430,7 +430,7 @@ static float nlastrip_get_frame_actionclip(NlaStrip *strip, float cframe, short return (strip->end + (strip->actstart * scale - cframe)) / scale; } else { /* if (mode == NLATIME_CONVERT_EVAL) */ - if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, ((int)strip->repeat))) { + if (IS_EQF((float)cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) { /* this case prevents the motion snapping back to the first frame at the end of the strip * by catching the case where repeats is a whole number, which means that the end of the strip * could also be interpreted as the end of the start of a repeat @@ -453,7 +453,7 @@ static float nlastrip_get_frame_actionclip(NlaStrip *strip, float cframe, short return strip->actstart + (cframe - strip->start) / scale; } else { /* if (mode == NLATIME_CONVERT_EVAL) */ - if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, ((int)strip->repeat))) { + if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) { /* this case prevents the motion snapping back to the first frame at the end of the strip * by catching the case where repeats is a whole number, which means that the end of the strip * could also be interpreted as the end of the start of a repeat @@ -1637,7 +1637,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt) } } - if (ELEM3(NULL, activeTrack, activeStrip, activeStrip->act)) { + if (ELEM(NULL, activeTrack, activeStrip, activeStrip->act)) { if (G.debug & G_DEBUG) { printf("NLA tweakmode enter - neither active requirement found\n"); printf("\tactiveTrack = %p, activeStrip = %p\n", (void *)activeTrack, (void *)activeStrip); @@ -1744,7 +1744,7 @@ static void UNUSED_FUNCTION(BKE_nla_bake) (Scene *scene, ID *UNUSED(id), AnimDat * 1) Scene and AnimData must be provided * 2) there must be tracks to merge... */ - if (ELEM3(NULL, scene, adt, adt->nla_tracks.first)) + if (ELEM(NULL, scene, adt, adt->nla_tracks.first)) return; /* if animdata currently has an action, 'push down' this onto the stack first */ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 56a76a54955..0f86b551092 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1205,13 +1205,13 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_ return newtree; } -bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, const bool do_id_user) +bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, Main *bmain, const bool do_id_user) { - return ntreeCopyTree_internal(ntree, G.main, do_id_user, true, true); + return ntreeCopyTree_internal(ntree, bmain, do_id_user, true, true); } bNodeTree *ntreeCopyTree(bNodeTree *ntree) { - return ntreeCopyTree_ex(ntree, true); + return ntreeCopyTree_ex(ntree, G.main, true); } /* use when duplicating scenes */ @@ -3406,6 +3406,7 @@ static void registerCompositNodes(void) register_node_type_cmp_inpaint(); register_node_type_cmp_despeckle(); register_node_type_cmp_defocus(); + register_node_type_cmp_sunbeams(); register_node_type_cmp_valtorgb(); register_node_type_cmp_rgbtobw(); @@ -3528,10 +3529,12 @@ static void registerShaderNodes(void) register_node_type_sh_mix_shader(); register_node_type_sh_add_shader(); register_node_type_sh_uvmap(); + register_node_type_sh_uvalongstroke(); register_node_type_sh_output_lamp(); register_node_type_sh_output_material(); register_node_type_sh_output_world(); + register_node_type_sh_output_linestyle(); register_node_type_sh_tex_image(); register_node_type_sh_tex_environment(); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 3490bb9ffbd..b09016506e3 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -42,6 +42,7 @@ #include "DNA_constraint_types.h" #include "DNA_group_types.h" #include "DNA_key_types.h" +#include "DNA_lamp_types.h" #include "DNA_lattice_types.h" #include "DNA_material_types.h" #include "DNA_meta_types.h" @@ -180,7 +181,7 @@ 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); + BKE_curve_bevelList_free(&ob->curve_cache->bev); if (ob->curve_cache->path) { free_path(ob->curve_cache->path); } @@ -246,7 +247,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) ModifierData *md; BKE_object_free_modifiers(ob_dst); - if (!ELEM5(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { + if (!ELEM(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { /* only objects listed above can have modifiers and linking them to objects * which doesn't have modifiers stack is quite silly */ return; @@ -255,11 +256,11 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) for (md = ob_src->modifiers.first; md; md = md->next) { ModifierData *nmd = NULL; - if (ELEM4(md->type, - eModifierType_Hook, - eModifierType_Softbody, - eModifierType_ParticleInstance, - eModifierType_Collision)) + if (ELEM(md->type, + eModifierType_Hook, + eModifierType_Softbody, + eModifierType_ParticleInstance, + eModifierType_Collision)) { continue; } @@ -296,7 +297,7 @@ void BKE_object_free_derived_caches(Object *ob) me->bb->flag |= BOUNDBOX_DIRTY; } } - else if (ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { + else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { Curve *cu = ob->data; if (cu->bb) { @@ -322,7 +323,7 @@ void BKE_object_free_derived_caches(Object *ob) if (ob->curve_cache) { BKE_displist_free(&ob->curve_cache->disp); - BLI_freelistN(&ob->curve_cache->bev); + BKE_curve_bevelList_free(&ob->curve_cache->bev); if (ob->curve_cache->path) { free_path(ob->curve_cache->path); ob->curve_cache->path = NULL; @@ -408,7 +409,7 @@ void BKE_object_free_ex(Object *ob, bool do_id_user) /* Free runtime curves data. */ if (ob->curve_cache) { - BLI_freelistN(&ob->curve_cache->bev); + BKE_curve_bevelList_free(&ob->curve_cache->bev); if (ob->curve_cache->path) free_path(ob->curve_cache->path); MEM_freeN(ob->curve_cache); @@ -709,7 +710,7 @@ void BKE_object_unlink(Object *ob) lineset; lineset = lineset->next) { if (lineset->linestyle) { - BKE_unlink_linestyle_target_object(lineset->linestyle, ob); + BKE_linestyle_target_object_unlink(lineset->linestyle, ob); } } } @@ -873,9 +874,9 @@ bool BKE_object_is_in_wpaint_select_vert(Object *ob) { if (ob->type == OB_MESH) { Mesh *me = ob->data; - return ( (ob->mode & OB_MODE_WEIGHT_PAINT) && - (me->edit_btmesh == NULL) && - (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX) ); + return ((ob->mode & OB_MODE_WEIGHT_PAINT) && + (me->edit_btmesh == NULL) && + (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX)); } return false; @@ -977,7 +978,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) ob->empty_drawtype = OB_PLAINAXES; ob->empty_drawsize = 1.0; - if (ELEM3(type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + if (ELEM(type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { ob->trackflag = OB_NEGZ; ob->upflag = OB_POSY; } @@ -1526,6 +1527,18 @@ Object *BKE_object_copy(Object *ob) return BKE_object_copy_ex(G.main, ob, false); } +static void extern_local_object__modifiersForeachIDLink( + void *UNUSED(userData), Object *UNUSED(ob), + ID **idpoin) +{ + if (*idpoin) { + /* intentionally omit ID_OB */ + if (ELEM(GS((*idpoin)->name), ID_IM, ID_TE)) { + id_lib_extern(*idpoin); + } + } +} + static void extern_local_object(Object *ob) { ParticleSystem *psys; @@ -1539,6 +1552,8 @@ static void extern_local_object(Object *ob) for (psys = ob->particlesystem.first; psys; psys = psys->next) id_lib_extern((ID *)psys->part); + + modifiers_foreachIDLink(ob, extern_local_object__modifiersForeachIDLink, NULL); } void BKE_object_make_local(Object *ob) @@ -1778,6 +1793,55 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) ob->dt = target->dt; } +/** + * Use with newly created objects to set their size + * (used to apply scene-scale). + */ +void BKE_object_obdata_size_init(struct Object *ob, const float size) +{ + /* apply radius as a scale to types that support it */ + switch (ob->type) { + case OB_EMPTY: + { + ob->empty_drawsize *= size; + break; + } + case OB_FONT: + { + Curve *cu = ob->data; + cu->fsize *= size; + break; + } + case OB_CAMERA: + { + Camera *cam = ob->data; + cam->drawsize *= size; + break; + } + case OB_LAMP: + { + Lamp *lamp = ob->data; + lamp->dist *= size; + lamp->area_size *= size; + lamp->area_sizey *= size; + lamp->area_sizez *= size; + break; + } + /* Only lattice (not mesh, curve, mball...), + * because its got data when newly added */ + case OB_LATTICE: + { + struct Lattice *lt = ob->data; + float mat[4][4]; + + unit_m4(mat); + scale_m4_fl(mat, size); + + BKE_lattice_transform(lt, (float (*)[4])mat, false); + break; + } + } +} /* *************** CALC ****************** */ @@ -1978,7 +2042,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) unit_m4(mat); cu = par->data; - 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! */ + if (ELEM(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 (par->curve_cache->path == NULL) return; @@ -1994,17 +2058,20 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) * we divide the curvetime calculated in the previous step by the length of the path, to get a time * factor, which then gets clamped to lie within 0.0 - 1.0 range */ - if (IS_EQF(cu->pathlen, 0.0f) == 0) + if (cu->pathlen) { ctime = cu->ctime / cu->pathlen; - else + } + else { ctime = cu->ctime; + } CLAMP(ctime, 0.0f, 1.0f); } else { ctime = BKE_scene_frame_get(scene); - if (IS_EQF(cu->pathlen, 0.0f) == 0) + if (cu->pathlen) { ctime /= cu->pathlen; + } CLAMP(ctime, 0.0f, 1.0f); } @@ -2289,7 +2356,7 @@ static bool where_is_object_parslow(Object *ob, float obmat[4][4], float slowmat int a; /* include framerate */ - fac1 = (1.0f / (1.0f + fabsf(ob->sf)) ); + fac1 = (1.0f / (1.0f + fabsf(ob->sf))); if (fac1 >= 1.0f) return 0; fac2 = 1.0f - fac1; @@ -2466,6 +2533,20 @@ void BKE_boundbox_init_from_minmax(BoundBox *bb, const float min[3], const float bb->vec[1][2] = bb->vec[2][2] = bb->vec[5][2] = bb->vec[6][2] = max[2]; } +void BKE_boundbox_calc_center_aabb(const BoundBox *bb, float r_cent[3]) +{ + r_cent[0] = 0.5f * (bb->vec[0][0] + bb->vec[4][0]); + r_cent[1] = 0.5f * (bb->vec[0][1] + bb->vec[2][1]); + r_cent[2] = 0.5f * (bb->vec[0][2] + bb->vec[1][2]); +} + +void BKE_boundbox_calc_size_aabb(const BoundBox *bb, float r_size[3]) +{ + r_size[0] = 0.5f * fabsf(bb->vec[0][0] - bb->vec[4][0]); + r_size[1] = 0.5f * fabsf(bb->vec[0][1] - bb->vec[2][1]); + r_size[2] = 0.5f * fabsf(bb->vec[0][2] - bb->vec[1][2]); +} + BoundBox *BKE_object_boundbox_get(Object *ob) { BoundBox *bb = NULL; @@ -2473,7 +2554,7 @@ BoundBox *BKE_object_boundbox_get(Object *ob) if (ob->type == OB_MESH) { bb = BKE_mesh_boundbox_get(ob); } - else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { bb = BKE_curve_boundbox_get(ob); } else if (ob->type == OB_MBALL) { @@ -2483,7 +2564,7 @@ BoundBox *BKE_object_boundbox_get(Object *ob) } /* used to temporally disable/enable boundbox */ -void BKE_object_boundbox_flag(Object *ob, int flag, int set) +void BKE_object_boundbox_flag(Object *ob, int flag, const bool set) { BoundBox *bb = BKE_object_boundbox_get(ob); if (bb) { @@ -3126,8 +3207,10 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc, * Test a bounding box for ray intersection * assumes the ray is already local to the boundbox space */ -bool BKE_boundbox_ray_hit_check(struct BoundBox *bb, const float ray_start[3], const float ray_normal[3], - float *r_lambda) +bool BKE_boundbox_ray_hit_check( + const struct BoundBox *bb, + const float ray_start[3], const float ray_normal[3], + float *r_lambda) { const int triangle_indexes[12][3] = { {0, 1, 2}, {0, 2, 3}, diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 707438bc673..0d82c6e89a1 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -754,14 +754,14 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj if (orco) { int j; - for (j = 0; j < mpoly->totloop; j++) { + for (j = 0; j < mp->totloop; j++) { madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w); } } if (mloopuv) { int j; - for (j = 0; j < mpoly->totloop; j++) { + for (j = 0; j < mp->totloop; j++) { madd_v2_v2fl(dob->uv, mloopuv[mp->loopstart + j].uv, w); } } diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 9a144b5461a..4382d74f34e 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -45,8 +45,10 @@ #include "BLI_bitmap.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" +#include "BLI_listbase.h" #include "BKE_brush.h" +#include "BKE_main.h" #include "BKE_context.h" #include "BKE_crazyspace.h" #include "BKE_depsgraph.h" @@ -269,6 +271,105 @@ void BKE_paint_brush_set(Paint *p, Brush *br) } } +void BKE_paint_curve_free(PaintCurve *pc) +{ + if (pc->points) { + MEM_freeN(pc->points); + pc->points = NULL; + pc->tot_points = 0; + } +} + +PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name) +{ + PaintCurve *pc; + + pc = BKE_libblock_alloc(bmain, ID_PC, name); + + return pc; +} + +Palette *BKE_paint_palette(Paint *p) +{ + return p ? p->palette : NULL; +} + +void BKE_paint_palette_set(Paint *p, Palette *palette) +{ + if (p) { + id_us_min((ID *)p->palette); + id_us_plus((ID *)palette); + p->palette = palette; + } +} + +void BKE_paint_curve_set(Brush *br, PaintCurve *pc) +{ + if (br) { + id_us_min((ID *)br->paint_curve); + id_us_plus((ID *)pc); + br->paint_curve = pc; + } +} + +/* remove colour from palette. Must be certain color is inside the palette! */ +void BKE_palette_color_remove(Palette *palette, PaletteColor *color) +{ + BLI_remlink(&palette->colors, color); + BLI_addhead(&palette->deleted, color); +} + +void BKE_palette_cleanup(Palette *palette) +{ + BLI_freelistN(&palette->deleted); +} + + +Palette *BKE_palette_add(Main *bmain, const char *name) +{ + Palette *palette; + + palette = BKE_libblock_alloc(bmain, ID_PAL, name); + + /* enable fake user by default */ + palette->id.flag |= LIB_FAKEUSER; + + return palette; +} + +void BKE_palette_free(Palette *palette) +{ + BLI_freelistN(&palette->colors); +} + +PaletteColor *BKE_palette_color_add(Palette *palette) +{ + PaletteColor *color = MEM_callocN(sizeof(*color), "Pallete Color"); + BLI_addtail(&palette->colors, color); + palette->active_color = BLI_countlist(&palette->colors) - 1; + return color; +} + +void BKE_palette_color_delete(struct Palette *palette) +{ + PaletteColor *color = BLI_findlink(&palette->colors, palette->active_color); + + if (color) { + if ((color == palette->colors.last) && (palette->colors.last != palette->colors.first)) + palette->active_color--; + + BLI_remlink(&palette->colors, color); + BLI_addhead(&palette->deleted, color); + } +} + + +bool BKE_palette_is_empty(const struct Palette *palette) +{ + return BLI_listbase_is_empty(&palette->colors); +} + + /* are we in vertex paint or weight pain face select mode? */ bool BKE_paint_select_face_test(Object *ob) { @@ -318,6 +419,7 @@ void BKE_paint_init(Paint *p, const char col[3]) void BKE_paint_free(Paint *paint) { id_us_min((ID *)paint->brush); + id_us_min((ID *)paint->palette); } /* called when copying scene settings, so even if 'src' and 'tar' are the same @@ -328,6 +430,7 @@ void BKE_paint_copy(Paint *src, Paint *tar) { tar->brush = src->brush; id_us_plus((ID *)tar->brush); + id_us_plus((ID *)tar->palette); } /* returns non-zero if any of the face's vertices @@ -378,7 +481,7 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level, return gpm->data[(y * factor) * gridsize + (x * factor)]; } -/* threshhold to move before updating the brush rotation */ +/* threshold to move before updating the brush rotation */ #define RAKE_THRESHHOLD 20 void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, const float mouse_pos[2]) diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 8161f9d8875..27d346f65b9 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -1657,11 +1657,14 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, const f index_mp_to_orig = NULL; } + totface = dm->getNumTessFaces(dm); + if (!totface) { + return DMCACHE_NOTFOUND; + } + mpoly = dm->getPolyArray(dm); osface = dm->getTessFaceDataArray(dm, CD_ORIGSPACE); - totface = dm->getNumTessFaces(dm); - if (osface == NULL || index_mf_to_mpoly == NULL) { /* Assume we don't need osface data */ if (index < totface) { diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 06ac9db0b16..09e20c02691 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -117,7 +117,7 @@ static int particles_are_dynamic(ParticleSystem *psys) if (psys->part->type == PART_HAIR) return psys->flag & PSYS_HAIR_DYNAMICS; else - return ELEM3(psys->part->phystype, PART_PHYS_NEWTON, PART_PHYS_BOIDS, PART_PHYS_FLUID); + return ELEM(psys->part->phystype, PART_PHYS_NEWTON, PART_PHYS_BOIDS, PART_PHYS_FLUID); } float psys_get_current_display_percentage(ParticleSystem *psys) @@ -399,7 +399,7 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys) } } - if (origindex_final != ORIGINDEX_NONE) { + if (origindex_final != ORIGINDEX_NONE && origindex_final < totelem) { if (nodearray[origindex_final]) { /* prepend */ node->next = nodearray[origindex_final]; @@ -507,7 +507,7 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys) sub_v3_v3v3(delta, max, min); /* determine major axis */ - axis = (delta[0]>=delta[1]) ? 0 : ((delta[1]>=delta[2]) ? 1 : 2); + axis = axis_dominant_v3_single(delta); d = delta[axis]/(float)res; @@ -1079,7 +1079,7 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D float *element_weight=NULL,*element_sum=NULL,*jitter_offset=NULL, *vweight=NULL; float cur, maxweight=0.0, tweight, totweight, inv_totweight, co[3], nor[3], orco[3]; - if (ELEM3(NULL, ob, psys, psys->part)) + if (ELEM(NULL, ob, psys, psys->part)) return 0; part=psys->part; @@ -2638,7 +2638,7 @@ static void sph_particle_courant(SPHData *sphdata, SPHRangeData *pfr) mul_v3_v3fl(sphdata->flow, flow, 1.0f / pfr->tot_neighbors); } else { - sphdata->element_size = MAXFLOAT; + sphdata->element_size = FLT_MAX; copy_v3_v3(sphdata->flow, flow); } } @@ -3153,7 +3153,7 @@ static void basic_rotate(ParticleSettings *part, ParticleData *pa, float dfra, f extrotfac = 0.0f; } - if ((part->flag & PART_ROT_DYN) && ELEM3(part->avemode, PART_AVE_VELOCITY, PART_AVE_HORIZONTAL, PART_AVE_VERTICAL)) { + if ((part->flag & PART_ROT_DYN) && ELEM(part->avemode, PART_AVE_VELOCITY, PART_AVE_HORIZONTAL, PART_AVE_VERTICAL)) { float angle; float len1 = len_v3(pa->prev_state.vel); float len2 = len_v3(pa->state.vel); @@ -4012,6 +4012,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim) if (!psys->clmd) { psys->clmd = (ClothModifierData*)modifier_new(eModifierType_Cloth); psys->clmd->sim_parms->goalspring = 0.0f; + psys->clmd->sim_parms->vel_damping = 1.0f; psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_GOAL|CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS; psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF; } @@ -4846,13 +4847,13 @@ void psys_changed_type(Object *ob, ParticleSystem *psys) psys->flag &= ~PSYS_KEYED; if (part->type == PART_HAIR) { - if (ELEM4(part->ren_as, PART_DRAW_NOT, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)==0) + if (ELEM(part->ren_as, PART_DRAW_NOT, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)==0) part->ren_as = PART_DRAW_PATH; if (part->distr == PART_DISTR_GRID) part->distr = PART_DISTR_JIT; - if (ELEM3(part->draw_as, PART_DRAW_NOT, PART_DRAW_REND, PART_DRAW_PATH)==0) + if (ELEM(part->draw_as, PART_DRAW_NOT, PART_DRAW_REND, PART_DRAW_PATH)==0) part->draw_as = PART_DRAW_REND; CLAMP(part->path_start, 0.0f, 100.0f); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 1a815cf0dee..3e763016efb 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -50,6 +50,15 @@ #define STACK_FIXED_DEPTH 100 +/* Setting zero so we can catch bugs in OpenMP/PBVH. */ +#ifdef _OPENMP +# ifdef DEBUG +# define PBVH_OMP_LIMIT 0 +# else +# define PBVH_OMP_LIMIT 8 +# endif +#endif + typedef struct PBVHStack { PBVHNode *node; int revisiting; @@ -965,7 +974,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, * can only update vertices marked with ME_VERT_PBVH_UPDATE. */ -#pragma omp parallel for private(n) schedule(static) +#pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; @@ -1009,7 +1018,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, } } -#pragma omp parallel for private(n) schedule(static) +#pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; @@ -1046,7 +1055,7 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) int n; /* update BB, redraw flag */ -#pragma omp parallel for private(n) schedule(static) +#pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c index 90b5d8cf1a1..b2178fe69b3 100644 --- a/source/blender/blenkernel/intern/report.c +++ b/source/blender/blenkernel/intern/report.c @@ -284,7 +284,7 @@ Report *BKE_reports_last_displayable(ReportList *reports) Report *report; for (report = reports->list.last; report; report = report->prev) { - if (ELEM3(report->type, RPT_ERROR, RPT_WARNING, RPT_INFO)) + if (ELEM(report->type, RPT_ERROR, RPT_WARNING, RPT_INFO)) return report; } diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 09293503ad5..3d61b0bdefb 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -57,6 +57,7 @@ #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_pointcache.h" #include "BKE_rigidbody.h" @@ -287,10 +288,10 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob) DM_ensure_tessface(dm); - mvert = (dm) ? dm->getVertArray(dm) : NULL; - totvert = (dm) ? dm->getNumVerts(dm) : 0; - mface = (dm) ? dm->getTessFaceArray(dm) : NULL; - totface = (dm) ? dm->getNumTessFaces(dm) : 0; + mvert = dm->getVertArray(dm); + totvert = dm->getNumVerts(dm); + mface = dm->getTessFaceArray(dm); + totface = dm->getNumTessFaces(dm); /* sanity checking - potential case when no data will be present */ if ((totvert == 0) || (totface == 0)) { @@ -344,7 +345,7 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob) } /* cleanup temp data */ - if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE) { + if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) { dm->release(dm); } } @@ -394,7 +395,7 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild) } mul_v3_fl(size, 0.5f); - if (ELEM3(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { + if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { /* take radius as largest x/y dimension, and height as z-dimension */ radius = MAX2(size[0], size[1]); height = size[2]; @@ -455,6 +456,182 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild) /* --------------------- */ +/* helper function to calculate volume of rigidbody object */ +// TODO: allow a parameter to specify method used to calculate this? +void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) +{ + RigidBodyOb *rbo = ob->rigidbody_object; + + float size[3] = {1.0f, 1.0f, 1.0f}; + float radius = 1.0f; + float height = 1.0f; + + float volume = 0.0f; + + /* if automatically determining dimensions, use the Object's boundbox + * - assume that all quadrics are standing upright on local z-axis + * - assume even distribution of mass around the Object's pivot + * (i.e. Object pivot is centralized in boundbox) + * - boundbox gives full width + */ + // XXX: all dimensions are auto-determined now... later can add stored settings for this + BKE_object_dimensions_get(ob, size); + + if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { + /* take radius as largest x/y dimension, and height as z-dimension */ + radius = MAX2(size[0], size[1]) * 0.5f; + height = size[2]; + } + else if (rbo->shape == RB_SHAPE_SPHERE) { + /* take radius to the the largest dimension to try and encompass everything */ + radius = max_fff(size[0], size[1], size[2]) * 0.5f; + } + + /* calculate volume as appropriate */ + switch (rbo->shape) { + case RB_SHAPE_BOX: + volume = size[0] * size[1] * size[2]; + break; + + case RB_SHAPE_SPHERE: + volume = 4.0f / 3.0f * (float)M_PI * radius * radius * radius; + break; + + /* for now, assume that capsule is close enough to a cylinder... */ + case RB_SHAPE_CAPSULE: + case RB_SHAPE_CYLINDER: + volume = (float)M_PI * radius * radius * height; + break; + + case RB_SHAPE_CONE: + volume = (float)M_PI / 3.0f * radius * radius * height; + break; + + case RB_SHAPE_CONVEXH: + case RB_SHAPE_TRIMESH: + { + if (ob->type == OB_MESH) { + DerivedMesh *dm = rigidbody_get_mesh(ob); + MVert *mvert; + MFace *mface; + int totvert, totface; + + /* ensure mesh validity, then grab data */ + if (dm == NULL) + return; + + DM_ensure_tessface(dm); + + mvert = dm->getVertArray(dm); + totvert = dm->getNumVerts(dm); + mface = dm->getTessFaceArray(dm); + totface = dm->getNumTessFaces(dm); + + if (totvert > 0 && totface > 0) { + BKE_mesh_calc_volume(mvert, totvert, mface, totface, &volume, NULL); + } + + /* cleanup temp data */ + if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) { + dm->release(dm); + } + } + else { + /* rough estimate from boundbox as fallback */ + /* XXX could implement other types of geometry here (curves, etc.) */ + volume = size[0] * size[1] * size[2]; + } + break; + } + +#if 0 // XXX: not defined yet + case RB_SHAPE_COMPOUND: + volume = 0.0f; + break; +#endif + } + + /* return the volume calculated */ + if (r_vol) *r_vol = volume; +} + +void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_com[3]) +{ + RigidBodyOb *rbo = ob->rigidbody_object; + + float size[3] = {1.0f, 1.0f, 1.0f}; + float height = 1.0f; + + zero_v3(r_com); + + /* if automatically determining dimensions, use the Object's boundbox + * - assume that all quadrics are standing upright on local z-axis + * - assume even distribution of mass around the Object's pivot + * (i.e. Object pivot is centralized in boundbox) + * - boundbox gives full width + */ + // XXX: all dimensions are auto-determined now... later can add stored settings for this + BKE_object_dimensions_get(ob, size); + + /* calculate volume as appropriate */ + switch (rbo->shape) { + case RB_SHAPE_BOX: + case RB_SHAPE_SPHERE: + case RB_SHAPE_CAPSULE: + case RB_SHAPE_CYLINDER: + break; + + case RB_SHAPE_CONE: + /* take radius as largest x/y dimension, and height as z-dimension */ + height = size[2]; + /* cone is geometrically centered on the median, + * center of mass is 1/4 up from the base + */ + r_com[2] = -0.25f * height; + break; + + case RB_SHAPE_CONVEXH: + case RB_SHAPE_TRIMESH: + { + if (ob->type == OB_MESH) { + DerivedMesh *dm = rigidbody_get_mesh(ob); + MVert *mvert; + MFace *mface; + int totvert, totface; + + /* ensure mesh validity, then grab data */ + if (dm == NULL) + return; + + DM_ensure_tessface(dm); + + mvert = dm->getVertArray(dm); + totvert = dm->getNumVerts(dm); + mface = dm->getTessFaceArray(dm); + totface = dm->getNumTessFaces(dm); + + if (totvert > 0 && totface > 0) { + BKE_mesh_calc_volume(mvert, totvert, mface, totface, NULL, r_com); + } + + /* cleanup temp data */ + if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) { + dm->release(dm); + } + } + break; + } + +#if 0 // XXX: not defined yet + case RB_SHAPE_COMPOUND: + volume = 0.0f; + break; +#endif + } +} + +/* --------------------- */ + /** * Create physics sim representation of object given RigidBody settings * @@ -543,7 +720,7 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b return; } - if (ELEM4(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) { + if (ELEM(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) { if (rbc->physics_constraint) { RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); RB_constraint_delete(rbc->physics_constraint); @@ -1414,6 +1591,8 @@ struct RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) { return NULL; } struct RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) { return NULL; } void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc) {} void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild) {} +void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) { if (r_vol) *r_vol = 0.0f; } +void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_com[3]) { zero_v3(r_com); } struct RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) { return NULL; } struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw) { return NULL; } void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw) {} diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index 1310162483e..4be75344133 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -392,6 +392,7 @@ void init_actuator(bActuator *act) bSteeringActuator *sta; bArmatureActuator *arma; bMouseActuator *ma; + bEditObjectActuator *eoa; if (act->data) MEM_freeN(act->data); act->data= NULL; @@ -430,6 +431,9 @@ void init_actuator(bActuator *act) break; case ACT_EDIT_OBJECT: act->data= MEM_callocN(sizeof(bEditObjectActuator), "editobact"); + eoa = act->data; + eoa->upflag= ACT_TRACK_UP_Z; + eoa->trackflag= ACT_TRACK_TRAXIS_Y; break; case ACT_CONSTRAINT: act->data= MEM_callocN(sizeof(bConstraintActuator), "cons act"); diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index f8ce31f1b8a..eb98e381222 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -39,6 +39,7 @@ #include "DNA_anim_types.h" #include "DNA_group_types.h" #include "DNA_linestyle_types.h" +#include "DNA_mesh_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_rigidbody_types.h" @@ -46,6 +47,8 @@ #include "DNA_screen_types.h" #include "DNA_sequence_types.h" #include "DNA_space_types.h" +#include "DNA_view3d_types.h" +#include "DNA_windowmanager_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" @@ -62,6 +65,7 @@ #include "BKE_action.h" #include "BKE_colortools.h" #include "BKE_depsgraph.h" +#include "BKE_editmesh.h" #include "BKE_fcurve.h" #include "BKE_freestyle.h" #include "BKE_global.h" @@ -78,6 +82,7 @@ #include "BKE_scene.h" #include "BKE_sequencer.h" #include "BKE_sound.h" +#include "BKE_unit.h" #include "BKE_world.h" #include "RE_engine.h" @@ -86,6 +91,8 @@ #include "IMB_colormanagement.h" +#include "bmesh.h" + //XXX #include "BIF_previewrender.h" //XXX #include "BIF_editseq.h" @@ -253,6 +260,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint); ts->imapaint.paintcursor = NULL; + id_us_plus((ID *)ts->imapaint.stencil); ts->particle.paintcursor = NULL; } @@ -510,6 +518,8 @@ Scene *BKE_scene_add(Main *bmain, const char *name) sce->r.border.ymin = 0.0f; sce->r.border.xmax = 1.0f; sce->r.border.ymax = 1.0f; + + sce->r.preview_start_resolution = 64; sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct"); sce->toolsettings->doublimit = 0.001; @@ -553,6 +563,8 @@ Scene *BKE_scene_add(Main *bmain, const char *name) sce->toolsettings->proportional_size = 1.0f; sce->toolsettings->imapaint.paint.flags |= PAINT_SHOW_BRUSH; + sce->toolsettings->imapaint.normal_angle = 80; + sce->toolsettings->imapaint.seam_bleed = 2; sce->physics_settings.gravity[0] = 0.0f; sce->physics_settings.gravity[1] = 0.0f; @@ -719,14 +731,14 @@ void BKE_scene_set_background(Main *bmain, Scene *scene) /* called from creator.c */ Scene *BKE_scene_set_name(Main *bmain, const char *name) { - Scene *sce = (Scene *)BKE_libblock_find_name(ID_SCE, name); + Scene *sce = (Scene *)BKE_libblock_find_name_ex(bmain, ID_SCE, name); if (sce) { BKE_scene_set_background(bmain, sce); - printf("Scene switch: '%s' in file: '%s'\n", name, G.main->name); + printf("Scene switch: '%s' in file: '%s'\n", name, bmain->name); return sce; } - printf("Can't find scene: '%s' in file: '%s'\n", name, G.main->name); + printf("Can't find scene: '%s' in file: '%s'\n", name, bmain->name); return NULL; } @@ -804,9 +816,7 @@ void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce) BKE_libblock_free(bmain, sce); } -/* used by metaballs - * doesn't return the original duplicated object, only dupli's - */ +/* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, Scene **scene, int val, Base **base, Object **ob) { @@ -817,11 +827,12 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, iter->phase = F_START; iter->dupob = NULL; iter->duplilist = NULL; + iter->dupli_refob = NULL; } else { /* run_again is set when a duplilist has been ended */ while (run_again) { - run_again = 0; + run_again = false; /* the first base */ if (iter->phase == F_START) { @@ -879,34 +890,46 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, iter->dupob = iter->duplilist->first; - if (!iter->dupob) + if (!iter->dupob) { free_object_duplilist(iter->duplilist); + iter->duplilist = NULL; + } + iter->dupli_refob = NULL; } } } /* handle dupli's */ if (iter->dupob) { - - copy_m4_m4(iter->omat, iter->dupob->ob->obmat); - copy_m4_m4(iter->dupob->ob->obmat, iter->dupob->mat); - (*base)->flag |= OB_FROMDUPLI; *ob = iter->dupob->ob; iter->phase = F_DUPLI; - + + if (iter->dupli_refob != *ob) { + if (iter->dupli_refob) { + /* Restore previous object's real matrix. */ + copy_m4_m4(iter->dupli_refob->obmat, iter->omat); + } + /* Backup new object's real matrix. */ + iter->dupli_refob = *ob; + copy_m4_m4(iter->omat, iter->dupli_refob->obmat); + } + copy_m4_m4((*ob)->obmat, iter->dupob->mat); + iter->dupob = iter->dupob->next; } else if (iter->phase == F_DUPLI) { iter->phase = F_SCENE; (*base)->flag &= ~OB_FROMDUPLI; - for (iter->dupob = iter->duplilist->first; iter->dupob; iter->dupob = iter->dupob->next) { - copy_m4_m4(iter->dupob->ob->obmat, iter->omat); + if (iter->dupli_refob) { + /* Restore last object's real matrix. */ + copy_m4_m4(iter->dupli_refob->obmat, iter->omat); + iter->dupli_refob = NULL; } free_object_duplilist(iter->duplilist); iter->duplilist = NULL; - run_again = 1; + run_again = true; } } } @@ -1118,11 +1141,6 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra) double intpart; scene->r.subframe = modf(cfra, &intpart); scene->r.cfra = (int)intpart; - - if (cfra < 0.0) { - scene->r.cfra -= 1; - scene->r.subframe = 1.0f + scene->r.subframe; - } } /* drivers support/hacks @@ -1541,6 +1559,53 @@ static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bma } +static bool check_rendered_viewport_visible(Main *bmain) +{ + wmWindowManager *wm = bmain->wm.first; + wmWindow *window; + for (window = wm->windows.first; window != NULL; window = window->next) { + bScreen *screen = window->screen; + ScrArea *area; + for (area = screen->areabase.first; area != NULL; area = area->next) { + View3D *v3d = area->spacedata.first; + if (area->spacetype != SPACE_VIEW3D) { + continue; + } + if (v3d->drawtype == OB_RENDER) { + return true; + } + } + } + return false; +} + +static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) +{ + /* This is needed to prepare mesh to be used by the render + * engine from the viewport rendering. We do loading here + * so all the objects which shares the same mesh datablock + * are nicely tagged for update and updated. + * + * This makes it so viewport render engine doesn't need to + * call loading of the edit data for the mesh objects. + */ + + Object *obedit = scene->obedit; + if (obedit) { + Mesh *mesh = obedit->data; + /* TODO(sergey): Check object recalc flags as well? */ + if ((obedit->type == OB_MESH) && + (mesh->id.flag & (LIB_ID_RECALC | LIB_ID_RECALC_DATA))) + { + if (check_rendered_viewport_visible(bmain)) { + BMesh *bm = mesh->edit_btmesh->bm; + BM_mesh_bm_to_me(bm, mesh, false); + DAG_id_tag_update(&mesh->id, 0); + } + } + } +} + void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene) { Scene *sce_iter; @@ -1552,6 +1617,9 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) DAG_scene_relations_update(bmain, sce_iter); + /* flush editing data if needed */ + prepare_mesh_for_viewport_render(bmain, scene); + /* flush recalc flags to dependencies */ DAG_ids_flush_tagged(bmain); @@ -1832,6 +1900,12 @@ bool BKE_scene_use_new_shading_nodes(Scene *scene) return (type && type->flag & RE_USE_SHADING_NODES); } +bool BKE_scene_uses_blender_internal(struct Scene *scene) +{ + return strcmp("BLENDER_RENDER", scene->r.engine) == 0; +} + + void BKE_scene_base_flag_to_objects(struct Scene *scene) { Base *base = scene->base.first; @@ -1903,3 +1977,29 @@ int BKE_scene_num_threads(const Scene *scene) { return BKE_render_num_threads(&scene->r); } + +/* Apply the needed correction factor to value, based on unit_type (only length-related are affected currently) + * and unit->scale_length. + */ +double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, double value) +{ + if (unit->system == USER_UNIT_NONE) { + /* Never apply scale_length when not using a unit setting! */ + return value; + } + + switch (unit_type) { + case B_UNIT_LENGTH: + return value * (double)unit->scale_length; + case B_UNIT_CAMERA: + return value * (double)unit->scale_length; + case B_UNIT_AREA: + return value * pow(unit->scale_length, 2); + case B_UNIT_VOLUME: + return value * pow(unit->scale_length, 3); + case B_UNIT_MASS: + return value * pow(unit->scale_length, 3); + default: + return value; + } +} diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 9d40ee6e667..b2296151cf7 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -425,6 +425,32 @@ ScrArea *BKE_screen_find_big_area(bScreen *sc, const int spacetype, const short return big; } +/** + * Utility function to get the active layer to use when adding new objects. + */ +unsigned int BKE_screen_view3d_layer_active_ex(const View3D *v3d, const Scene *scene, bool use_localvd) +{ + unsigned int lay; + if ((v3d == NULL) || (v3d->scenelock && !v3d->localvd)) { + lay = scene->layact; + } + else { + lay = v3d->layact; + } + + if (use_localvd) { + if (v3d && v3d->localvd) { + lay |= v3d->lay; + } + } + + return lay; +} +unsigned int BKE_screen_view3d_layer_active(const struct View3D *v3d, const struct Scene *scene) +{ + return BKE_screen_view3d_layer_active_ex(v3d, scene, true); +} + void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene) { int bit; diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 2b14b92217b..d2dc9da47f9 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -52,6 +52,11 @@ #include "RNA_access.h" +/* TODO(sergey): Could be considered a bad level call, but + * need this for gaussian table. + */ +#include "RE_pipeline.h" + static void slice_get_byte_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2, const ImBuf *ibuf3, const ImBuf *out, int start_line, unsigned char **rect1, unsigned char **rect2, unsigned char **rect3, unsigned char **rect_out) @@ -2579,6 +2584,295 @@ static void do_overdrop_effect(const SeqRenderData *context, Sequence *UNUSED(se } } +/*********************** Gaussian Blur *************************/ + +/* NOTE: This gaussian blur implementation accumulates values in the square + * kernel rather that doing X direction and then Y direction because of the + * lack of using multiple-staged filters. + * + * Once we can we'll implement a way to apply filter as multiple stages we + * can optimize hell of a lot in here. + */ + +static void init_gaussian_blur_effect(Sequence *seq) +{ + if (seq->effectdata) + MEM_freeN(seq->effectdata); + + seq->effectdata = MEM_callocN(sizeof(WipeVars), "wipevars"); +} + +static int num_inputs_gaussian_blur(void) +{ + return 1; +} + +static void free_gaussian_blur_effect(Sequence *seq) +{ + if (seq->effectdata) + MEM_freeN(seq->effectdata); + + seq->effectdata = NULL; +} + +static void copy_gaussian_blur_effect(Sequence *dst, Sequence *src) +{ + dst->effectdata = MEM_dupallocN(src->effectdata); +} + +static int early_out_gaussian_blur(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1)) +{ + GaussianBlurVars *data = seq->effectdata; + if (data->size_x == 0.0f && data->size_y == 0) { + return EARLY_USE_INPUT_1; + } + return EARLY_DO_EFFECT; +} + +/* TODO(sergey): De-duplicate with compositor. */ +static float *make_gaussian_blur_kernel(float rad, int size) +{ + float *gausstab, sum, val; + float fac; + int i, n; + + n = 2 * size + 1; + + gausstab = (float *)MEM_mallocN(sizeof(float) * n, __func__); + + sum = 0.0f; + fac = (rad > 0.0f ? 1.0f / rad : 0.0f); + for (i = -size; i <= size; i++) { + val = RE_filter_value(R_FILTER_GAUSS, (float)i * fac); + sum += val; + gausstab[i + size] = val; + } + + sum = 1.0f / sum; + for (i = 0; i < n; i++) + gausstab[i] *= sum; + + return gausstab; +} + +static void do_gaussian_blur_effect_byte(Sequence *seq, + int start_line, + int x, int y, + int frame_width, int frame_height, + unsigned char *rect, + unsigned char *out) +{ +#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4) + GaussianBlurVars *data = seq->effectdata; + const int size_x = (int) (data->size_x + 0.5f), + size_y = (int) (data->size_y + 0.5f); + int i, j; + + /* Make gaussian weight tabke. */ + float *gausstab_x, *gausstab_y; + gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x); + if (data->size_x == data->size_y) { + gausstab_y = gausstab_x; + } + else { + gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y); + } + + for (i = 0; i < y; ++i) { + for (j = 0; j < x; ++j) { + int out_index = INDEX(j, i); + int current_x, current_y; + float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float accum_weight = 0.0f; + for (current_y = i - size_y; + current_y <= i + size_y; + ++current_y) + { + if (current_y < -start_line || + current_y + start_line >= frame_height) + { + /* Out of bounds. */ + continue; + } + + for (current_x = j - size_x; + current_x <= j + size_x; + ++current_x) + { + float weight; + int index = INDEX(current_x, current_y + start_line); + if (current_x < 0 || current_x >= frame_width) { + /* Out of bounds. */ + continue; + } + BLI_assert(index >= 0); + BLI_assert(index < frame_width * frame_height * 4); + + if (size_x != 0 && size_y != 0) { + weight = gausstab_x[current_x - j + size_x] * + gausstab_y[current_y - i + size_y]; + } + else if (size_x == 0) { + weight = gausstab_y[current_y - i + size_y]; + } + else { + weight = gausstab_x[current_x - j + size_x]; + } + accum[0] += rect[index] * weight; + accum[1] += rect[index + 1] * weight; + accum[2] += rect[index + 2] * weight; + accum[3] += rect[index + 3] * weight; + accum_weight += weight; + } + } + out[out_index + 0] = accum[0] / accum_weight; + out[out_index + 1] = accum[1] / accum_weight; + out[out_index + 2] = accum[2] / accum_weight; + out[out_index + 3] = accum[3] / accum_weight; + } + } + + MEM_freeN(gausstab_x); + if (gausstab_x != gausstab_y) { + MEM_freeN(gausstab_y); + } +#undef INDEX +} + +static void do_gaussian_blur_effect_float(Sequence *seq, + int start_line, + int x, int y, + int frame_width, int frame_height, + float *rect, + float *out) +{ +#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4) + GaussianBlurVars *data = seq->effectdata; + const int size_x = (int) (data->size_x + 0.5f), + size_y = (int) (data->size_y + 0.5f); + int i, j; + + /* Make gaussian weight tabke. */ + float *gausstab_x, *gausstab_y; + gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x); + if (data->size_x == data->size_y) { + gausstab_y = gausstab_x; + } + else { + gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y); + } + + for (i = 0; i < y; ++i) { + for (j = 0; j < x; ++j) { + int out_index = INDEX(j, i); + int current_x, current_y; + float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float accum_weight = 0.0f; + for (current_y = i - size_y; + current_y <= i + size_y; + ++current_y) + { + float weight; + if (current_y < -start_line || + current_y + start_line >= frame_height) + { + /* Out of bounds. */ + continue; + } + + for (current_x = j - size_x; + current_x <= j + size_x; + ++current_x) + { + int index = INDEX(current_x, current_y + start_line); + if (current_x < 0 || current_x >= frame_width) { + /* Out of bounds. */ + continue; + } + + if (size_x != 0 && size_y != 0) { + weight = gausstab_x[current_x - j + size_x] * + gausstab_y[current_y - i + size_y]; + } + else if (size_x == 0) { + weight = gausstab_y[current_y - i + size_y]; + } + else { + weight = gausstab_x[current_x - j + size_x]; + } + madd_v4_v4fl(accum, &rect[index], weight); + accum_weight += weight; + } + } + mul_v4_v4fl(&out[out_index], accum, 1.0f / accum_weight); + } + } + + MEM_freeN(gausstab_x); + if (gausstab_x != gausstab_y) { + MEM_freeN(gausstab_y); + } +#undef INDEX +} + +static void do_gaussian_blur_effect(const SeqRenderData *context, + Sequence *seq, + float UNUSED(cfra), + float UNUSED(facf0), + float UNUSED(facf1), + ImBuf *ibuf1, + ImBuf *ibuf2, + ImBuf *UNUSED(ibuf3), + int start_line, + int total_lines, + ImBuf *out) +{ + if (out->rect_float) { + float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; + + slice_get_float_buffers(context, + ibuf1, ibuf2, + NULL, + out, + start_line, + &rect1, + &rect2, + NULL, + &rect_out); + + do_gaussian_blur_effect_float(seq, + start_line, + context->rectx, + total_lines, + context->rectx, + context->recty, + ibuf1->rect_float, + rect_out); + } + else { + unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; + + slice_get_byte_buffers(context, + ibuf1, ibuf2, + NULL, + out, + start_line, + &rect1, + &rect2, + NULL, + &rect_out); + + do_gaussian_blur_effect_byte(seq, + start_line, + context->rectx, + total_lines, + context->rectx, + context->recty, + (unsigned char *) ibuf1->rect, + rect_out); + } +} + /*********************** sequence effect factory *************************/ static void init_noop(Sequence *UNUSED(seq)) @@ -2767,6 +3061,15 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.early_out = early_out_adjustment; rval.execute = do_adjustment; break; + case SEQ_TYPE_GAUSSIAN_BLUR: + rval.multithreaded = true; + rval.init = init_gaussian_blur_effect; + rval.num_inputs = num_inputs_gaussian_blur; + rval.free = free_gaussian_blur_effect; + rval.copy = copy_gaussian_blur_effect; + rval.early_out = early_out_gaussian_blur; + rval.execute_slice = do_gaussian_blur_effect; + break; } return rval; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index f5efe04951f..c9647b05ce7 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -758,7 +758,7 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r int prev_startdisp = 0, prev_enddisp = 0; /* note: don't rename the strip, will break animation curves */ - if (ELEM7(seq->type, + if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE, SEQ_TYPE_META, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) == 0) { @@ -994,28 +994,29 @@ void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq) static const char *give_seqname_by_type(int type) { switch (type) { - case SEQ_TYPE_META: return "Meta"; - case SEQ_TYPE_IMAGE: return "Image"; - case SEQ_TYPE_SCENE: return "Scene"; - case SEQ_TYPE_MOVIE: return "Movie"; - case SEQ_TYPE_MOVIECLIP: return "Clip"; - case SEQ_TYPE_MASK: return "Mask"; - case SEQ_TYPE_SOUND_RAM: return "Audio"; - case SEQ_TYPE_CROSS: return "Cross"; - case SEQ_TYPE_GAMCROSS: return "Gamma Cross"; - case SEQ_TYPE_ADD: return "Add"; - case SEQ_TYPE_SUB: return "Sub"; - case SEQ_TYPE_MUL: return "Mul"; - case SEQ_TYPE_ALPHAOVER: return "Alpha Over"; - case SEQ_TYPE_ALPHAUNDER: return "Alpha Under"; - case SEQ_TYPE_OVERDROP: return "Over Drop"; - case SEQ_TYPE_WIPE: return "Wipe"; - case SEQ_TYPE_GLOW: return "Glow"; - case SEQ_TYPE_TRANSFORM: return "Transform"; - case SEQ_TYPE_COLOR: return "Color"; - case SEQ_TYPE_MULTICAM: return "Multicam"; - case SEQ_TYPE_ADJUSTMENT: return "Adjustment"; - case SEQ_TYPE_SPEED: return "Speed"; + case SEQ_TYPE_META: return "Meta"; + case SEQ_TYPE_IMAGE: return "Image"; + case SEQ_TYPE_SCENE: return "Scene"; + case SEQ_TYPE_MOVIE: return "Movie"; + case SEQ_TYPE_MOVIECLIP: return "Clip"; + case SEQ_TYPE_MASK: return "Mask"; + case SEQ_TYPE_SOUND_RAM: return "Audio"; + case SEQ_TYPE_CROSS: return "Cross"; + case SEQ_TYPE_GAMCROSS: return "Gamma Cross"; + case SEQ_TYPE_ADD: return "Add"; + case SEQ_TYPE_SUB: return "Sub"; + case SEQ_TYPE_MUL: return "Mul"; + case SEQ_TYPE_ALPHAOVER: return "Alpha Over"; + case SEQ_TYPE_ALPHAUNDER: return "Alpha Under"; + case SEQ_TYPE_OVERDROP: return "Over Drop"; + case SEQ_TYPE_WIPE: return "Wipe"; + case SEQ_TYPE_GLOW: return "Glow"; + case SEQ_TYPE_TRANSFORM: return "Transform"; + case SEQ_TYPE_COLOR: return "Color"; + case SEQ_TYPE_MULTICAM: return "Multicam"; + case SEQ_TYPE_ADJUSTMENT: return "Adjustment"; + case SEQ_TYPE_SPEED: return "Speed"; + case SEQ_TYPE_GAUSSIAN_BLUR: return "Gaussian Blur"; default: return NULL; } @@ -2224,7 +2225,7 @@ static ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, con init_data.out = out; IMB_processor_apply_threaded(out->y, sizeof(RenderEffectThread), &init_data, - render_effect_execute_init_handle, render_effect_execute_do_thread); + render_effect_execute_init_handle, render_effect_execute_do_thread); return out; } @@ -2808,7 +2809,7 @@ static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, floa float nr = give_stripelem_index(seq, cfra); /* all effects are handled similarly with the exception of speed effect */ int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : seq->type; - bool is_preprocessed = !ELEM3(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE); + bool is_preprocessed = !ELEM(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE); ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF); @@ -2875,7 +2876,7 @@ static bool seq_must_swap_input_in_blend_mode(Sequence *seq) /* bad hack, to fix crazy input ordering of * those two effects */ - if (ELEM3(seq->blend_mode, SEQ_TYPE_ALPHAOVER, SEQ_TYPE_ALPHAUNDER, SEQ_TYPE_OVERDROP)) { + if (ELEM(seq->blend_mode, SEQ_TYPE_ALPHAOVER, SEQ_TYPE_ALPHAUNDER, SEQ_TYPE_OVERDROP)) { swap_input = true; } @@ -2960,7 +2961,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq /* Some of the blend modes are unclear how to apply with only single input, * or some of them will just produce an empty result.. */ - if (ELEM3(seq->blend_mode, SEQ_BLEND_REPLACE, SEQ_TYPE_CROSS, SEQ_TYPE_ALPHAOVER)) { + if (ELEM(seq->blend_mode, SEQ_BLEND_REPLACE, SEQ_TYPE_CROSS, SEQ_TYPE_ALPHAOVER)) { int early_out; if (seq->blend_mode == SEQ_BLEND_REPLACE) { early_out = EARLY_NO_INPUT; @@ -3512,16 +3513,28 @@ bool BKE_sequence_single_check(Sequence *seq) } /* check if the selected seq's reference unselected seq's */ -bool BKE_sequence_base_isolated_sel_check(ListBase *seqbase) +bool BKE_sequence_base_isolated_sel_check(ListBase *seqbase, bool one_only) { Sequence *seq; - /* is there more than 1 select */ + /* is there a valid selection select */ bool ok = false; + /* is there one selected already? */ + bool first = false; for (seq = seqbase->first; seq; seq = seq->next) { if (seq->flag & SELECT) { - ok = true; - break; + if (one_only) { + ok = true; + break; + } + else { + if (first) { + ok = true; + break; + } + else + first = true; + } } } @@ -3688,7 +3701,7 @@ Sequence *BKE_sequencer_foreground_frame_get(Scene *scene, int frame) if (seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame) continue; /* only use elements you can see - not */ - if (ELEM5(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR)) { + if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR)) { if (seq->machine > best_machine) { best_seq = seq; best_machine = seq->machine; diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index e2cc7b84f95..d2a4d15a2c6 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -50,6 +50,7 @@ #include "BKE_lattice.h" #include "BKE_deform.h" +#include "BKE_mesh.h" /* for OMP limits. */ #include "BKE_subsurf.h" #include "BKE_editmesh.h" @@ -65,57 +66,6 @@ /* Util macros */ #define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n")) -/* get derived mesh */ -/* TODO is anyfunction that does this? returning the derivedFinal without we caring if its in edit mode or not? */ -DerivedMesh *object_get_derived_final(Object *ob, bool for_render) -{ - Mesh *me = ob->data; - BMEditMesh *em = me->edit_btmesh; - - if (for_render) { - /* TODO(sergey): use proper derived render here in the future. */ - return ob->derivedFinal; - } - - if (em) { - DerivedMesh *dm = em->derivedFinal; - return dm; - } - - return ob->derivedFinal; -} - -/* Space transform */ -void space_transform_from_matrixs(SpaceTransform *data, float local[4][4], float target[4][4]) -{ - float itarget[4][4]; - invert_m4_m4(itarget, target); - mul_m4_m4m4(data->local2target, itarget, local); - invert_m4_m4(data->target2local, data->local2target); -} - -void space_transform_apply(const SpaceTransform *data, float co[3]) -{ - mul_v3_m4v3(co, ((SpaceTransform *)data)->local2target, co); -} - -void space_transform_invert(const SpaceTransform *data, float co[3]) -{ - mul_v3_m4v3(co, ((SpaceTransform *)data)->target2local, co); -} - -static void space_transform_apply_normal(const SpaceTransform *data, float no[3]) -{ - mul_mat3_m4_v3(((SpaceTransform *)data)->local2target, no); - normalize_v3(no); /* TODO: could we just determine de scale value from the matrix? */ -} - -static void space_transform_invert_normal(const SpaceTransform *data, float no[3]) -{ - mul_mat3_m4_v3(((SpaceTransform *)data)->target2local, no); - normalize_v3(no); /* TODO: could we just determine de scale value from the matrix? */ -} - /* * Shrinkwrap to the nearest vertex * @@ -135,12 +85,12 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) OUT_OF_MEMORY(); return; } - + /* Setup nearest */ nearest.index = -1; nearest.dist_sq = FLT_MAX; #ifndef __APPLE__ -#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData, calc) schedule(static) +#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData, calc) schedule(static) if(calc->numVerts > BKE_MESH_OMP_LIMIT) #endif for (i = 0; i < calc->numVerts; ++i) { float *co = calc->vertexCos[i]; @@ -158,7 +108,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) else { copy_v3_v3(tmp_co, co); } - space_transform_apply(&calc->local2target, tmp_co); + BLI_space_transform_apply(&calc->local2target, tmp_co); /* Use local proximity heuristics (to reduce the nearest search) * @@ -184,7 +134,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) /* Convert the coordinates back to mesh coordinates */ copy_v3_v3(tmp_co, nearest.co); - space_transform_invert(&calc->local2target, tmp_co); + BLI_space_transform_invert(&calc->local2target, tmp_co); interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ } @@ -223,11 +173,11 @@ bool BKE_shrinkwrap_project_normal( /* Apply space transform (TODO readjust dist) */ if (transf) { copy_v3_v3(tmp_co, vert); - space_transform_apply(transf, tmp_co); + BLI_space_transform_apply(transf, tmp_co); co = tmp_co; copy_v3_v3(tmp_no, dir); - space_transform_apply_normal(transf, tmp_no); + BLI_space_transform_apply_normal(transf, tmp_no); no = tmp_no; #ifdef USE_DIST_CORRECT @@ -246,7 +196,7 @@ bool BKE_shrinkwrap_project_normal( if (hit_tmp.index != -1) { /* invert the normal first so face culling works on rotated objects */ if (transf) { - space_transform_invert_normal(transf, hit_tmp.no); + BLI_space_transform_invert_normal(transf, hit_tmp.no); } if (options & (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)) { @@ -261,7 +211,7 @@ bool BKE_shrinkwrap_project_normal( if (transf) { /* Inverting space transform (TODO make coeherent with the initial dist readjust) */ - space_transform_invert(transf, hit_tmp.co); + BLI_space_transform_invert(transf, hit_tmp.co); #ifdef USE_DIST_CORRECT hit_tmp.dist = len_v3v3(vert, hit_tmp.co); #endif @@ -326,7 +276,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for auxMesh = object_get_derived_final(calc->smd->auxTarget, for_render); if (!auxMesh) return; - SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget); + BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget); } /* After sucessufuly build the trees, start projection vertexs */ @@ -335,7 +285,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for { #ifndef __APPLE__ -#pragma omp parallel for private(i, hit) schedule(static) +#pragma omp parallel for private(i, hit) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT) #endif for (i = 0; i < calc->numVerts; ++i) { float *co = calc->vertexCos[i]; @@ -445,7 +395,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) /* Find the nearest vertex */ #ifndef __APPLE__ -#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc, treeData) schedule(static) +#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc, treeData) schedule(static) if(calc->numVerts > BKE_MESH_OMP_LIMIT) #endif for (i = 0; i < calc->numVerts; ++i) { float *co = calc->vertexCos[i]; @@ -460,7 +410,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) else { copy_v3_v3(tmp_co, co); } - space_transform_apply(&calc->local2target, tmp_co); + BLI_space_transform_apply(&calc->local2target, tmp_co); /* Use local proximity heuristics (to reduce the nearest search) * @@ -494,7 +444,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) } /* Convert the coordinates back to mesh coordinates */ - space_transform_invert(&calc->local2target, tmp_co); + BLI_space_transform_invert(&calc->local2target, tmp_co); interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ } } @@ -537,7 +487,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM /* TODO there might be several "bugs" on non-uniform scales matrixs * because it will no longer be nearest surface, not sphere projection * because space has been deformed */ - SPACE_TRANSFORM_SETUP(&calc.local2target, ob, smd->target); + BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, smd->target); /* TODO: smd->keepDist is in global units.. must change to local */ calc.keepDist = smd->keepDist; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 12a19381e9d..0bd9517dcfd 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -41,6 +41,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" @@ -2290,18 +2291,23 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, DMSetDrawOptionsTex drawParams, DMSetDrawOptions drawParamsMapped, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag flag) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; MCol *mcol = dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL); MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE); + MTFace *tf_stencil_base = NULL; + MTFace *tf_stencil = NULL; + MTFace *tf_base; short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL); DMFlagMat *faceFlags = ccgdm->faceFlags; DMDrawOption draw_option; int i, totface, gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; + int gridOffset = 0; + int mat_nr_cache = -1; (void) compareDrawOptions; @@ -2315,6 +2321,12 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, mcol = dm->getTessFaceDataArray(dm, CD_TEXTURE_MCOL); totface = ccgSubSurf_getNumFaces(ss); + + if (flag & DM_DRAW_USE_TEXPAINT_UV) { + int stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE); + tf_stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil); + } + for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); @@ -2333,6 +2345,18 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, mat_nr = 0; } + /* texture painting, handle the correct uv layer here */ + if (flag & DM_DRAW_USE_TEXPAINT_UV) { + if (mat_nr != mat_nr_cache) { + tf_base = DM_paint_uvlayer_active_get(dm, mat_nr); + + mat_nr_cache = mat_nr; + } + tf = tf_base + gridOffset; + tf_stencil = tf_stencil_base + gridOffset; + gridOffset += gridFaces * gridFaces * numVerts; + } + if (drawParams) draw_option = drawParams(tf, (mcol != NULL), mat_nr); else if (index != ORIGINDEX_NONE) @@ -2373,26 +2397,31 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, float *d_co = CCG_grid_elem_co(&key, faceGridData, x, y + 1); if (tf) glTexCoord2fv(tf->uv[1]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[1]); if (cp) glColor3ub(cp[7], cp[6], cp[5]); glNormal3sv(ln[0][1]); glVertex3fv(d_co); if (tf) glTexCoord2fv(tf->uv[2]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[2]); if (cp) glColor3ub(cp[11], cp[10], cp[9]); glNormal3sv(ln[0][2]); glVertex3fv(c_co); if (tf) glTexCoord2fv(tf->uv[3]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[3]); if (cp) glColor3ub(cp[15], cp[14], cp[13]); glNormal3sv(ln[0][3]); glVertex3fv(b_co); if (tf) glTexCoord2fv(tf->uv[0]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[0]); if (cp) glColor3ub(cp[3], cp[2], cp[1]); glNormal3sv(ln[0][0]); glVertex3fv(a_co); if (tf) tf++; + if (tf_stencil) tf_stencil++; if (cp) cp += 16; ln++; } @@ -2408,17 +2437,20 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, b = CCG_grid_elem(&key, faceGridData, x, y + 1); if (tf) glTexCoord2fv(tf->uv[0]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[0]); if (cp) glColor3ub(cp[3], cp[2], cp[1]); glNormal3fv(CCG_elem_no(&key, a)); glVertex3fv(CCG_elem_co(&key, a)); if (tf) glTexCoord2fv(tf->uv[1]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[1]); if (cp) glColor3ub(cp[7], cp[6], cp[5]); glNormal3fv(CCG_elem_no(&key, b)); glVertex3fv(CCG_elem_co(&key, b)); if (x != gridFaces - 1) { if (tf) tf++; + if (tf_stencil) tf_stencil++; if (cp) cp += 16; } } @@ -2427,16 +2459,19 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, b = CCG_grid_elem(&key, faceGridData, x, y + 1); if (tf) glTexCoord2fv(tf->uv[3]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[3]); if (cp) glColor3ub(cp[15], cp[14], cp[13]); glNormal3fv(CCG_elem_no(&key, a)); glVertex3fv(CCG_elem_co(&key, a)); if (tf) glTexCoord2fv(tf->uv[2]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[2]); if (cp) glColor3ub(cp[11], cp[10], cp[9]); glNormal3fv(CCG_elem_no(&key, b)); glVertex3fv(CCG_elem_co(&key, b)); if (tf) tf++; + if (tf_stencil) tf_stencil++; if (cp) cp += 16; glEnd(); @@ -2455,22 +2490,27 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, ccgDM_glNormalFast(a_co, b_co, c_co, d_co); if (tf) glTexCoord2fv(tf->uv[1]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[1]); if (cp) glColor3ub(cp[7], cp[6], cp[5]); glVertex3fv(d_co); if (tf) glTexCoord2fv(tf->uv[2]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[2]); if (cp) glColor3ub(cp[11], cp[10], cp[9]); glVertex3fv(c_co); if (tf) glTexCoord2fv(tf->uv[3]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[3]); if (cp) glColor3ub(cp[15], cp[14], cp[13]); glVertex3fv(b_co); if (tf) glTexCoord2fv(tf->uv[0]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[0]); if (cp) glColor3ub(cp[3], cp[2], cp[1]); glVertex3fv(a_co); if (tf) tf++; + if (tf_stencil) tf_stencil++; if (cp) cp += 16; } } @@ -2483,17 +2523,17 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, static void ccgDM_drawFacesTex(DerivedMesh *dm, DMSetDrawOptionsTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag flag) { - ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData); + ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag); } static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag flag) { - ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData); + ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag); } static void ccgDM_drawUVEdges(DerivedMesh *dm) diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 90687ef9916..4cd85fb342e 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -1286,6 +1286,19 @@ void txt_sel_all(Text *text) text->selc = text->sell->len; } +/** + * Reverse of #txt_pop_sel + * Clears the selection and ensures the cursor is located + * at the selection (where the cursor is visually while editing). + */ +void txt_sel_clear(Text *text) +{ + if (text->sell) { + text->curl = text->sell; + text->curc = text->selc; + } +} + void txt_sel_line(Text *text) { if (!text) return; @@ -2697,7 +2710,7 @@ void txt_indent(Text *text) /* hardcoded: TXT_TABSIZE = 4 spaces: */ int spaceslen = TXT_TABSIZE; - if (ELEM3(NULL, text, text->curl, text->sell)) { + if (ELEM(NULL, text, text->curl, text->sell)) { return; } @@ -2764,7 +2777,7 @@ void txt_unindent(Text *text) /* hardcoded: TXT_TABSIZE = 4 spaces: */ int spaceslen = TXT_TABSIZE; - if (ELEM3(NULL, text, text->curl, text->sell)) { + if (ELEM(NULL, text, text->curl, text->sell)) { return; } diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index bb956cb085c..b1981a3a804 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -41,6 +41,7 @@ #include "BLI_math.h" #include "BLI_kdopbvh.h" #include "BLI_utildefines.h" +#include "BLI_math_color.h" #include "DNA_key_types.h" #include "DNA_object_types.h" @@ -145,12 +146,12 @@ void init_tex_mapping(TexMapping *texmap) 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); + mul_m4_series(texmap->mat, tmat, rmat, smat); 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); + mul_m4_series(texmap->mat, tmat, rmat, smat); } else if (texmap->type == TEXMAP_TYPE_VECTOR) { /* no translation for vectors */ @@ -237,7 +238,7 @@ void init_colorband(ColorBand *coba, bool rangetype) } coba->tot = 2; - + coba->color_mode = COLBAND_BLEND_RGB; } ColorBand *add_colorband(bool rangetype) @@ -252,106 +253,209 @@ ColorBand *add_colorband(bool rangetype) /* ------------------------------------------------------------------------- */ +static float colorband_hue_interp( + const int ipotype_hue, + const float mfac, const float fac, + float h1, float h2) +{ + float h_interp; + int mode = 0; + +#define HUE_INTERP(h_a, h_b) ((mfac * (h_a)) + (fac * (h_b))) +#define HUE_MOD(h) (((h) < 1.0f) ? (h) : (h) - 1.0f) + + h1 = HUE_MOD(h1); + h2 = HUE_MOD(h2); + + BLI_assert(h1 >= 0.0f && h1 < 1.0f); + BLI_assert(h2 >= 0.0f && h2 < 1.0f); + + switch (ipotype_hue) { + case COLBAND_HUE_NEAR: + { + if ((h1 < h2) && (h2 - h1) > +0.5f) mode = 1; + else if ((h1 > h2) && (h2 - h1) < -0.5f) mode = 2; + else mode = 0; + break; + } + case COLBAND_HUE_FAR: + { + if ((h1 < h2) && (h2 - h1) < +0.5f) mode = 1; + else if ((h1 > h2) && (h2 - h1) > -0.5f) mode = 2; + else mode = 0; + break; + } + case COLBAND_HUE_CCW: + { + if (h1 > h2) mode = 2; + else mode = 0; + break; + } + case COLBAND_HUE_CW: + { + if (h1 < h2) mode = 1; + else mode = 0; + break; + } + } + + switch (mode) { + case 0: + h_interp = HUE_INTERP(h1, h2); + break; + case 1: + h_interp = HUE_INTERP(h1 + 1.0f, h2); + h_interp = HUE_MOD(h_interp); + break; + case 2: + h_interp = HUE_INTERP(h1, h2 + 1.0f); + h_interp = HUE_MOD(h_interp); + break; + } + + BLI_assert(h_interp >= 0.0f && h_interp < 1.0f); + +#undef HUE_INTERP +#undef HUE_MOD + + return h_interp; +} + bool do_colorband(const ColorBand *coba, float in, float out[4]) { const CBData *cbd1, *cbd2, *cbd0, *cbd3; - float fac, mfac, t[4]; + float fac; + int ipotype; int a; if (coba == NULL || coba->tot == 0) return 0; cbd1 = coba->data; + + ipotype = (coba->color_mode == COLBAND_BLEND_RGB) ? coba->ipotype : COLBAND_INTERP_LINEAR; + if (coba->tot == 1) { out[0] = cbd1->r; out[1] = cbd1->g; out[2] = cbd1->b; out[3] = cbd1->a; } + else if ((in <= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) { + out[0] = cbd1->r; + out[1] = cbd1->g; + out[2] = cbd1->b; + out[3] = cbd1->a; + } else { - if (in <= cbd1->pos && coba->ipotype < 2) { + CBData left, right; + + /* we're looking for first pos > in */ + for (a = 0; a < coba->tot; a++, cbd1++) if (cbd1->pos > in) break; + + if (a == coba->tot) { + cbd2 = cbd1 - 1; + right = *cbd2; + right.pos = 1.0f; + cbd1 = &right; + } + else if (a == 0) { + left = *cbd1; + left.pos = 0.0f; + cbd2 = &left; + } + else { + cbd2 = cbd1 - 1; + } + + if ((in >= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) { out[0] = cbd1->r; out[1] = cbd1->g; out[2] = cbd1->b; out[3] = cbd1->a; } else { - CBData left, right; - - /* we're looking for first pos > in */ - for (a = 0; a < coba->tot; a++, cbd1++) if (cbd1->pos > in) break; - - if (a == coba->tot) { - cbd2 = cbd1 - 1; - right = *cbd2; - right.pos = 1.0f; - cbd1 = &right; - } - else if (a == 0) { - left = *cbd1; - left.pos = 0.0f; - cbd2 = &left; + + if (cbd2->pos != cbd1->pos) { + fac = (in - cbd1->pos) / (cbd2->pos - cbd1->pos); } else { - cbd2 = cbd1 - 1; + /* was setting to 0.0 in 2.56 & previous, but this + * is incorrect for the last element, see [#26732] */ + fac = (a != coba->tot) ? 0.0f : 1.0f; } - - if (in >= cbd1->pos && coba->ipotype < 2) { - out[0] = cbd1->r; - out[1] = cbd1->g; - out[2] = cbd1->b; - out[3] = cbd1->a; + + if (ipotype == COLBAND_INTERP_CONSTANT) { + /* constant */ + out[0] = cbd2->r; + out[1] = cbd2->g; + out[2] = cbd2->b; + out[3] = cbd2->a; } - else { - - if (cbd2->pos != cbd1->pos) - fac = (in - cbd1->pos) / (cbd2->pos - cbd1->pos); + else if (ipotype >= COLBAND_INTERP_B_SPLINE) { + /* ipo from right to left: 3 2 1 0 */ + float t[4]; + + if (a >= coba->tot - 1) cbd0 = cbd1; + else cbd0 = cbd1 + 1; + if (a < 2) cbd3 = cbd2; + else cbd3 = cbd2 - 1; + + CLAMP(fac, 0.0f, 1.0f); + + if (ipotype == COLBAND_INTERP_CARDINAL) { + key_curve_position_weights(fac, t, KEY_CARDINAL); + } else { - /* was setting to 0.0 in 2.56 & previous, but this - * is incorrect for the last element, see [#26732] */ - fac = (a != coba->tot) ? 0.0f : 1.0f; + key_curve_position_weights(fac, t, KEY_BSPLINE); + } + + out[0] = t[3] * cbd3->r + t[2] * cbd2->r + t[1] * cbd1->r + t[0] * cbd0->r; + out[1] = t[3] * cbd3->g + t[2] * cbd2->g + t[1] * cbd1->g + t[0] * cbd0->g; + out[2] = t[3] * cbd3->b + t[2] * cbd2->b + t[1] * cbd1->b + t[0] * cbd0->b; + out[3] = t[3] * cbd3->a + t[2] * cbd2->a + t[1] * cbd1->a + t[0] * cbd0->a; + CLAMP(out[0], 0.0f, 1.0f); + CLAMP(out[1], 0.0f, 1.0f); + CLAMP(out[2], 0.0f, 1.0f); + CLAMP(out[3], 0.0f, 1.0f); + } + else { + float mfac; + + if (ipotype == COLBAND_INTERP_EASE) { + mfac = fac * fac; + fac = 3.0f * mfac - 2.0f * mfac * fac; } - - if (coba->ipotype == 4) { - /* constant */ - out[0] = cbd2->r; - out[1] = cbd2->g; - out[2] = cbd2->b; - out[3] = cbd2->a; - return 1; + + mfac = 1.0f - fac; + + if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSV)) { + float col1[3], col2[3]; + + rgb_to_hsv_v(&cbd1->r, col1); + rgb_to_hsv_v(&cbd2->r, col2); + + out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]); + out[1] = mfac * col1[1] + fac * col2[1]; + out[2] = mfac * col1[2] + fac * col2[2]; + out[3] = mfac * cbd1->a + fac * cbd2->a; + + hsv_to_rgb_v(out, out); } - - if (coba->ipotype >= 2) { - /* ipo from right to left: 3 2 1 0 */ - - if (a >= coba->tot - 1) cbd0 = cbd1; - else cbd0 = cbd1 + 1; - if (a < 2) cbd3 = cbd2; - else cbd3 = cbd2 - 1; - - CLAMP(fac, 0.0f, 1.0f); - - if (coba->ipotype == 3) - key_curve_position_weights(fac, t, KEY_CARDINAL); - else - key_curve_position_weights(fac, t, KEY_BSPLINE); - - out[0] = t[3] * cbd3->r + t[2] * cbd2->r + t[1] * cbd1->r + t[0] * cbd0->r; - out[1] = t[3] * cbd3->g + t[2] * cbd2->g + t[1] * cbd1->g + t[0] * cbd0->g; - out[2] = t[3] * cbd3->b + t[2] * cbd2->b + t[1] * cbd1->b + t[0] * cbd0->b; - out[3] = t[3] * cbd3->a + t[2] * cbd2->a + t[1] * cbd1->a + t[0] * cbd0->a; - CLAMP(out[0], 0.0f, 1.0f); - CLAMP(out[1], 0.0f, 1.0f); - CLAMP(out[2], 0.0f, 1.0f); - CLAMP(out[3], 0.0f, 1.0f); + else if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSL)) { + float col1[3], col2[3]; + + rgb_to_hsl_v(&cbd1->r, col1); + rgb_to_hsl_v(&cbd2->r, col2); + + out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]); + out[1] = mfac * col1[1] + fac * col2[1]; + out[2] = mfac * col1[2] + fac * col2[2]; + out[3] = mfac * cbd1->a + fac * cbd2->a; + + hsl_to_rgb_v(out, out); } else { - - if (coba->ipotype == 1) { /* EASE */ - mfac = fac * fac; - fac = 3.0f * mfac - 2.0f * mfac * fac; - } - mfac = 1.0f - fac; - + /* COLBAND_BLEND_RGB */ out[0] = mfac * cbd1->r + fac * cbd2->r; out[1] = mfac * cbd1->g + fac * cbd2->g; out[2] = mfac * cbd1->b + fac * cbd2->b; @@ -408,19 +512,18 @@ CBData *colorband_element_add(struct ColorBand *coba, float position) if (coba->tot == MAXCOLORBAND) { return NULL; } - else if (coba->tot > 0) { + else { CBData *xnew; - float col[4]; - - do_colorband(coba, position, col); xnew = &coba->data[coba->tot]; xnew->pos = position; - xnew->r = col[0]; - xnew->g = col[1]; - xnew->b = col[2]; - xnew->a = col[3]; + if (coba->tot != 0) { + do_colorband(coba, position, &xnew->r); + } + else { + zero_v4(&xnew->r); + } } coba->tot++; @@ -474,7 +577,8 @@ void BKE_texture_free(Tex *tex) void default_tex(Tex *tex) { - tex->type = TEX_CLOUDS; + tex->type = TEX_IMAGE; + tex->ima = NULL; tex->stype = 0; tex->flag = TEX_CHECKER_ODD; tex->imaflag = TEX_INTERPOL | TEX_MIPMAP | TEX_USEALPHA; @@ -592,7 +696,7 @@ Tex *add_texture(Main *bmain, const char *name) void default_mtex(MTex *mtex) { - mtex->texco = TEXCO_ORCO; + mtex->texco = TEXCO_UV; mtex->mapto = MAP_COL; mtex->object = NULL; mtex->projx = PROJ_X; @@ -747,8 +851,7 @@ Tex *localize_texture(Tex *tex) { Tex *texn; - texn = BKE_libblock_copy(&tex->id); - BLI_remlink(&G.main->tex, texn); + texn = BKE_libblock_copy_nolib(&tex->id, false); /* image texture: BKE_texture_free also doesn't decrease */ diff --git a/source/blender/blenkernel/intern/tracking_region_tracker.c b/source/blender/blenkernel/intern/tracking_region_tracker.c index 76b7ad5d982..6300e29f516 100644 --- a/source/blender/blenkernel/intern/tracking_region_tracker.c +++ b/source/blender/blenkernel/intern/tracking_region_tracker.c @@ -501,7 +501,7 @@ static void tracking_scale_marker_search(const MovieTrackingMarker *old_marker, static void tracking_insert_new_marker(MovieTrackingContext *context, MovieTrackingTrack *track, const MovieTrackingMarker *old_marker, int curfra, bool tracked, int frame_width, int frame_height, - double dst_pixel_x[5], double dst_pixel_y[5]) + const double dst_pixel_x[5], const double dst_pixel_y[5]) { MovieTrackingMarker new_marker; int frame_delta = context->backwards ? -1 : 1; diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index ffbdf5cb486..eb224020977 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -82,7 +82,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, int width, int height, - float firstmedian[2], float median[2], + const float firstmedian[2], const float median[2], float translation[2], float *scale, float *angle) { MovieTrackingStabilization *stab = &tracking->stabilization; @@ -439,6 +439,6 @@ void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */ /* compose transformation matrix */ - mul_serie_m4(mat, translation_mat, center_mat, aspect_mat, rotation_mat, inv_aspect_mat, - scale_mat, inv_center_mat, NULL); + mul_m4_series(mat, translation_mat, center_mat, aspect_mat, rotation_mat, inv_aspect_mat, + scale_mat, inv_center_mat); } diff --git a/source/blender/blenkernel/intern/treehash.c b/source/blender/blenkernel/intern/treehash.c index fb55e3d2137..a65bd28da97 100644 --- a/source/blender/blenkernel/intern/treehash.c +++ b/source/blender/blenkernel/intern/treehash.c @@ -59,7 +59,7 @@ static TseGroup *tse_group_create(void) static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem) { - if (tse_group->size == tse_group->allocated) { + if (UNLIKELY(tse_group->size == tse_group->allocated)) { tse_group->allocated *= 2; tse_group->elems = MEM_reallocN(tse_group->elems, sizeof(TreeStoreElem *) * tse_group->allocated); } diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index 8aca9f78702..5a2c77b5619 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -41,6 +41,8 @@ # include "BLI_winstuff.h" #endif +/* no BKE or DNA includes! */ + #define TEMP_STR_SIZE 256 #define SEP_CHR '#' @@ -349,7 +351,7 @@ static void unit_dual_convert(double value, bUnitCollection *usys, bUnitDef **un static size_t unit_as_string(char *str, int len_max, double value, int prec, bUnitCollection *usys, /* non exposed options */ - bUnitDef *unit, char pad) + const bUnitDef *unit, char pad) { double value_conv; size_t len, i; @@ -456,7 +458,7 @@ size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system return unit_as_string(str, len_max, value, prec, usys, NULL, pad ? ' ' : '\0'); } -BLI_INLINE int isalpha_or_utf8(const int ch) +BLI_INLINE bool isalpha_or_utf8(const int ch) { return (ch >= 128 || isalpha(ch)); } @@ -493,11 +495,11 @@ static const char *unit_find_str(const char *str, const char *substr) * * "1m1cm+2mm" - Original value * "1*1#1*0.01#+2*0.001#" - Replace numbers - * "1*1,1*0.01 +2*0.001 " - Add comma's if ( - + * / % ^ < > ) not found in between + * "1*1+1*0.01 +2*0.001 " - Add add signs if ( + - * / | & ~ < > ^ ! = % ) not found in between * */ -/* not too strict, (- = * /) are most common */ +/* not too strict, (+ - * /) are most common */ static bool ch_is_op(char op) { switch (op) { @@ -514,9 +516,11 @@ static bool ch_is_op(char op) case '!': case '=': case '%': - return 1; + return true; + break; default: - return 0; + return false; + break; } } @@ -579,14 +583,42 @@ static int unit_replace(char *str, int len_max, char *str_tmp, double scale_pref return ofs; } -static int unit_find(const char *str, bUnitDef *unit) +static bool unit_find(const char *str, bUnitDef *unit) { - if (unit_find_str(str, unit->name_short)) return 1; - if (unit_find_str(str, unit->name_plural)) return 1; - if (unit_find_str(str, unit->name_alt)) return 1; - if (unit_find_str(str, unit->name)) return 1; + if (unit_find_str(str, unit->name_short)) return true; + if (unit_find_str(str, unit->name_plural)) return true; + if (unit_find_str(str, unit->name_alt)) return true; + if (unit_find_str(str, unit->name)) return true; - return 0; + return false; +} + +static bUnitDef *unit_detect_from_str(bUnitCollection *usys, const char *str, const char *str_prev) +{ + /* Try to find a default unit from current or previous string. + * This allows us to handle cases like 2 + 2mm, people would expect to get 4mm, not 2.002m! + * Note this does not handle corner cases like 2 + 2cm + 1 + 2.5mm... We can't support everything. */ + bUnitDef *unit = NULL; + + /* see which units the new value has */ + for (unit = usys->units; unit->name; unit++) { + if (unit_find(str, unit)) + break; + } + /* Else, try to infer the default unit from the previous string. */ + if (str_prev && (unit == NULL || unit->name == NULL)) { + /* see which units the original value had */ + for (unit = usys->units; unit->name; unit++) { + if (unit_find(str_prev, unit)) + break; + } + } + /* Else, fall back to default unit. */ + if (unit == NULL || unit->name == NULL) { + unit = unit_default(usys); + } + + return unit; } /* make a copy of the string that replaces the units with numbers @@ -597,37 +629,58 @@ static int unit_find(const char *str, bUnitDef *unit) * 10.1km -> 10.1*1000.0 * ...will be resolved by python. * - * values will be split by a comma's - * 5'2" -> 5*0.3048, 2*0.0254 + * values will be split by an add sign + * 5'2" -> 5*0.3048 + 2*0.0254 * * str_prev is optional, when valid it is used to get a base unit when none is set. * * return true of a change was made. */ -int bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type) +bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type) { bUnitCollection *usys = unit_get_system(system, type); - bUnitDef *unit; + bUnitDef *unit = NULL, *default_unit; + double scale_pref_base = scale_pref; char str_tmp[TEMP_STR_SIZE]; - int changed = 0; + bool changed = false; if (usys == NULL || usys->units[0].name == NULL) { - return 0; + return changed; } /* make lowercase */ BLI_ascii_strtolower(str, len_max); + /* Try to find a default unit from current or previous string. */ + default_unit = unit_detect_from_str(usys, str, str_prev); + + /* We apply the default unit to the whole expression (default unit is now the reference '1.0' one). */ + scale_pref_base *= default_unit->scalar; + + /* Apply the default unit on the whole expression, this allows to handle nasty cases like '2+2in'. */ + if (BLI_snprintf(str_tmp, sizeof(str_tmp), "(%s)*%.9g", str, default_unit->scalar) < sizeof(str_tmp)) { + strncpy(str, str_tmp, len_max); + } + else { + /* BLI_snprintf would not fit into str_tmp, cant do much in this case + * check for this because otherwise bUnit_ReplaceString could call its self forever */ + return changed; + } + for (unit = usys->units; unit->name; unit++) { /* in case there are multiple instances */ - while (unit_replace(str, len_max, str_tmp, scale_pref, unit)) + while (unit_replace(str, len_max, str_tmp, scale_pref_base, unit)) changed = true; } unit = NULL; { /* try other unit systems now, so we can evaluate imperial when metric is set for eg. */ + /* Note that checking other systems at that point means we do not support their units as 'default' one. + * In other words, when in metrics, typing '2+2in' will give 2 meters 2 inches, not 4 inches. + * I do think this is the desired behavior! + */ bUnitCollection *usys_iter; int system_iter; @@ -638,7 +691,7 @@ int bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double sca for (unit = usys_iter->units; unit->name; unit++) { int ofs = 0; /* in case there are multiple instances */ - while ((ofs = unit_replace(str + ofs, len_max - ofs, str_tmp, scale_pref, unit))) + while ((ofs = unit_replace(str + ofs, len_max - ofs, str_tmp, scale_pref_base, unit))) changed = true; } } @@ -647,35 +700,9 @@ int bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double sca } unit = NULL; - if (changed == 0) { - /* no units given so infer a unit from the previous string or default */ - if (str_prev) { - /* see which units the original value had */ - for (unit = usys->units; unit->name; unit++) { - if (unit_find(str_prev, unit)) - break; - } - } - - if (unit == NULL || unit->name == NULL) - unit = unit_default(usys); - - /* add the unit prefix and re-run, use brackets in case there was an expression given */ - if (BLI_snprintf(str_tmp, sizeof(str_tmp), "(%s)%s", str, unit->name) < sizeof(str_tmp)) { - strncpy(str, str_tmp, len_max); - return bUnit_ReplaceString(str, len_max, NULL, scale_pref, system, type); - } - else { - /* BLI_snprintf would not fit into str_tmp, cant do much in this case - * check for this because otherwise bUnit_ReplaceString could call its self forever */ - return 0; - } - - } - - /* replace # with commas when there is no operator between it and the next number + /* replace # with add sign when there is no operator between it and the next number * - * "1*1# 3*100# * 3" -> "1 *1, 3 *100 * 3" + * "1*1# 3*100# * 3" -> "1*1+ 3*100 * 3" * * */ { @@ -683,25 +710,19 @@ int bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double sca const char *ch = str; while ((str_found = strchr(str_found, SEP_CHR))) { + bool op_found = false; - int op_found = 0; - /* any operators after this?*/ + /* any operators after this? */ for (ch = str_found + 1; *ch != '\0'; ch++) { - if (*ch == ' ' || *ch == '\t') { - /* do nothing */ - } - else if (ch_is_op(*ch) || *ch == ',') { /* found an op, no need to insert a ',' */ - op_found = 1; - break; - } - else { /* found a non-op character */ - op_found = 0; - break; + continue; } + op_found = (ch_is_op(*ch) || ELEM(*ch, ',', ')')); + break; } - *str_found++ = op_found ? ' ' : ','; + /* If found an op, comma or closing parenthesis, no need to insert a '+', else we need it. */ + *str_found++ = op_found ? ' ' : '+'; } } @@ -771,7 +792,7 @@ double bUnit_BaseScalar(int system, int type) } /* external access */ -int bUnit_IsValid(int system, int type) +bool bUnit_IsValid(int system, int type) { return !(system < 0 || system > UNIT_SYSTEM_TOT || type < 0 || type > B_UNIT_TYPE_TOT); } diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 5065c3ae04f..8e3c92314e6 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -142,8 +142,7 @@ World *localize_world(World *wrld) World *wrldn; int a; - wrldn = BKE_libblock_copy(&wrld->id); - BLI_remlink(&G.main->world, wrldn); + wrldn = BKE_libblock_copy_nolib(&wrld->id, false); for (a = 0; a < MAX_MTEX; a++) { if (wrld->mtex[a]) { diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index a9f040b8650..aef44993912 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -110,7 +110,7 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) } #endif #ifdef WITH_FFMPEG - if (ELEM4(imtype, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_XVID, R_IMF_IMTYPE_THEORA)) { + if (ELEM(imtype, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_XVID, R_IMF_IMTYPE_THEORA)) { mh.start_movie = BKE_ffmpeg_start; mh.append_movie = BKE_ffmpeg_append; mh.end_movie = BKE_ffmpeg_end; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 00dfae9e72a..ca21180000d 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -30,13 +30,6 @@ #include <string.h> #include <stdio.h> -#if defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__) -/* This does not seem necessary or present on MSVC 8, but may be needed in earlier versions? */ -# if _MSC_VER < 1400 -# include <stdint.h> -# endif -#endif - #include <stdlib.h> #include <libavformat/avformat.h> @@ -708,7 +701,7 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex * you have various implementations around. float samples in particular are not always supported. */ const enum AVSampleFormat *p = codec->sample_fmts; - for (; *p!=-1; p++) { + for (; *p != -1; p++) { if (*p == st->codec->sample_fmt) break; } diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h index f8e23629429..3a9d013f796 100644 --- a/source/blender/blenlib/BLI_array.h +++ b/source/blender/blenlib/BLI_array.h @@ -97,8 +97,7 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, (void)0 /* do nothing */ : \ _bli_array_grow_func((void **)&(arr), _##arr##_static, \ sizeof(*(arr)), _##arr##_count, num, \ - "BLI_array." #arr), \ - (void)0) /* msvc2008 needs this */ \ + "BLI_array." #arr)) \ ), \ /* increment the array count, all conditions above are accounted for. */ \ (_##arr##_count += num)) @@ -144,7 +143,7 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, /* set the count of the array, doesn't actually increase the allocated array * size. don't use this unless you know what you're doing. */ -#define BLI_array_length_set(arr, count) \ +#define BLI_array_count_set(arr, count) \ { _##arr##_count = (count); }(void)0 /* only to prevent unused warnings */ @@ -182,5 +181,8 @@ void _bli_array_wrap(void *arr, unsigned int arr_len, size_t arr_stride, int dir #define BLI_array_wrap(arr, arr_len, dir) \ _bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir) +int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p); +#define BLI_array_findindex(arr, arr_len, p) \ + _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p) #endif /* __BLI_ARRAY_H__ */ diff --git a/source/blender/blenlib/BLI_callbacks.h b/source/blender/blenlib/BLI_callbacks.h index 8d5ea91c422..2f963cfac51 100644 --- a/source/blender/blenlib/BLI_callbacks.h +++ b/source/blender/blenlib/BLI_callbacks.h @@ -29,12 +29,20 @@ struct bContext; struct Main; struct ID; +/** + * Common suffix uses: + * - ``_PRE/_POST``: + * For handling discrete non-interactive events. + * - ``_INIT/_COMPLETE/_CANCEL``: + * For handling jobs (which may in turn cause other handlers to be called). + */ typedef enum { BLI_CB_EVT_FRAME_CHANGE_PRE, BLI_CB_EVT_FRAME_CHANGE_POST, BLI_CB_EVT_RENDER_PRE, BLI_CB_EVT_RENDER_POST, BLI_CB_EVT_RENDER_STATS, + BLI_CB_EVT_RENDER_INIT, BLI_CB_EVT_RENDER_COMPLETE, BLI_CB_EVT_RENDER_CANCEL, BLI_CB_EVT_LOAD_PRE, @@ -45,6 +53,7 @@ typedef enum { BLI_CB_EVT_SCENE_UPDATE_POST, BLI_CB_EVT_GAME_PRE, BLI_CB_EVT_GAME_POST, + BLI_CB_EVT_VERSION_UPDATE, BLI_CB_EVT_TOT } eCbEvent; diff --git a/source/blender/blenlib/BLI_dial.h b/source/blender/blenlib/BLI_dial.h new file mode 100644 index 00000000000..c8b57e803d2 --- /dev/null +++ b/source/blender/blenlib/BLI_dial.h @@ -0,0 +1,59 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_DIAL_H__ +#define __BLI_DIAL_H__ + +/** \file BLI_dial.h + * \ingroup bli + * + * \note dials act similar to old rotation based phones and output an angle. + * + * They just are initialized with the center of the dial and a threshold value as input. + * + * When the distance of the current position of the dial from the center + * exceeds the threshold, this position is used to calculate the initial direction. + * After that, the angle from the initial direction is calculated based on + * current and previous directions of the digit, and returned to the user. + * + * Usage examples: + * \code + * float start_position[2] = {0.0f, 0.0f}; + * float current_position[2]; + * float threshold = 0.5f; + * float angle; + * Dial *dial; + * + * dial = BLI_dial_initialize(start_position, threshold); + * + * angle = BLI_dial_angle(dial, curent_position); + * + * MEM_freeN(dial); + * + * \endcode + */ + +typedef struct Dial Dial; + +Dial *BLI_dial_initialize(float start_position[2], float threshold); + +float BLI_dial_angle(Dial *dial, float current_position[2]); + +#endif /* __BLI_DIAL_H__ */ diff --git a/source/blender/blenlib/BLI_dynstr.h b/source/blender/blenlib/BLI_dynstr.h index 484cddd0039..7aa1c30e449 100644 --- a/source/blender/blenlib/BLI_dynstr.h +++ b/source/blender/blenlib/BLI_dynstr.h @@ -54,7 +54,7 @@ void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATT void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...) ATTR_PRINTF_FORMAT(2, 3) ATTR_NONNULL(1, 2); void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, va_list args) ATTR_PRINTF_FORMAT(2, 0) ATTR_NONNULL(1, 2); -int BLI_dynstr_get_len(DynStr *ds) ATTR_NONNULL(); +int BLI_dynstr_get_len(DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); char *BLI_dynstr_get_cstring(DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BLI_dynstr_get_cstring_ex(DynStr *__restrict ds, char *__restrict str) ATTR_NONNULL(); diff --git a/source/blender/blenlib/BLI_edgehash.h b/source/blender/blenlib/BLI_edgehash.h index c0529d9032d..a0455489d24 100644 --- a/source/blender/blenlib/BLI_edgehash.h +++ b/source/blender/blenlib/BLI_edgehash.h @@ -106,6 +106,8 @@ bool BLI_edgeset_add(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); +void BLI_edgeset_flag_set(EdgeSet *es, unsigned int flag); +void BLI_edgeset_flag_clear(EdgeSet *es, unsigned int flag); /* rely on inline api for now */ BLI_INLINE EdgeSetIterator *BLI_edgesetIterator_new(EdgeSet *gs) { return (EdgeSetIterator *)BLI_edgehashIterator_new((EdgeHash *)gs); } @@ -114,5 +116,9 @@ BLI_INLINE void BLI_edgesetIterator_getKey(EdgeSetIterator *esi, unsigned int *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); } +#ifdef DEBUG +double BLI_edgehash_calc_quality(EdgeHash *eh); +double BLI_edgeset_calc_quality(EdgeSet *es); +#endif #endif /* __BLI_EDGEHASH_H__ */ diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index 2d1e1d84882..4f451a6c741 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -62,7 +62,7 @@ int BLI_create_symlink(const char *path, const char *to); /* keep in sync with the definition of struct direntry in BLI_fileops_types.h */ #ifdef WIN32 -# if (defined(_MSC_VER) && (_MSC_VER >= 1500)) || defined(__MINGW64__) +# if defined(_MSC_VER) || defined(__MINGW64__) typedef struct _stat64 BLI_stat_t; # elif defined(__MINGW32__) typedef struct _stati64 BLI_stat_t; @@ -101,7 +101,9 @@ int BLI_access(const char *filename, int mode); bool BLI_file_is_writable(const char *file); bool BLI_file_touch(const char *file); +#if 0 /* UNUSED */ int BLI_file_gzip(const char *from, const char *to); +#endif char *BLI_file_ungzip_to_mem(const char *from_file, int *r_size); size_t BLI_file_descriptor_size(int file); diff --git a/source/blender/blenlib/BLI_fileops_types.h b/source/blender/blenlib/BLI_fileops_types.h index 53c9fa16b70..0e6eab687ad 100644 --- a/source/blender/blenlib/BLI_fileops_types.h +++ b/source/blender/blenlib/BLI_fileops_types.h @@ -46,7 +46,7 @@ struct direntry { char *relname; char *path; #ifdef WIN32 /* keep in sync with the definition of BLI_stat_t in BLI_fileops.h */ -# if (defined(_MSC_VER) && (_MSC_VER >= 1500)) || defined(__MINGW64__) +# if defined(_MSC_VER) || defined(__MINGW64__) struct _stat64 s; # elif defined(__MINGW32__) struct _stati64 s; diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index a59023d4f9b..dd3f62cd6d3 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -139,6 +139,9 @@ unsigned int BLI_ghashutil_uinthash(unsigned int key); unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4]); #define BLI_ghashutil_inthash_v4_p \ ((GSetHashFP)BLI_ghashutil_uinthash_v4) +int BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b); +#define BLI_ghashutil_inthash_v4_cmp \ + BLI_ghashutil_uinthash_v4_cmp unsigned int BLI_ghashutil_inthash_p(const void *ptr); int BLI_ghashutil_intcmp(const void *a, const void *b); @@ -189,6 +192,8 @@ 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_flag_set(GSet *gs, unsigned int flag); +void BLI_gset_flag_clear(GSet *gs, unsigned int flag); void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp); void BLI_gset_insert(GSet *gh, void *key); bool BLI_gset_add(GSet *gs, void *key); @@ -224,6 +229,11 @@ BLI_INLINE bool BLI_gsetIterator_done(GSetIterator *gsi) { return BLI_ghashItera BLI_gsetIterator_done(&gs_iter_) == false; \ BLI_gsetIterator_step(&gs_iter_), i_++) +#ifdef DEBUG +double BLI_ghash_calc_quality(GHash *gh); +double BLI_gset_calc_quality(GSet *gs); +#endif + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h index d17897df665..4600d6f6325 100644 --- a/source/blender/blenlib/BLI_gsqueue.h +++ b/source/blender/blenlib/BLI_gsqueue.h @@ -30,8 +30,6 @@ /** \file BLI_gsqueue.h * \ingroup bli - * \brief A generic structure queue (a queue for fixed length - * (generally small) structures. */ typedef struct _GSQueue GSQueue; @@ -46,4 +44,3 @@ void BLI_gsqueue_pushback(GSQueue *gq, const void *item); void BLI_gsqueue_free(GSQueue *gq); #endif /* __BLI_GSQUEUE_H__ */ - diff --git a/source/blender/blenlib/BLI_heap.h b/source/blender/blenlib/BLI_heap.h index 8a157f5e8db..ac9edfd46a2 100644 --- a/source/blender/blenlib/BLI_heap.h +++ b/source/blender/blenlib/BLI_heap.h @@ -35,31 +35,31 @@ typedef void (*HeapFreeFP)(void *ptr); /* Creates a new heap. BLI_memarena is used for allocating nodes. Removed nodes * are recycled, so memory usage will not shrink. */ -Heap *BLI_heap_new_ex(unsigned int tot_reserve); -Heap *BLI_heap_new(void); -void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp); +Heap *BLI_heap_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT; +Heap *BLI_heap_new(void) ATTR_WARN_UNUSED_RESULT; +void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1); /* Insert heap node with a value (often a 'cost') and pointer into the heap, * duplicate values are allowed. */ -HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr); +HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1); /* Remove a heap node. */ -void BLI_heap_remove(Heap *heap, HeapNode *node); +void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1, 2); /* Return 0 if the heap is empty, 1 otherwise. */ -bool BLI_heap_is_empty(Heap *heap); +bool BLI_heap_is_empty(Heap *heap) ATTR_NONNULL(1); /* Return the size of the heap. */ -unsigned int BLI_heap_size(Heap *heap); +unsigned int BLI_heap_size(Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); /* Return the top node of the heap. This is the node with the lowest value. */ -HeapNode *BLI_heap_top(Heap *heap); +HeapNode *BLI_heap_top(Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); /* Pop the top node off the heap and return it's pointer. */ -void *BLI_heap_popmin(Heap *heap); +void *BLI_heap_popmin(Heap *heap) ATTR_NONNULL(1); /* Return the value or pointer of a heap node. */ -float BLI_heap_node_value(HeapNode *heap); -void *BLI_heap_node_ptr(HeapNode *heap); +float BLI_heap_node_value(HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +void *BLI_heap_node_ptr(HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); #endif /* __BLI_HEAP_H__ */ diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h index 7b00fd90bf6..99a5fad397a 100644 --- a/source/blender/blenlib/BLI_kdopbvh.h +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -93,7 +93,7 @@ int BLI_bvhtree_update_node(BVHTree *tree, int index, const float co[3], const f void BLI_bvhtree_update_tree(BVHTree *tree); /* collision/overlap: check two trees if they overlap, alloc's *overlap with length of the int return value */ -BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, unsigned int *result); +BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, unsigned int *r_overlap_tot); float BLI_bvhtree_getepsilon(const BVHTree *tree); diff --git a/source/blender/blenlib/BLI_linklist_stack.h b/source/blender/blenlib/BLI_linklist_stack.h index 84e7130a962..17d40e068b3 100644 --- a/source/blender/blenlib/BLI_linklist_stack.h +++ b/source/blender/blenlib/BLI_linklist_stack.h @@ -116,6 +116,9 @@ # define _BLI_SMALLSTACK_CAST(var) #endif +#define _BLI_SMALLSTACK_FAKEUSER(var) \ + (void)(&(_##var##_type)) + #define BLI_SMALLSTACK_DECLARE(var, type) \ LinkNode *_##var##_stack = NULL, *_##var##_free = NULL, *_##var##_temp = NULL; \ type _##var##_type @@ -133,11 +136,14 @@ _##var##_temp->next = _##var##_stack; \ _##var##_temp->link = data; \ _##var##_stack = _##var##_temp; \ + _BLI_SMALLSTACK_FAKEUSER(var); \ } (void)0 /* internal use, no null check */ #define _BLI_SMALLSTACK_DEL_EX(var_src, var_dst) \ - (void)((_##var_src##_temp = _##var_src##_stack->next), \ + (void)(_BLI_SMALLSTACK_FAKEUSER(var_src), \ + _BLI_SMALLSTACK_FAKEUSER(var_dst), \ + (_##var_src##_temp = _##var_src##_stack->next), \ (_##var_src##_stack->next = _##var_dst##_free), \ (_##var_dst##_free = _##var_src##_stack), \ (_##var_src##_stack = _##var_src##_temp)) \ @@ -180,10 +186,6 @@ SWAP(LinkNode *, _##var_a##_free, _##var_b##_free); \ } (void)0 -#define BLI_SMALLSTACK_FREE(var) { \ - (void)&(_##var##_type); \ -} (void)0 - /** \} */ #endif /* __BLI_LINKLIST_STACK_H__ */ diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index b900b5f21a5..697ba863603 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -76,8 +76,8 @@ void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1); void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2); void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1, 2); void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1); -void BLI_rotatelist_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2); -void BLI_rotatelist_last(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2); +void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2); +void BLI_listbase_rotate_last(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2); /** * Utility functions to avoid first/last references inline all over. @@ -95,27 +95,27 @@ struct LinkData *BLI_genericNodeN(void *data); * * \code{.c} * - * LISTBASE_CIRCULAR_FORWARD_BEGIN (listbase, item, item_init) { + * BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (listbase, item, item_init) { * ...operate on marker... * } - * LISTBASE_CIRCULAR_FORWARD_END (listbase, item, item_init); + * BLI_LISTBASE_CIRCULAR_FORWARD_END (listbase, item, item_init); * * \endcode */ -#define LISTBASE_CIRCULAR_FORWARD_BEGIN(lb, lb_iter, lb_init) \ +#define BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN(lb, lb_iter, lb_init) \ if ((lb)->first && (lb_init || (lb_init = (lb)->first))) { \ lb_iter = lb_init; \ do { -#define LISTBASE_CIRCULAR_FORWARD_END(lb, lb_iter, lb_init) \ +#define BLI_LISTBASE_CIRCULAR_FORWARD_END(lb, lb_iter, lb_init) \ } while ((lb_iter = (lb_iter)->next ? (lb_iter)->next : (lb)->first), \ (lb_iter != lb_init)); \ } -#define LISTBASE_CIRCULAR_BACKWARD_BEGIN(lb, lb_iter, lb_init) \ +#define BLI_LISTBASE_CIRCULAR_BACKWARD_BEGIN(lb, lb_iter, lb_init) \ if ((lb)->last && (lb_init || (lb_init = (lb)->last))) { \ lb_iter = lb_init; \ do { -#define LISTBASE_CIRCULAR_BACKWARD_END(lb, lb_iter, lb_init) \ +#define BLI_LISTBASE_CIRCULAR_BACKWARD_END(lb, lb_iter, lb_init) \ } while ((lb_iter = (lb_iter)->prev ? (lb_iter)->prev : (lb)->last), \ (lb_iter != lb_init)); \ } diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index 54e9349f1f8..5f94f04e0a8 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -75,11 +75,6 @@ #define M_LN10 2.30258509299404568402 #endif -/* non-standard defines, used in some places */ -#ifndef MAXFLOAT -#define MAXFLOAT ((float)3.40282347e+38) -#endif - #if defined(__GNUC__) # define NAN_FLT __builtin_nanf("") #else @@ -147,13 +142,7 @@ static const int NAN_INT = 0x7FC00000; #ifdef WIN32 # if defined(_MSC_VER) -# if (_MSC_VER < 1800) && !defined(isnan) -# define isnan(n) _isnan(n) -# endif # define finite(n) _finite(n) -# if (_MSC_VER < 1800) && !defined(hypot) -# define hypot(a, b) _hypot(a, b) -# endif # endif #endif @@ -163,7 +152,7 @@ static const int NAN_INT = 0x7FC00000; #ifndef CHECK_TYPE #ifdef __GNUC__ #define CHECK_TYPE(var, type) { \ - __typeof(var) *__tmp; \ + typeof(var) *__tmp; \ __tmp = (type *)NULL; \ (void)__tmp; \ } (void)0 @@ -241,11 +230,6 @@ MINLINE int mod_i(int i, int n); MINLINE unsigned int highest_order_bit_i(unsigned int n); MINLINE unsigned short highest_order_bit_s(unsigned short n); -#if defined(_MSC_VER) && (_MSC_VER < 1800) -extern double copysign(double x, double y); -extern double round(double x); -#endif - double double_round(double x, int ndigits); #ifdef BLI_MATH_GCC_WARN_PRAGMA diff --git a/source/blender/blenlib/BLI_math_color_blend.h b/source/blender/blenlib/BLI_math_color_blend.h index d7e9bf50eae..2535a31ccc4 100644 --- a/source/blender/blenlib/BLI_math_color_blend.h +++ b/source/blender/blenlib/BLI_math_color_blend.h @@ -49,6 +49,24 @@ MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]); MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]); MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]); + +MINLINE void blend_color_overlay_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_hardlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_burn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_linearburn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_dodge_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_screen_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_softlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_pinlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_linearlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_difference_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_exclusion_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_color_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_hue_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_saturation_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_luminosity_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); + MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], float t); MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4]); @@ -59,6 +77,24 @@ MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const float src2[4]); MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], const float src2[4]); MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], const float src2[4]); + +MINLINE void blend_color_overlay_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_burn_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_linearburn_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_dodge_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_screen_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_pinlight_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_linearlight_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_difference_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_exclusion_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_color_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_hue_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_saturation_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_luminosity_float(float dst[4], const float src1[4], const float src2[2]); + MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t); #if BLI_MATH_DO_INLINE diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index f4bcc810846..81ca2908619 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -72,6 +72,7 @@ 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]); +float volume_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]); bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]); bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]); @@ -85,8 +86,11 @@ 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 r_close[2], const float p[2], const float l1[2], const float l2[2]); -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_signed_squared_to_plane_v3(const float p[3], const float plane[4]); +float dist_squared_to_plane_v3(const float p[3], const float plane[4]); +float dist_signed_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_squared_to_line_v3(const float p[3], const float l1[3], const float l2[3]); @@ -126,9 +130,14 @@ int isect_line_sphere_v2(const float l1[2], const float l2[2], const float sp[2] int isect_seg_seg_v2_point(const float v1[2], const float v2[2], const float v3[2], const float v4[2], float vi[2]); bool isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]); -int isect_line_line_v3(const float v1[3], const float v2[3], - const float v3[3], const float v4[3], - float i1[3], float i2[3]); +int isect_line_line_epsilon_v3( + const float v1[3], const float v2[3], + const float v3[3], const float v4[3], float i1[3], float i2[3], + const float epsilon); +int isect_line_line_v3( + const float v1[3], const float v2[3], + const float v3[3], const float v4[3], + float i1[3], float i2[3]); bool isect_line_line_strict_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float vi[3], float *r_lambda); @@ -168,6 +177,8 @@ int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2], bool isect_point_tri_v2_cw(const float pt[2], const float v1[2], const float v2[2], const float v3[2]); int isect_point_tri_v2_int(const int x1, const int y1, const int x2, const int y2, const int a, const int b); bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3]); +bool isect_point_tri_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3], + float r_vi[3]); /* axis-aligned bounding box */ bool isect_aabb_aabb_v3(const float min1[3], const float max1[3], const float min2[3], const float max2[3]); @@ -209,9 +220,14 @@ void interp_cubic_v3(float x[3], float v[3], int interp_sparse_array(float *array, const int list_size, const float invalid); -void barycentric_transform(float pt_tar[3], float const pt_src[3], - const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3], - const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3]); +void transform_point_by_tri_v3( + float pt_tar[3], float const pt_src[3], + const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3], + const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3]); +void transform_point_by_seg_v3( + float p_dst[3], const float p_src[3], + const float l_dst_p1[3], const float l_dst_p2[3], + const float l_src_p1[3], const float l_src_p2[3]); void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]); diff --git a/source/blender/blenlib/BLI_math_interp.h b/source/blender/blenlib/BLI_math_interp.h index 43ef64214ad..d2ec7b80d86 100644 --- a/source/blender/blenlib/BLI_math_interp.h +++ b/source/blender/blenlib/BLI_math_interp.h @@ -45,4 +45,24 @@ 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); +#define EWA_MAXIDX 255 +extern const float EWA_WTS[EWA_MAXIDX + 1]; + +typedef void (*ewa_filter_read_pixel_cb) (void *userdata, int x, int y, float result[4]); + +void BLI_ewa_imp2radangle(float A, float B, float C, float F, float *a, float *b, float *th, float *ecc); + +/* TODO(sergey): Consider making this function inlined, so the pixel read callback + * could also be inlined in order to avoid per-pixel function calls. + */ +void BLI_ewa_filter(const int width, const int height, + const bool intpol, + const bool use_alpha, + const float uv[2], + const float du[2], + const float dv[2], + ewa_filter_read_pixel_cb read_pixel_cb, + void *customdata, + float result[4]); + #endif /* __BLI_MATH_INTERP_H__ */ diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 5550a1c9fd9..5868912e762 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -34,14 +34,19 @@ extern "C" { #endif +#include "BLI_compiler_attrs.h" + /********************************* Init **************************************/ +void zero_m2(float R[2][2]); void zero_m3(float R[3][3]); void zero_m4(float R[4][4]); +void unit_m2(float R[2][2]); void unit_m3(float R[3][3]); void unit_m4(float R[4][4]); +void copy_m2_m2(float R[2][2], float A[2][2]); void copy_m3_m3(float R[3][3], float A[3][3]); void copy_m4_m4(float R[4][4], float A[4][4]); void copy_m3_m4(float R[3][3], float A[4][4]); @@ -67,6 +72,7 @@ void mul_m4_m4m3(float R[4][4], float A[4][4], float B[3][3]); void mul_m4_m4m4(float R[4][4], float A[4][4], float B[4][4]); void mul_m3_m3m4(float R[3][3], float A[4][4], float B[3][3]); + void mul_m4_m4m4_q(float m1[4][4], float m3[4][4], float m2[4][4]); void mul_m4_m3m4_q(float m1[4][4], float m3[4][4], float m2[3][3]); @@ -76,6 +82,33 @@ void mul_serie_m3(float R[3][3], void mul_serie_m4(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4], float M5[4][4], float M6[4][4], float M7[4][4], float M8[4][4]); +/* mul_m3_series */ +void _va_mul_m3_series_3(float R[3][3], float M1[3][3], float M2[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_4(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_5(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_6(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3], + float M5[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_7(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3], + float M5[3][3], float M6[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_8(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3], + float M5[3][3], float M6[3][3], float M7[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_9(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3], + float M5[3][3], float M6[3][3], float M7[3][3], float M8[3][3]) ATTR_NONNULL(); +/* mul_m4_series */ +void _va_mul_m4_series_3(float R[4][4], float M1[4][4], float M2[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_4(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_5(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_6(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4], + float M5[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_7(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4], + float M5[4][4], float M6[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_8(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4], + float M5[4][4], float M6[4][4], float M7[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_9(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4], + float M5[4][4], float M6[4][4], float M7[4][4], float M8[4][4]) ATTR_NONNULL(); + +#define mul_m3_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m3_series_, __VA_ARGS__) +#define mul_m4_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m4_series_, __VA_ARGS__) void mul_m4_v3(float M[4][4], float r[3]); void mul_v3_m4v3(float r[3], float M[4][4], const float v[3]); @@ -216,6 +249,23 @@ void mat4_frustum_set(float m[4][4], float left, float right, float bottom, floa void mat4_look_from_origin(float m[4][4], float lookdir[3], float camup[3]); +/* SpaceTransform helper */ +typedef struct SpaceTransform { + float local2target[4][4]; + float target2local[4][4]; + +} SpaceTransform; + +void BLI_space_transform_from_matrices(struct SpaceTransform *data, float local[4][4], float target[4][4]); +void BLI_space_transform_apply(const struct SpaceTransform *data, float co[3]); +void BLI_space_transform_invert(const struct SpaceTransform *data, float co[3]); +void BLI_space_transform_apply_normal(const struct SpaceTransform *data, float no[3]); +void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float no[3]); + +#define BLI_SPACE_TRANSFORM_SETUP(data, local, target) \ + BLI_space_transform_from_matrices((data), (local)->obmat, (target)->obmat) + + /*********************************** Other ***********************************/ void print_m3(const char *str, float M[3][3]); diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index fdad16adb7d..34e65e61981 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -65,6 +65,7 @@ MINLINE void swap_v4_v4(float a[4], float b[4]); MINLINE void copy_v2_v2_char(char r[2], const char a[2]); MINLINE void copy_v3_v3_char(char r[3], const char a[3]); MINLINE void copy_v4_v4_char(char r[4], const char a[4]); + /* short */ MINLINE void copy_v2_v2_short(short r[2], const short a[2]); MINLINE void copy_v3_v3_short(short r[3], const short a[3]); @@ -231,6 +232,7 @@ MINLINE bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_R 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 bool compare_len_squared_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT; 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; diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 244c308a05c..3d82480d050 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -111,6 +111,7 @@ const char *BLI_last_slash(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_R int BLI_add_slash(char *string) ATTR_NONNULL(); void BLI_del_slash(char *string) ATTR_NONNULL(); const char *BLI_first_slash(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; +void BLI_path_native_slash(char *path) ATTR_NONNULL(); void BLI_getlastdir(const char *dir, char *last, const size_t maxlen); bool BLI_testextensie(const char *str, const char *ext) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; @@ -128,9 +129,6 @@ int BLI_stringdec(const char *string, char *head, char *start, unsigned short *n void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic); 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) ATTR_NONNULL(); - /** * dir can be any input, like from buttons, and this function * converts it to a regular full path. diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h index 50ab50e449a..c86b3aea503 100644 --- a/source/blender/blenlib/BLI_rand.h +++ b/source/blender/blenlib/BLI_rand.h @@ -42,33 +42,33 @@ typedef struct RNG RNG; struct RNG *BLI_rng_new(unsigned int seed); struct RNG *BLI_rng_new_srandom(unsigned int seed); -void BLI_rng_free(struct RNG *rng); +void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1); -void BLI_rng_seed(struct RNG *rng, unsigned int seed); -void BLI_rng_srandom(struct RNG *rng, unsigned int seed); -int BLI_rng_get_int(struct RNG *rng); -unsigned int BLI_rng_get_uint(struct RNG *rng); -double BLI_rng_get_double(struct RNG *rng); -float BLI_rng_get_float(struct RNG *rng); -void BLI_rng_get_float_unit_v2(struct RNG *rng, float v[2]); -void BLI_rng_get_float_unit_v3(struct RNG *rng, float v[3]); -void BLI_rng_shuffle_array(struct RNG *rng, void *data, unsigned int elem_size_i, unsigned int elem_tot); +void BLI_rng_seed(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1); +void BLI_rng_srandom(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1); +int BLI_rng_get_int(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +unsigned int BLI_rng_get_uint(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +double BLI_rng_get_double(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +void BLI_rng_get_float_unit_v2(struct RNG *rng, float v[2]) ATTR_NONNULL(1, 2); +void BLI_rng_get_float_unit_v3(struct RNG *rng, float v[3]) ATTR_NONNULL(1, 2); +void BLI_rng_shuffle_array(struct RNG *rng, void *data, unsigned int elem_size_i, unsigned int elem_tot) ATTR_NONNULL(1, 2); /** Note that skipping is as slow as generating n numbers! */ -void BLI_rng_skip(struct RNG *rng, int n); +void BLI_rng_skip(struct RNG *rng, int n) ATTR_NONNULL(1); /** Seed for the random number generator, using noise.c hash[] */ void BLI_srandom(unsigned int seed); /** Return a pseudo-random number N where 0<=N<(2^31) */ -int BLI_rand(void); +int BLI_rand(void) ATTR_WARN_UNUSED_RESULT; /** Return a pseudo-random number N where 0.0f<=N<1.0f */ -float BLI_frand(void); +float BLI_frand(void) ATTR_WARN_UNUSED_RESULT; void BLI_frand_unit_v3(float v[3]); /** Return a pseudo-random (hash) float from an integer value */ -float BLI_hash_frand(unsigned int seed); +float BLI_hash_frand(unsigned int seed) ATTR_WARN_UNUSED_RESULT; /** Shuffle an array randomly using the given seed. * contents. This routine does not use nor modify @@ -83,10 +83,10 @@ void BLI_thread_srandom(int thread, unsigned int seed); /** Return a pseudo-random number N where 0<=N<(2^31) */ /** Allows up to BLENDER_MAX_THREADS threads to address */ -int BLI_thread_rand(int thread); +int BLI_thread_rand(int thread) ATTR_WARN_UNUSED_RESULT; /** Return a pseudo-random number N where 0.0f<=N<1.0f */ /** Allows up to BLENDER_MAX_THREADS threads to address */ -float BLI_thread_frand(int thread); +float BLI_thread_frand(int thread) ATTR_WARN_UNUSED_RESULT; #endif /* __BLI_RAND_H__ */ diff --git a/source/blender/blenlib/BLI_smallhash.h b/source/blender/blenlib/BLI_smallhash.h index b2fec6f870c..b80044bccff 100644 --- a/source/blender/blenlib/BLI_smallhash.h +++ b/source/blender/blenlib/BLI_smallhash.h @@ -70,4 +70,8 @@ void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key) ATTR_NONNUL void *BLI_smallhash_iternew(SmallHash *sh, SmallHashIter *iter, uintptr_t *key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; /* void BLI_smallhash_print(SmallHash *sh); */ /* UNUSED */ +#ifdef DEBUG +double BLI_smallhash_calc_quality(SmallHash *sh); +#endif + #endif /* __BLI_SMALLHASH_H__ */ diff --git a/source/blender/blenlib/BLI_stack.h b/source/blender/blenlib/BLI_stack.h index d65c8f02462..1e0b29bc7e8 100644 --- a/source/blender/blenlib/BLI_stack.h +++ b/source/blender/blenlib/BLI_stack.h @@ -34,16 +34,20 @@ typedef struct BLI_Stack BLI_Stack; BLI_Stack *BLI_stack_new_ex( const size_t elem_size, const char *description, - const size_t chunk_size) ATTR_NONNULL(); + const size_t chunk_size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BLI_Stack *BLI_stack_new( - const size_t elem_size, const char *description) ATTR_NONNULL(); + const size_t elem_size, const char *description) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL(); -void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL(); +void *BLI_stack_push_r(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL(); +void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL(); void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL(); -bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_NONNULL(); +size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -#endif +bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); + +#endif /* __BLI_STACK_H__ */ diff --git a/source/blender/blenlib/BLI_stackdefines.h b/source/blender/blenlib/BLI_stackdefines.h index 24cb043cd43..da9bf5ea04c 100644 --- a/source/blender/blenlib/BLI_stackdefines.h +++ b/source/blender/blenlib/BLI_stackdefines.h @@ -36,7 +36,7 @@ # define _STACK_SWAP_TOTALLOC(stack_a, stack_b) SWAP(unsigned int, _##stack_a##_totalloc, _##stack_b##_totalloc) #else # define STACK_DECLARE(stack) unsigned int _##stack##_index -# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)(tot)) +# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)(0 ? tot : 0)) # define _STACK_SIZETEST(stack, off) (void)(stack), (void)(off) # define _STACK_SWAP_TOTALLOC(stack_a, stack_b) (void)(stack_a), (void)(stack_b) #endif @@ -57,9 +57,12 @@ #define STACK_PEEK_PTR(stack) (BLI_assert(_##stack##_index), &((stack)[_##stack##_index - 1])) /** remove any item from the stack, take care, re-orders */ #define STACK_REMOVE(stack, i) \ - _STACK_BOUNDSTEST(stack, i); \ - if (--_##stack##_index != i) { \ - stack[i] = stack[_##stack##_index]; \ + { \ + const unsigned int _i = i; \ + _STACK_BOUNDSTEST(stack, _i); \ + if (--_##stack##_index != _i) { \ + stack[_i] = stack[_##stack##_index]; \ + } \ } (void)0 #ifdef __GNUC__ #define STACK_SWAP(stack_a, stack_b) { \ diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index 786e5e9d9d8..b249bc720c6 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -64,6 +64,8 @@ char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT A size_t BLI_strescape(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL(); +size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL(); + 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(); diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h index fcbed1daf66..c9cf33f2f69 100644 --- a/source/blender/blenlib/BLI_sys_types.h +++ b/source/blender/blenlib/BLI_sys_types.h @@ -47,127 +47,7 @@ extern "C" { #endif -/* MSVC 2010 and 2012 (>=1600) have stdint.h so we should use this for consistency */ -#if defined(_WIN32) && defined(_MSC_VER) && _MSC_VER <= 1500 - -/* The __intXX are built-in types of the visual compiler! So we don't - * need to include anything else here. */ - - -typedef signed __int8 int8_t; -typedef signed __int16 int16_t; -typedef signed __int32 int32_t; -typedef signed __int64 int64_t; - -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; - -// 7.18.2 Limits of specified-width integer types - -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 - -// 7.18.2.1 Limits of exact-width integer types -#define INT8_MIN ((int8_t)_I8_MIN) -#define INT8_MAX _I8_MAX -#define INT16_MIN ((int16_t)_I16_MIN) -#define INT16_MAX _I16_MAX -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX _I32_MAX -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX _I64_MAX -#define UINT8_MAX _UI8_MAX -#define UINT16_MAX _UI16_MAX -#define UINT32_MAX _UI32_MAX -#define UINT64_MAX _UI64_MAX - -// 7.18.2.2 Limits of minimum-width integer types -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MIN INT64_MIN -#define INT_LEAST64_MAX INT64_MAX -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -// 7.18.2.3 Limits of fastest minimum-width integer types -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MIN INT64_MIN -#define INT_FAST64_MAX INT64_MAX -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -// 7.18.2.4 Limits of integer types capable of holding object pointers -#ifdef _WIN64 // [ -# define INTPTR_MIN INT64_MIN -# define INTPTR_MAX INT64_MAX -# define UINTPTR_MAX UINT64_MAX -#else // _WIN64 ][ -# define INTPTR_MIN INT32_MIN -# define INTPTR_MAX INT32_MAX -# define UINTPTR_MAX UINT32_MAX -#endif // _WIN64 ] - -// 7.18.2.5 Limits of greatest-width integer types -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -// 7.18.3 Limits of other integer types - -#ifdef _WIN64 // [ -# define PTRDIFF_MIN _I64_MIN -# define PTRDIFF_MAX _I64_MAX -#else // _WIN64 ][ -# define PTRDIFF_MIN _I32_MIN -# define PTRDIFF_MAX _I32_MAX -#endif // _WIN64 ] - -#define SIG_ATOMIC_MIN INT_MIN -#define SIG_ATOMIC_MAX INT_MAX - -#ifndef SIZE_MAX // [ -# ifdef _WIN64 // [ -# define SIZE_MAX _UI64_MAX -# else // _WIN64 ][ -# define SIZE_MAX _UI32_MAX -# endif // _WIN64 ] -#endif // SIZE_MAX ] - -#endif // __STDC_LIMIT_MACROS ] - -#ifndef _INTPTR_T_DEFINED -#ifdef _WIN64 -typedef __int64 intptr_t; -#else -typedef long intptr_t; -#endif -#define _INTPTR_T_DEFINED -#endif - -#ifndef _UINTPTR_T_DEFINED -#ifdef _WIN64 -typedef unsigned __int64 uintptr_t; -#else -typedef unsigned long uintptr_t; -#endif -#define _UINTPTR_T_DEFINED -#endif - -#elif defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__) +#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__) /* Linux-i386, Linux-Alpha, Linux-ppc */ #include <stdint.h> @@ -186,7 +66,7 @@ typedef uint64_t u_int64_t; #include <inttypes.h> /* MinGW and MSVC >= 2010 */ -#elif defined(FREE_WINDOWS) || (defined(_MSC_VER) && _MSC_VER >= 1600) +#elif defined(FREE_WINDOWS) || defined(_MSC_VER) #include <stdint.h> #else diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index 56931a45495..63a6b2a1943 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -40,6 +40,25 @@ #include <stdio.h> #endif + +/* varargs macros (keep first so others can use) */ +/* --- internal helpers --- */ +#define _VA_NARGS_GLUE(x, y) x y +#define _VA_NARGS_RETURN_COUNT(\ + _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, \ + _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, \ + count, ...) count +#define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args +#define _VA_NARGS_COUNT_MAX32(...) _VA_NARGS_EXPAND((__VA_ARGS__, \ + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, \ + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) +#define _VA_NARGS_OVERLOAD_MACRO2(name, count) name##count +#define _VA_NARGS_OVERLOAD_MACRO1(name, count) _VA_NARGS_OVERLOAD_MACRO2(name, count) +#define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count) +/* --- expose for re-use --- */ +#define VA_NARGS_CALL_OVERLOAD(name, ...) \ + _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, _VA_NARGS_COUNT_MAX32(__VA_ARGS__)), (__VA_ARGS__)) + /* useful for finding bad use of min/max */ #if 0 /* gcc only */ @@ -137,20 +156,20 @@ * ... the compiler optimizes away the temp var */ #ifdef __GNUC__ #define CHECK_TYPE(var, type) { \ - __typeof(var) *__tmp; \ + typeof(var) *__tmp; \ __tmp = (type *)NULL; \ (void)__tmp; \ } (void)0 #define CHECK_TYPE_PAIR(var_a, var_b) { \ - __typeof(var_a) *__tmp; \ - __tmp = (__typeof(var_b) *)NULL; \ + typeof(var_a) *__tmp; \ + __tmp = (typeof(var_b) *)NULL; \ (void)__tmp; \ } (void)0 #define CHECK_TYPE_PAIR_INLINE(var_a, var_b) ((void)({ \ - __typeof(var_a) *__tmp; \ - __tmp = (__typeof(var_b) *)NULL; \ + typeof(var_a) *__tmp; \ + __tmp = (typeof(var_b) *)NULL; \ (void)__tmp; \ })) @@ -161,8 +180,19 @@ #endif /* can be used in simple macros */ -#define CHECK_TYPE_INLINE(val, type) \ - ((void)(((type)0) != (val))) +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +# define CHECK_TYPE_INLINE(val, type) \ + (void)((void)(((type)0) != (0 ? (val) : ((type)0))), \ + _Generic((val), type: 0, const type: 0)) +#else +# define CHECK_TYPE_INLINE(val, type) \ + ((void)(((type)0) != (0 ? (val) : ((type)0)))) +#endif + +#define CHECK_TYPE_NONCONST(var) { \ + void *non_const = 0 ? (var) : NULL; \ + (void)non_const; \ +} (void)0 #define SWAP(type, a, b) { \ type sw_ap; \ @@ -182,17 +212,42 @@ (b) = (tval); \ } (void)0 -/* ELEM#(a, ...): is the first arg equal any of the others */ -#define ELEM(a, b, c) ((a) == (b) || (a) == (c)) -#define ELEM3(a, b, c, d) (ELEM(a, b, c) || (a) == (d) ) -#define ELEM4(a, b, c, d, e) (ELEM(a, b, c) || ELEM(a, d, e) ) -#define ELEM5(a, b, c, d, e, f) (ELEM(a, b, c) || ELEM3(a, d, e, f) ) -#define ELEM6(a, b, c, d, e, f, g) (ELEM(a, b, c) || ELEM4(a, d, e, f, g) ) -#define ELEM7(a, b, c, d, e, f, g, h) (ELEM3(a, b, c, d) || ELEM4(a, e, f, g, h) ) -#define ELEM8(a, b, c, d, e, f, g, h, i) (ELEM4(a, b, c, d, e) || ELEM4(a, f, g, h, i) ) -#define ELEM9(a, b, c, d, e, f, g, h, i, j) (ELEM4(a, b, c, d, e) || ELEM5(a, f, g, h, i, j) ) -#define ELEM10(a, b, c, d, e, f, g, h, i, j, k) (ELEM4(a, b, c, d, e) || ELEM6(a, f, g, h, i, j, k) ) -#define ELEM11(a, b, c, d, e, f, g, h, i, j, k, l) (ELEM4(a, b, c, d, e) || ELEM7(a, f, g, h, i, j, k, l) ) +/* ELEM#(v, ...): is the first arg equal any others? */ +/* internal helpers*/ +#define _VA_ELEM3(v, a, b) \ + (((v) == (a)) || ((v) == (b))) +#define _VA_ELEM4(v, a, b, c) \ + (_VA_ELEM3(v, a, b) || ((v) == (c))) +#define _VA_ELEM5(v, a, b, c, d) \ + (_VA_ELEM4(v, a, b, c) || ((v) == (d))) +#define _VA_ELEM6(v, a, b, c, d, e) \ + (_VA_ELEM5(v, a, b, c, d) || ((v) == (e))) +#define _VA_ELEM7(v, a, b, c, d, e, f) \ + (_VA_ELEM6(v, a, b, c, d, e) || ((v) == (f))) +#define _VA_ELEM8(v, a, b, c, d, e, f, g) \ + (_VA_ELEM7(v, a, b, c, d, e, f) || ((v) == (g))) +#define _VA_ELEM9(v, a, b, c, d, e, f, g, h) \ + (_VA_ELEM8(v, a, b, c, d, e, f, g) || ((v) == (h))) +#define _VA_ELEM10(v, a, b, c, d, e, f, g, h, i) \ + (_VA_ELEM9(v, a, b, c, d, e, f, g, h) || ((v) == (i))) +#define _VA_ELEM11(v, a, b, c, d, e, f, g, h, i, j) \ + (_VA_ELEM10(v, a, b, c, d, e, f, g, h, i) || ((v) == (j))) +#define _VA_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) \ + (_VA_ELEM11(v, a, b, c, d, e, f, g, h, i, j) || ((v) == (k))) +#define _VA_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) \ + (_VA_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) || ((v) == (l))) +#define _VA_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) \ + (_VA_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) || ((v) == (m))) +#define _VA_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) \ + (_VA_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) || ((v) == (n))) +#define _VA_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) \ + (_VA_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) || ((v) == (o))) +#define _VA_ELEM17(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \ + (_VA_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) || ((v) == (p))) + +/* reusable ELEM macro */ +#define ELEM(...) VA_NARGS_CALL_OVERLOAD(_VA_ELEM, __VA_ARGS__) + /* shift around elements */ #define SHIFT3(type, a, b, c) { \ @@ -346,13 +401,13 @@ #define IN_RANGE_INCL(a, b, c) ((b < c) ? ((b <= a && a <= c) ? 1 : 0) : ((c <= a && a <= b) ? 1 : 0)) /* unpack vector for args */ -#define UNPACK2(a) ((a)[0]), ((a)[1]) -#define UNPACK3(a) ((a)[0]), ((a)[1]), ((a)[2]) -#define UNPACK4(a) ((a)[0]), ((a)[1]), ((a)[2]), ((a)[3]) -/* op may be '&' or '*' */ -#define UNPACK2OP(op, a) op((a)[0]), op((a)[1]) -#define UNPACK3OP(op, a) op((a)[0]), op((a)[1]), op((a)[2]) -#define UNPACK4OP(op, a) op((a)[0]), op((a)[1]), op((a)[2]), op((a)[3]) +#define UNPACK2(a) ((a)[0]), ((a)[1]) +#define UNPACK3(a) UNPACK2(a), ((a)[2]) +#define UNPACK4(a) UNPACK3(a), ((a)[3]) +/* pre may be '&', '*' or func, post may be '->member' */ +#define UNPACK2_EX(pre, a, post) (pre((a)[0])post), (pre((a)[1])post) +#define UNPACK3_EX(pre, a, post) UNPACK2_EX(pre, a, post), (pre((a)[2])post) +#define UNPACK4_EX(pre, a, post) UNPACK3_EX(pre, a, post), (pre((a)[3])post) /* array helpers */ #define ARRAY_LAST_ITEM(arr_start, arr_dtype, tot) \ @@ -385,8 +440,7 @@ /* memcpy, skipping the first part of a struct, * ensures 'struct_dst' isn't const and that the offset can be computed at compile time */ #define MEMCPY_STRUCT_OFS(struct_dst, struct_src, member) { \ - void *_not_const = struct_dst; \ - (void)_not_const; \ + CHECK_TYPE_NONCONST(struct_dst); \ ((void)(struct_dst == struct_src), \ memcpy((char *)(struct_dst) + OFFSETOF_STRUCT(struct_dst, member), \ (char *)(struct_src) + OFFSETOF_STRUCT(struct_dst, member), \ diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 0c1c5f1d774..dd02bcf22a9 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -42,6 +42,7 @@ set(INC_SYS set(SRC intern/BLI_args.c intern/BLI_array.c + intern/BLI_dial.c intern/BLI_dynstr.c intern/BLI_ghash.c intern/BLI_heap.c @@ -118,6 +119,7 @@ set(SRC BLI_compiler_attrs.h BLI_compiler_compat.h BLI_convexhull2d.h + BLI_dial.h BLI_dlrbTree.h BLI_dynlib.h BLI_dynstr.h diff --git a/source/blender/blenlib/intern/BLI_array.c b/source/blender/blenlib/intern/BLI_array.c index 21d7a5a6d10..da2eef8ab6a 100644 --- a/source/blender/blenlib/intern/BLI_array.c +++ b/source/blender/blenlib/intern/BLI_array.c @@ -137,3 +137,18 @@ void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int d BLI_assert(0); } } + +/** + * \note Not efficient, use for error checks/asserts. + */ +int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p) +{ + const char *arr_step = (const char *)arr; + unsigned int i; + for (i = 0; i < arr_len; i++, arr_step += arr_stride) { + if (memcmp(arr_step, p, arr_stride) == 0) { + return (int)i; + } + } + return -1; +} diff --git a/source/blender/blenlib/intern/BLI_dial.c b/source/blender/blenlib/intern/BLI_dial.c new file mode 100644 index 00000000000..cfbb52847fd --- /dev/null +++ b/source/blender/blenlib/intern/BLI_dial.c @@ -0,0 +1,100 @@ +/* + * ***** 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 "BLI_dial.h" +#include "BLI_math.h" + +#include "MEM_guardedalloc.h" + +struct Dial { + /* center of the dial */ + float center[2]; + + /* threshold of the dial. Distance of current position has to be greater + * than the threshold to be used in any calculations */ + float threshold_squared; + + /* the direction of the first dial position exceeding the threshold. This + * is later used as the basis against which rotation angle is calculated */ + float initial_direction[2]; + + /* cache the last angle to detect rotations bigger than -/+ PI */ + float last_angle; + + /* number of full rotations */ + int rotations; + + /* has initial_direction been initialized */ + bool initialized; +}; + + +Dial *BLI_dial_initialize(float start_position[2], float threshold) +{ + Dial *dial = MEM_callocN(sizeof(Dial), "dial"); + + copy_v2_v2(dial->center, start_position); + dial->threshold_squared = threshold * threshold; + + return dial; +} + +float BLI_dial_angle(Dial *dial, float current_position[2]) +{ + float current_direction[2]; + + sub_v2_v2v2(current_direction, current_position, dial->center); + + /* only update when we have enough precision, by having the mouse adequately away from center */ + if (len_squared_v2(current_direction) > dial->threshold_squared) { + float angle; + float cosval, sinval; + + normalize_v2(current_direction); + + if (!dial->initialized) { + copy_v2_v2(dial->initial_direction, current_direction); + dial->initialized = true; + } + + /* calculate mouse angle between initial and final mouse position */ + cosval = dot_v2v2(current_direction, dial->initial_direction); + sinval = cross_v2v2(current_direction, dial->initial_direction); + + /* clamp to avoid nans in acos */ + angle = atan2f(sinval, cosval); + + /* change of sign, we passed the 180 degree threshold. This means we need to add a turn. + * to distinguish between transition from 0 to -1 and -PI to +PI, use comparison with PI/2 */ + if ((angle * dial->last_angle < 0.0f) && + (fabsf(dial->last_angle) > (float)M_PI_2)) + { + if (dial->last_angle < 0.0f) + dial->rotations--; + else + dial->rotations++; + } + dial->last_angle = angle; + + return angle + 2.0f * (float)M_PI * dial->rotations; + } + + return dial->last_angle; +} diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index b30553d0b5e..74d7fdc88cb 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -399,7 +399,7 @@ void *BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default) * \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. + * \note This has 2 main benefits 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). */ @@ -570,12 +570,12 @@ void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh) ghi->curEntry = NULL; ghi->curBucket = UINT_MAX; /* wraps to zero */ if (gh->nentries) { - while (!ghi->curEntry) { + do { ghi->curBucket++; if (UNLIKELY(ghi->curBucket == ghi->gh->nbuckets)) break; ghi->curEntry = ghi->gh->buckets[ghi->curBucket]; - } + } while (!ghi->curEntry); } } @@ -704,6 +704,11 @@ unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4]) return hash; } +int BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b) +{ + return memcmp(a, b, sizeof(unsigned int[4])); +} + unsigned int BLI_ghashutil_uinthash(unsigned int key) { key += ~(key << 16); @@ -967,6 +972,17 @@ void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp) { BLI_ghash_free((GHash *)gs, keyfreefp, NULL); } + +void BLI_gset_flag_set(GSet *gs, unsigned int flag) +{ + ((GHash *)gs)->flag |= flag; +} + +void BLI_gset_flag_clear(GSet *gs, unsigned int flag) +{ + ((GHash *)gs)->flag &= ~flag; +} + /** \} */ @@ -996,3 +1012,41 @@ GSet *BLI_gset_pair_new(const char *info) } /** \} */ + + +/** \name Debugging & Introspection + * \{ */ +#ifdef DEBUG + +/** + * Measure how well the hash function performs + * (1.0 is approx as good as random distribution). + * + * Smaller is better! + */ +double BLI_ghash_calc_quality(GHash *gh) +{ + uint64_t sum = 0; + unsigned int i; + + if (gh->nentries == 0) + return -1.0; + + for (i = 0; i < gh->nbuckets; i++) { + uint64_t count = 0; + Entry *e; + for (e = gh->buckets[i]; e; e = e->next) { + count += 1; + } + sum += count * (count + 1); + } + return ((double)sum * (double)gh->nbuckets / + ((double)gh->nentries * (gh->nentries + 2 * gh->nbuckets - 1))); +} +double BLI_gset_calc_quality(GSet *gs) +{ + return BLI_ghash_calc_quality((GHash *)gs); +} + +#endif +/** \} */ diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 6b1fbe855a1..dbacb0f3451 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -34,6 +34,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" +#include "BLI_stack.h" #include "BLI_kdopbvh.h" #include "BLI_math.h" #include "BLI_strict_flags.h" @@ -42,14 +43,30 @@ #include <omp.h> #endif +/* used for iterative_raycast */ +// #define USE_SKIP_LINKS + #define MAX_TREETYPE 32 +/* Setting zero so we can catch bugs in OpenMP/KDOPBVH. + * TODO(sergey): Deduplicate the limits with PBVH from BKE. + */ +#ifdef _OPENMP +# ifdef DEBUG +# define KDOPBVH_OMP_LIMIT 0 +# else +# define KDOPBVH_OMP_LIMIT 1024 +# endif +#endif + typedef unsigned char axis_t; typedef struct BVHNode { struct BVHNode **children; struct BVHNode *parent; /* some user defined traversed need that */ +#ifdef USE_SKIP_LINKS struct BVHNode *skip[2]; +#endif float *bv; /* Bounding volume of all nodes, max 13 axis */ int index; /* face, edge, vertex index */ char totnode; /* how many nodes are used, used for speedup */ @@ -77,9 +94,7 @@ BLI_STATIC_ASSERT((sizeof(void *) == 8 && sizeof(BVHTree) <= 48) || typedef struct BVHOverlapData { BVHTree *tree1, *tree2; - BVHTreeOverlap *overlap; - unsigned int i; - unsigned int max_overlap; /* i is number of overlaps */ + struct BLI_Stack *overlap; /* store BVHTreeOverlap */ axis_t start_axis, stop_axis; } BVHOverlapData; @@ -375,7 +390,7 @@ static int partition_nth_element(BVHNode **a, int _begin, int _end, int n, int a return n; } -/* --- */ +#ifdef USE_SKIP_LINKS static void build_skip_links(BVHTree *tree, BVHNode *node, BVHNode *left, BVHNode *right) { int i; @@ -392,6 +407,7 @@ static void build_skip_links(BVHTree *tree, BVHNode *node, BVHNode *left, BVHNod left = node->children[i]; } } +#endif /* * BVHTree bounding volumes functions @@ -670,7 +686,7 @@ static int implicit_leafs_index(BVHBuildHelper *data, int depth, int child_index /* This functions returns the number of branches needed to have the requested number of leafs. */ static int implicit_needed_branches(int tree_type, int leafs) { - return max_ii(1, (leafs + tree_type - 3) / (tree_type - 1) ); + return max_ii(1, (leafs + tree_type - 3) / (tree_type - 1)); } /** @@ -750,7 +766,8 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array, int j; /* Loop all branches on this level */ -#pragma omp parallel for private(j) schedule(static) + +#pragma omp parallel for private(j) schedule(static) if (num_leafs > KDOPBVH_OMP_LIMIT) for (j = i; j < end_j; j++) { int k; const int parent_level_index = j - i; @@ -931,7 +948,10 @@ void BLI_bvhtree_balance(BVHTree *tree) for (i = 0; i < tree->totbranch; i++) tree->nodes[tree->totleaf + i] = branches_array + i; +#ifdef USE_SKIP_LINKS build_skip_links(tree, tree->nodes[tree->totleaf], NULL, NULL); +#endif + /* bvhtree_info(tree); */ } @@ -1038,27 +1058,16 @@ static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2) if (!node1->totnode) { /* check if node2 is a leaf */ if (!node2->totnode) { + BVHTreeOverlap *overlap; - if (node1 == node2) { + if (UNLIKELY(node1 == node2)) { return; } - if (data->i >= data->max_overlap) { - /* try to make alloc'ed memory bigger */ - data->overlap = realloc(data->overlap, sizeof(BVHTreeOverlap) * (size_t)data->max_overlap * 2); - - if (!data->overlap) { - printf("Out of Memory in traverse\n"); - return; - } - data->max_overlap *= 2; - } - /* both leafs, insert overlap! */ - data->overlap[data->i].indexA = node1->index; - data->overlap[data->i].indexB = node2->index; - - data->i++; + overlap = BLI_stack_push_r(data->overlap); + overlap->indexA = node1->index; + overlap->indexB = node2->index; } else { for (j = 0; j < data->tree2->tree_type; j++) { @@ -1077,16 +1086,21 @@ static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2) return; } -BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, unsigned int *result) +BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, unsigned int *r_overlap_tot) { int j; - unsigned int total = 0; + size_t total = 0; BVHTreeOverlap *overlap = NULL, *to = NULL; BVHOverlapData **data; /* check for compatibility of both trees (can't compare 14-DOP with 18-DOP) */ - if ((tree1->axis != tree2->axis) && (tree1->axis == 14 || tree2->axis == 14) && (tree1->axis == 18 || tree2->axis == 18)) + if (UNLIKELY((tree1->axis != tree2->axis) && + (tree1->axis == 14 || tree2->axis == 14) && + (tree1->axis == 18 || tree2->axis == 18))) + { + BLI_assert(0); return NULL; + } /* fast check root nodes for collision before doing big splitting + traversal */ if (!tree_overlap(tree1->nodes[tree1->totleaf], tree2->nodes[tree2->totleaf], @@ -1096,43 +1110,42 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, unsigned int return NULL; } - data = MEM_callocN(sizeof(BVHOverlapData *) * tree1->tree_type, "BVHOverlapData_star"); + data = MEM_mallocN(sizeof(BVHOverlapData *) * tree1->tree_type, "BVHOverlapData_star"); for (j = 0; j < tree1->tree_type; j++) { - data[j] = MEM_callocN(sizeof(BVHOverlapData), "BVHOverlapData"); + data[j] = MEM_mallocN(sizeof(BVHOverlapData), "BVHOverlapData"); /* init BVHOverlapData */ - data[j]->overlap = malloc(sizeof(BVHTreeOverlap) * (size_t)max_ii(tree1->totleaf, tree2->totleaf)); + data[j]->overlap = BLI_stack_new(sizeof(BVHTreeOverlap), __func__); data[j]->tree1 = tree1; data[j]->tree2 = tree2; - 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); } -#pragma omp parallel for private(j) schedule(static) +#pragma omp parallel for private(j) schedule(static) if (tree1->totleaf > KDOPBVH_OMP_LIMIT) for (j = 0; j < MIN2(tree1->tree_type, tree1->nodes[tree1->totleaf]->totnode); j++) { traverse(data[j], tree1->nodes[tree1->totleaf]->children[j], tree2->nodes[tree2->totleaf]); } for (j = 0; j < tree1->tree_type; j++) - total += data[j]->i; + total += BLI_stack_count(data[j]->overlap); - to = overlap = MEM_callocN(sizeof(BVHTreeOverlap) * total, "BVHTreeOverlap"); + to = overlap = MEM_mallocN(sizeof(BVHTreeOverlap) * total, "BVHTreeOverlap"); for (j = 0; j < tree1->tree_type; j++) { - memcpy(to, data[j]->overlap, data[j]->i * sizeof(BVHTreeOverlap)); - to += data[j]->i; + unsigned int count = (unsigned int)BLI_stack_count(data[j]->overlap); + BLI_stack_pop_n(data[j]->overlap, to, count); + BLI_stack_free(data[j]->overlap); + to += count; } for (j = 0; j < tree1->tree_type; j++) { - free(data[j]->overlap); MEM_freeN(data[j]); } MEM_freeN(data); - (*result) = total; + *r_overlap_tot = (unsigned int)total; return overlap; } @@ -1172,13 +1185,6 @@ static float calc_nearest_point_squared(const float proj[3], BVHNode *node, floa return len_squared_v3v3(proj, nearest); } - -typedef struct NodeDistance { - BVHNode *node; - float dist; - -} NodeDistance; - /* TODO: use a priority queue to reduce the number of nodes looked on */ static void dfs_find_nearest_dfs(BVHNearestData *data, BVHNode *node) { @@ -1226,6 +1232,12 @@ static void dfs_find_nearest_begin(BVHNearestData *data, BVHNode *node) #if 0 +typedef struct NodeDistance { + BVHNode *node; + float dist; + +} NodeDistance; + #define DEFAULT_FIND_NEAREST_HEAP_SIZE 1024 #define NodeDistance_priority(a, b) ((a).dist < (b).dist) diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c index 66fcfd21fbb..a0b61e7945c 100644 --- a/source/blender/blenlib/intern/BLI_linklist.c +++ b/source/blender/blenlib/intern/BLI_linklist.c @@ -38,17 +38,12 @@ int BLI_linklist_length(LinkNode *list) { - if (0) { - return list ? (1 + BLI_linklist_length(list->next)) : 0; - } - else { - int len; + int len; - for (len = 0; list; list = list->next) - len++; - - return len; - } + for (len = 0; list; list = list->next) + len++; + + return len; } int BLI_linklist_index(LinkNode *list, void *ptr) diff --git a/source/blender/blenlib/intern/callbacks.c b/source/blender/blenlib/intern/callbacks.c index 719809e6bcd..191be49263c 100644 --- a/source/blender/blenlib/intern/callbacks.c +++ b/source/blender/blenlib/intern/callbacks.c @@ -37,7 +37,7 @@ void BLI_callback_exec(struct Main *main, struct ID *self, eCbEvent evt) ListBase *lb = &callback_slots[evt]; bCallbackFuncStore *funcstore; - for (funcstore = (bCallbackFuncStore *)lb->first; funcstore; funcstore = (bCallbackFuncStore *)funcstore->next) { + for (funcstore = lb->first; funcstore; funcstore = funcstore->next) { funcstore->func(main, self, funcstore->arg); } } @@ -61,8 +61,8 @@ void BLI_callback_global_finalize(void) ListBase *lb = &callback_slots[evt]; bCallbackFuncStore *funcstore; bCallbackFuncStore *funcstore_next; - for (funcstore = (bCallbackFuncStore *)lb->first; funcstore; funcstore = funcstore_next) { - funcstore_next = (bCallbackFuncStore *)funcstore->next; + for (funcstore = lb->first; funcstore; funcstore = funcstore_next) { + funcstore_next = funcstore->next; BLI_remlink(lb, funcstore); if (funcstore->alloc) { MEM_freeN(funcstore); diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c index 173d2a5a590..4ed82f8a473 100644 --- a/source/blender/blenlib/intern/edgehash.c +++ b/source/blender/blenlib/intern/edgehash.c @@ -93,7 +93,7 @@ BLI_INLINE unsigned int edgehash_keyhash(EdgeHash *eh, unsigned int v0, unsigned { BLI_assert(v0 < v1); - return ((v0 * 39) ^ (v1 * 31)) % eh->nbuckets; + return ((v0 * 65) ^ (v1 * 31)) % eh->nbuckets; } /** @@ -270,7 +270,7 @@ static void edgehash_free_cb(EdgeHash *eh, EdgeHashFreeFP valfreefp) for (e = eh->buckets[i]; e; ) { EdgeEntry *e_next = e->next; - if (valfreefp) valfreefp(e->val); + valfreefp(e->val); e = e_next; } @@ -463,14 +463,14 @@ void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh) ehi->curEntry = NULL; ehi->curBucket = UINT_MAX; /* wraps to zero */ if (eh->nentries) { - while (!ehi->curEntry) { + do { ehi->curBucket++; if (UNLIKELY(ehi->curBucket == ehi->eh->nbuckets)) { break; } ehi->curEntry = ehi->eh->buckets[ehi->curBucket]; - } + } while (!ehi->curEntry); } } @@ -622,4 +622,49 @@ void BLI_edgeset_free(EdgeSet *es) BLI_edgehash_free((EdgeHash *)es, NULL); } +void BLI_edgeset_flag_set(EdgeSet *es, unsigned int flag) +{ + ((EdgeHash *)es)->flag |= flag; +} + +void BLI_edgeset_flag_clear(EdgeSet *es, unsigned int flag) +{ + ((EdgeHash *)es)->flag &= ~flag; +} + +/** \} */ + +/** \name Debugging & Introspection + * \{ */ +#ifdef DEBUG + +/** + * Measure how well the hash function performs + * (1.0 is approx as good as random distribution). + */ +double BLI_edgehash_calc_quality(EdgeHash *eh) +{ + uint64_t sum = 0; + unsigned int i; + + if (eh->nentries == 0) + return -1.0; + + for (i = 0; i < eh->nbuckets; i++) { + uint64_t count = 0; + EdgeEntry *e; + for (e = eh->buckets[i]; e; e = e->next) { + count += 1; + } + sum += count * (count + 1); + } + return ((double)sum * (double)eh->nbuckets / + ((double)eh->nentries * (eh->nentries + 2 * eh->nbuckets - 1))); +} +double BLI_edgeset_calc_quality(EdgeSet *es) +{ + return BLI_edgehash_calc_quality((EdgeHash *)es); +} + +#endif /** \} */ diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c index 0893c3e380f..f6bbd3273f9 100644 --- a/source/blender/blenlib/intern/fileops.c +++ b/source/blender/blenlib/intern/fileops.c @@ -66,7 +66,7 @@ #include "BLI_fileops.h" #include "BLI_sys_types.h" // for intptr_t support - +#if 0 /* UNUSED */ /* gzip the file in from and write it to "to". * return -1 if zlib fails, -2 if the originating file does not exist * note: will remove the "from" file @@ -111,6 +111,7 @@ int BLI_file_gzip(const char *from, const char *to) return rval; } +#endif /* gzip the file in from_file and write it to memory to_mem, at most size bytes. * return the unziped size diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c index 67703c3f033..94d18ce3c77 100644 --- a/source/blender/blenlib/intern/gsqueue.c +++ b/source/blender/blenlib/intern/gsqueue.c @@ -27,6 +27,12 @@ /** \file blender/blenlib/intern/gsqueue.c * \ingroup bli + * + * \brief A generic structure queue + * (a queue for fixed length generally small) structures. + * + * \note Only use this if you need (first-in-first-out), + * otherwise #BLI_stack is more efficient (first-in-last-out). */ #include <string.h> diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c index b0c24899bd1..abf15d57cf7 100644 --- a/source/blender/blenlib/intern/listbase.c +++ b/source/blender/blenlib/intern/listbase.c @@ -354,7 +354,7 @@ int BLI_countlist(const ListBase *listbase) } /** - * Returns the nth element of \a listbase, numbering from 1. + * Returns the nth element of \a listbase, numbering from 0. */ void *BLI_findlink(const ListBase *listbase, int number) { @@ -372,7 +372,7 @@ void *BLI_findlink(const ListBase *listbase, int number) } /** - * Returns the nth-last element of \a listbase, numbering from 1. + * Returns the nth-last element of \a listbase, numbering from 0. */ void *BLI_rfindlink(const ListBase *listbase, int number) { @@ -390,7 +390,7 @@ void *BLI_rfindlink(const ListBase *listbase, int number) } /** - * Returns the position of \a vlink within \a listbase, numbering from 1, or -1 if not found. + * Returns the position of \a vlink within \a listbase, numbering from 0, or -1 if not found. */ int BLI_findindex(const ListBase *listbase, const void *vlink) { @@ -599,7 +599,7 @@ void BLI_listbase_reverse(ListBase *lb) /** * \param vlink Link to make first. */ -void BLI_rotatelist_first(ListBase *lb, void *vlink) +void BLI_listbase_rotate_first(ListBase *lb, void *vlink) { /* make circular */ ((Link *)lb->first)->prev = lb->last; @@ -615,7 +615,7 @@ void BLI_rotatelist_first(ListBase *lb, void *vlink) /** * \param vlink Link to make last. */ -void BLI_rotatelist_last(ListBase *lb, void *vlink) +void BLI_listbase_rotate_last(ListBase *lb, void *vlink) { /* make circular */ ((Link *)lb->first)->prev = lb->last; diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c index 57a48bb5fa8..3ed7230b1d2 100644 --- a/source/blender/blenlib/intern/math_color.c +++ b/source/blender/blenlib/intern/math_color.c @@ -37,112 +37,38 @@ void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b) { - if (s != 0.0f) { - float i, f, p; - h = (h - floorf(h)) * 6.0f; - - i = floorf(h); - f = h - i; - - /* avoid computing q/t when not needed */ - p = (v * (1.0f - s)); -#define q (v * (1.0f - (s * f))) -#define t (v * (1.0f - (s * (1.0f - f)))) - - /* faster to compare floats then int conversion */ - if (i < 1.0f) { - *r = v; - *g = t; - *b = p; - } - else if (i < 2.0f) { - *r = q; - *g = v; - *b = p; - } - else if (i < 3.0f) { - *r = p; - *g = v; - *b = t; - } - else if (i < 4.0f) { - *r = p; - *g = q; - *b = v; - } - else if (i < 5.0f) { - *r = t; - *g = p; - *b = v; - } - else { - *r = v; - *g = p; - *b = q; - } + float nr, ng, nb; -#undef q -#undef t + nr = fabsf(h * 6.0f - 3.0f) - 1.0f; + ng = 2.0f - fabsf(h * 6.0f - 2.0f); + nb = 2.0f - fabsf(h * 6.0f - 4.0f); - } - else { - *r = v; - *g = v; - *b = v; - } + CLAMP(nr, 0.0f, 1.0f); + CLAMP(nb, 0.0f, 1.0f); + CLAMP(ng, 0.0f, 1.0f); + + *r = ((nr - 1.0f) * s + 1.0f) * v; + *g = ((ng - 1.0f) * s + 1.0f) * v; + *b = ((nb - 1.0f) * s + 1.0f) * v; } -/* HSL to rgb conversion from https://en.wikipedia.org/wiki/HSL_and_HSV */ void hsl_to_rgb(float h, float s, float l, float *r, float *g, float *b) { - float i, f, c; - h = (h - floorf(h)) * 6.0f; - c = (l > 0.5f) ? (2.0f * (1.0f - l) * s) : (2.0f * l * s); - i = floorf(h); - f = h - i; + float nr, ng, nb, chroma; -#define x2 (c * f) -#define x1 (c * (1.0f - f)) + nr = fabsf(h * 6.0f - 3.0f) - 1.0f; + ng = 2.0f - fabsf(h * 6.0f - 2.0f); + nb = 2.0f - fabsf(h * 6.0f - 4.0f); - /* faster to compare floats then int conversion */ - if (i < 1.0f) { - *r = c; - *g = x2; - *b = 0; - } - else if (i < 2.0f) { - *r = x1; - *g = c; - *b = 0; - } - else if (i < 3.0f) { - *r = 0; - *g = c; - *b = x2; - } - else if (i < 4.0f) { - *r = 0; - *g = x1; - *b = c; - } - else if (i < 5.0f) { - *r = x2; - *g = 0; - *b = c; - } - else { - *r = c; - *g = 0; - *b = x1; - } + CLAMP(nr, 0.0f, 1.0f); + CLAMP(nb, 0.0f, 1.0f); + CLAMP(ng, 0.0f, 1.0f); -#undef x1 -#undef x2 + chroma = (1.0f - fabsf(2.0f * l - 1.0f)) * s; - f = l - 0.5f * c; - *r += f; - *g += f; - *b += f; + *r = (nr - 0.5f) * chroma + l; + *g = (ng - 0.5f) * chroma + l; + *b = (nb - 0.5f) * chroma + l; } /* convenience function for now */ @@ -152,9 +78,9 @@ void hsv_to_rgb_v(const float hsv[3], float r_rgb[3]) } /* convenience function for now */ -void hsl_to_rgb_v(const float hcl[3], float r_rgb[3]) +void hsl_to_rgb_v(const float hsl[3], float r_rgb[3]) { - hsl_to_rgb(hcl[0], hcl[1], hcl[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]); + hsl_to_rgb(hsl[0], hsl[1], hsl[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]); } void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv) @@ -187,7 +113,7 @@ void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb) void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr, int colorspace) { float sr, sg, sb; - float y = 128.f, cr = 128.f, cb = 128.f; + float y = 128.0f, cr = 128.0f, cb = 128.0f; sr = 255.0f * r; sg = 255.0f * g; @@ -226,7 +152,7 @@ void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr, in /* FIXME comment above must be wrong because BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009 */ void ycc_to_rgb(float y, float cb, float cr, float *lr, float *lg, float *lb, int colorspace) { - float r = 128.f, g = 128.f, b = 128.f; + float r = 128.0f, g = 128.0f, b = 128.0f; switch (colorspace) { case BLI_YCC_ITU_BT601: @@ -284,57 +210,26 @@ void hex_to_rgb(char *hexcol, float *r, float *g, float *b) void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv) { - float h, s, v; - float cmax, cmin; - - cmax = r; - cmin = r; - cmax = (g > cmax ? g : cmax); - cmin = (g < cmin ? g : cmin); - cmax = (b > cmax ? b : cmax); - cmin = (b < cmin ? b : cmin); - - v = cmax; /* value */ - if (cmax != 0.0f) { - float cdelta; - - cdelta = cmax - cmin; - s = cdelta / cmax; - - if (s != 0.0f) { - float rc, gc, bc; - - rc = (cmax - r) / cdelta; - gc = (cmax - g) / cdelta; - bc = (cmax - b) / cdelta; - - if (r == cmax) { - h = bc - gc; - if (h < 0.0f) { - h += 6.0f; - } - } - else if (g == cmax) { - h = 2.0f + rc - bc; - } - else { - h = 4.0f + gc - rc; - } - - h *= (1.0f / 6.0f); - } - else { - h = 0.0f; - } + float k = 0.0f; + float chroma; + float min_gb; + + if (g < b) { + SWAP(float, g, b); + k = -1.0f; } - else { - h = 0.0f; - s = 0.0f; + min_gb = b; + if (r < g) { + SWAP(float, r, g); + k = -2.0f / 6.0f - k; + min_gb = min_ff(g, b); } - *lh = h; - *ls = s; - *lv = v; + chroma = r - min_gb; + + *lh = fabsf(k + (g - b) / (6.0f * chroma + 1e-20f)); + *ls = chroma / (r + 1e-20f); + *lv = r; } /* convenience function for now */ @@ -374,8 +269,8 @@ void rgb_to_hsl(float r, float g, float b, float *lh, float *ls, float *ll) void rgb_to_hsl_compat(float r, float g, float b, float *lh, float *ls, float *ll) { - float orig_s = *ls; - float orig_h = *lh; + const float orig_s = *ls; + const float orig_h = *lh; rgb_to_hsl(r, g, b, lh, ls, ll); @@ -407,8 +302,8 @@ void rgb_to_hsl_v(const float rgb[3], float r_hsl[3]) void rgb_to_hsv_compat(float r, float g, float b, float *lh, float *ls, float *lv) { - float orig_h = *lh; - float orig_s = *ls; + const float orig_h = *lh; + const float orig_s = *ls; rgb_to_hsv(r, g, b, lh, ls, lv); @@ -703,11 +598,12 @@ static float index_to_float(const unsigned short i) void BLI_init_srgb_conversion(void) { - static int initialized = 0; + static bool initialized = false; unsigned int i, b; - if (initialized) return; - initialized = 1; + if (initialized) + return; + initialized = true; /* Fill in the lookup table to convert floats to bytes: */ for (i = 0; i < 0x10000; i++) { @@ -736,6 +632,9 @@ static float inverse_srgb_companding(float v) } } +/** + * \note Does sRGB to linear conversion + */ void rgb_to_xyz(float r, float g, float b, float *x, float *y, float *z) { r = inverse_srgb_companding(r) * 100.0f; @@ -762,13 +661,13 @@ static float xyz_to_lab_component(float v) void xyz_to_lab(float x, float y, float z, float *l, float *a, float *b) { - float xr = x / 95.047f; - float yr = y / 100.0f; - float zr = z / 108.883f; + const float xr = x / 95.047f; + const float yr = y / 100.0f; + const float zr = z / 108.883f; - float fx = xyz_to_lab_component(xr); - float fy = xyz_to_lab_component(yr); - float fz = xyz_to_lab_component(zr); + const float fx = xyz_to_lab_component(xr); + const float fy = xyz_to_lab_component(yr); + const float fz = xyz_to_lab_component(zr); *l = 116.0f * fy - 16.0f; *a = 500.0f * (fx - fy); diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c index 4810fe757fa..2522fe5f6c9 100644 --- a/source/blender/blenlib/intern/math_color_blend_inline.c +++ b/source/blender/blenlib/intern/math_color_blend_inline.c @@ -30,11 +30,16 @@ #include "BLI_math_base.h" #include "BLI_math_color.h" #include "BLI_math_color_blend.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" #ifndef __MATH_COLOR_BLEND_INLINE_C__ #define __MATH_COLOR_BLEND_INLINE_C__ +/* don't add any saturation to a completly black and white image */ +#define EPS_SATURATION 0.0005f +#define EPS_ALPHA 0.0005f + /***************************** Color Blending ******************************** * * - byte colors are assumed to be straight alpha @@ -67,10 +72,7 @@ MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1 } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -92,10 +94,7 @@ MINLINE void blend_color_add_byte(unsigned char dst[4], const unsigned char src1 } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -117,10 +116,7 @@ MINLINE void blend_color_sub_byte(unsigned char dst[4], const unsigned char src1 } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -143,10 +139,7 @@ MINLINE void blend_color_mul_byte(unsigned char dst[4], const unsigned char src1 } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -169,10 +162,7 @@ MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -195,10 +185,7 @@ MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char s } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -215,10 +202,7 @@ MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned c } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -235,11 +219,391 @@ MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned cha } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + +MINLINE void blend_color_overlay_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = (int)src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + int temp; + + if (src1[i] > 127) { + temp = 255 - ((255 - 2 * (src1[i] - 127)) * (255 - src2[i]) / 255); + } + else { + temp = (2 * src1[i] * src2[i]) >> 8; + } + dst[i] = (unsigned char)min_ii((temp * fac + src1[i] * mfac) / 255, 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_hardlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = (int)src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + int temp; + + if (src2[i] > 127) { + temp = 255 - ((255 - 2 * (src2[i] - 127)) * (255 - src1[i]) / 255); + } + else { + temp = (2 * src2[i] * src1[i]) >> 8; + } + dst[i] = (unsigned char)min_ii((temp * fac + src1[i] * mfac) / 255, 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_burn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + const int temp = (src2[i] == 0) ? 0 : max_ii(255 - ((255 - src1[i]) * 255) / src2[i], 0); + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_linearburn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + const int temp = max_ii(src1[i] + src2[i] - 255, 0); + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_dodge_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + const int temp = (src2[i] == 255) ? 255 : min_ii((src1[i] * 255) / (255 - src2[i]), 255); + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + +MINLINE void blend_color_screen_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + const int temp = max_ii(255 - (((255 - src1[i]) * (255 - src2[i])) / 255), 0); + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_softlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + int temp; + + if (src1[i] < 127) { + temp = ((2 * ((src2[i] / 2) + 64)) * src1[i]) / 255; + } + else { + temp = 255 - (2 * (255 - ((src2[i] / 2) + 64)) * (255 - src1[i]) / 255); + } + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_pinlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + int temp; + + if (src2[i] > 127) { + temp = max_ii(2 * (src2[i] - 127), src1[i]); + } + else { + temp = min_ii(2 * src2[i], src1[i]); + } + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_linearlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + int temp; + + if (src2[i] > 127) { + temp = min_ii(src1[i] + 2 * (src2[i] - 127), 255); + } + else { + temp = max_ii(src1[i] + 2 * src2[i] - 255, 0); + } + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + int temp; + + if (src2[i] == 255) { + temp = 255; + } + else if (src2[i] == 0) { + temp = 0; + } + else if (src2[i] > 127) { + temp = min_ii(((src1[i]) * 255) / (2 * (255 - src2[i])), 255); + } + else { + temp = max_ii(255 - ((255 - src1[i]) * 255 / (2 * src2[i])), 0); + } + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + + +MINLINE void blend_color_difference_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + const int temp = abs(src1[i] - src2[i]); + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_exclusion_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + const int temp = 127 - ((2 * (src1[i] - 127) * (src2[i] - 127)) / 255); + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + +MINLINE void blend_color_color_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2); + + + h1 = h2; + s1 = s2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (unsigned char)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255); + dst[1] = (unsigned char)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255); + dst[2] = (unsigned char)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255); + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + +MINLINE void blend_color_hue_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2); + + + h1 = h2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (unsigned char)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255); + dst[1] = (unsigned char)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255); + dst[2] = (unsigned char)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255); + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } + +} + +MINLINE void blend_color_saturation_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2); + + if (s1 > EPS_SATURATION) { + s1 = s2; + } + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (unsigned char)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255); + dst[1] = (unsigned char)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255); + dst[2] = (unsigned char)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255); + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + +MINLINE void blend_color_luminosity_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2); + + v1 = v2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (unsigned char)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255); + dst[1] = (unsigned char)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255); + dst[2] = (unsigned char)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255); + + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); } + } MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], float ft) @@ -257,10 +621,7 @@ MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned c dst[3] = (unsigned char)divide_round_i(tmp, 255); } else { - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -280,10 +641,7 @@ MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const floa } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -298,10 +656,7 @@ MINLINE void blend_color_add_float(float dst[4], const float src1[4], const floa } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -316,10 +671,7 @@ MINLINE void blend_color_sub_float(float dst[4], const float src1[4], const floa } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -337,10 +689,7 @@ MINLINE void blend_color_mul_float(float dst[4], const float src1[4], const floa } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -360,10 +709,7 @@ MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -383,10 +729,7 @@ MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const f } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -397,8 +740,9 @@ MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], co float alpha = max_ff(src1[3] - src2[3], 0.0f); float map_alpha; - if (alpha <= 0.0005f) + if (alpha <= EPS_ALPHA) { alpha = 0.0f; + } map_alpha = alpha / src1[3]; @@ -409,10 +753,7 @@ MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], co } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -423,8 +764,9 @@ MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], cons float alpha = min_ff(src1[3] + src2[3], 1.0f); float map_alpha; - if (alpha >= 1.0f - 0.0005f) + if (alpha >= 1.0f - EPS_ALPHA) { alpha = 1.0f; + } map_alpha = (src1[3] > 0.0f) ? alpha / src1[3] : 1.0f; @@ -435,17 +777,390 @@ MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], cons } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_overlay_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + float temp; + + if (src1[i] > 0.5f) { + temp = 1.0f - (1.0f - 2.0f * (src1[i] - 0.5f)) * (1.0f - src2[i]); + } + else { + temp = 2.0f * src1[i] * src2[i]; + } + dst[i] = min_ff(temp * fac + src1[i] * mfac, 1.0f); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + + +MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], const float src2[2]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + float temp; + + if (src2[i] > 0.5f) { + temp = 1.0f - ((1.0f - 2.0f * (src2[i] - 0.5f)) * (1.0f - src1[i])); + } + else { + temp = 2.0f * src2[i] * src1[i]; + } + dst[i] = min_ff((temp * fac + src1[i] * mfac) / 1.0f, 1.0f); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_burn_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + const float temp = (src2[i] == 0.0f) ? 0.0f : max_ff(1.0f - ((1.0f - src1[i]) / src2[i]), 0.0f); + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_linearburn_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + const float temp = max_ff(src1[i] + src2[i] - 1.0f, 0.0f); + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + + +MINLINE void blend_color_dodge_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + const float temp = (src2[i] >= 1.0f) ? 1.0f : min_ff(src1[i] / (1.0f - src2[i]), 1.0f); + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_screen_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + const float temp = max_ff(1.0f - ((1.0f - src1[i]) * (1.0f - src2[i])), 0.0f); + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_softlight_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + float temp; + + if (src1[i] < 0.5f) { + temp = (src2[i] + 0.5f) * src1[i]; + } + else { + temp = 1.0f - ((1.0f - (src2[i] + 0.5f)) * (1.0f - src1[i])); + } + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_pinlight_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + float temp; + + if (src2[i] > 0.5f) { + temp = max_ff(2.0f * (src2[i] - 0.5f), src1[i]); + } + else { + temp = min_ff(2.0f * src2[i], src1[i]); + } + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + + +MINLINE void blend_color_linearlight_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + float temp; + + if (src2[i] > 0.5f) { + temp = min_ff(src1[i] + 2.0f * (src2[i] - 0.5f), 1.0f); + } + else { + temp = max_ff(src1[i] + 2.0f * src2[i] - 1.0f, 0.0f); + } + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + + +MINLINE void blend_color_vividlight_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + float temp; + + if (src2[i] == 1.0f) { + temp = 1.0f; + } + else if (src2[i] == 0.0f) { + temp = 0.0f; + } + else if (src2[i] > 0.5f) { + temp = min_ff(((src1[i]) * 1.0f) / (2.0f * (1.0f - src2[i])), 1.0f); + } + else { + temp = max_ff(1.0f - ((1.0f - src1[i]) * 1.0f / (2.0f * src2[i])), 0.0f); + } + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_difference_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + dst[i] = (fabsf(src1[i] - src2[i]) * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); } } + +MINLINE void blend_color_exclusion_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + const float temp = 0.5f - ((2 * (src1[i] - 0.5f) * (src2[i] - 0.5f))); + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } + +} + +MINLINE void blend_color_color_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + + rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1); + rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2); + + h1 = h2; + s1 = s2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (r * fac + src1[0] * mfac); + dst[1] = (g * fac + src1[1] * mfac); + dst[2] = (b * fac + src1[2] * mfac); + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + + +MINLINE void blend_color_hue_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + + rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1); + rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2); + + h1 = h2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (r * fac + src1[0] * mfac); + dst[1] = (g * fac + src1[1] * mfac); + dst[2] = (b * fac + src1[2] * mfac); + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_saturation_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + + rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1); + rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2); + + if (s1 > EPS_SATURATION) { + s1 = s2; + } + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (r * fac + src1[0] * mfac); + dst[1] = (g * fac + src1[1] * mfac); + dst[2] = (b * fac + src1[2] * mfac); + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_luminosity_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + + rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1); + rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2); + + v1 = v2; + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (r * fac + src1[0] * mfac); + dst[1] = (g * fac + src1[1] * mfac); + dst[2] = (b * fac + src1[2] * mfac); + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + + MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t) { /* interpolation, colors are premultiplied so it goes fine */ - float mt = 1.0f - t; + const float mt = 1.0f - t; dst[0] = mt * src1[0] + t * src2[0]; dst[1] = mt * src1[1] + t * src2[1]; @@ -453,4 +1168,7 @@ MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], co dst[3] = mt * src1[3] + t * src2[3]; } +#undef EPS_SATURATION +#undef EPS_ALPHA + #endif /* __MATH_COLOR_BLEND_INLINE_C__ */ diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c index bb2201541d9..9233749d5df 100644 --- a/source/blender/blenlib/intern/math_color_inline.c +++ b/source/blender/blenlib/intern/math_color_inline.c @@ -255,11 +255,11 @@ MINLINE float rgb_to_luma_y(const float rgb[3]) MINLINE int compare_rgb_uchar(const unsigned char col_a[3], const unsigned char col_b[3], const int limit) { - int r = (int)col_a[0] - (int)col_b[0]; + const int r = (int)col_a[0] - (int)col_b[0]; if (ABS(r) < limit) { - int g = (int)col_a[1] - (int)col_b[1]; + const int g = (int)col_a[1] - (int)col_b[1]; if (ABS(g) < limit) { - int b = (int)col_a[2] - (int)col_b[2]; + const int b = (int)col_a[2] - (int)col_b[2]; if (ABS(b) < limit) { return 1; } @@ -280,7 +280,7 @@ MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4]) straight[3] = premul[3]; } else { - float alpha_inv = 1.0f / premul[3]; + const float alpha_inv = 1.0f / premul[3]; straight[0] = premul[0] * alpha_inv; straight[1] = premul[1] * alpha_inv; straight[2] = premul[2] * alpha_inv; @@ -295,7 +295,7 @@ MINLINE void premul_to_straight_v4(float color[4]) MINLINE void straight_to_premul_v4_v4(float premul[4], const float straight[4]) { - float alpha = straight[3]; + const float alpha = straight[3]; premul[0] = straight[0] * alpha; premul[1] = straight[1] * alpha; premul[2] = straight[2] * alpha; @@ -309,8 +309,8 @@ MINLINE void straight_to_premul_v4(float color[4]) MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4]) { - float alpha = color[3] * (1.0f / 255.0f); - float fac = alpha * (1.0f / 255.0f); + const float alpha = color[3] * (1.0f / 255.0f); + const float fac = alpha * (1.0f / 255.0f); result[0] = color[0] * fac; result[1] = color[1] * fac; @@ -327,7 +327,7 @@ MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float c result[3] = FTOCHAR(color[3]); } else { - float alpha_inv = 1.0f / color[3]; + const float alpha_inv = 1.0f / color[3]; /* hopefully this would be optimized */ result[0] = FTOCHAR(color[0] * alpha_inv); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 5f3ab5eb73e..1cd1d1875fc 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -238,6 +238,18 @@ float volume_tetrahedron_v3(const float v1[3], const float v2[3], const float v3 return fabsf(determinant_m3_array(m)) / 6.0f; } +/** + * The volume from a tetrahedron, normal pointing inside gives negative volume + */ +float volume_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]) +{ + float m[3][3]; + sub_v3_v3v3(m[0], v1, v2); + sub_v3_v3v3(m[1], v2, v3); + sub_v3_v3v3(m[2], v3, v4); + return determinant_m3_array(m) / 6.0f; +} + /********************************* Distance **********************************/ @@ -364,24 +376,36 @@ void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[ madd_v3_v3v3fl(r_close, pt, plane, -side / len_sq); } -float dist_squared_to_plane_v3(const float pt[3], const float plane[4]) +float dist_signed_squared_to_plane_v3(const float pt[3], const float plane[4]) { const float len_sq = len_squared_v3(plane); const float side = plane_point_side_v3(plane, pt); const float fac = side / len_sq; return copysignf(len_sq * (fac * fac), side); } +float dist_squared_to_plane_v3(const float pt[3], const float plane[4]) +{ + const float len_sq = len_squared_v3(plane); + const float side = plane_point_side_v3(plane, pt); + const float fac = side / len_sq; + /* only difference to code above - no 'copysignf' */ + return len_sq * (fac * fac); +} /** * Return the signed distance from the point to the plane. */ -float dist_to_plane_v3(const float pt[3], const float plane[4]) +float dist_signed_to_plane_v3(const float pt[3], const float plane[4]) { const float len_sq = len_squared_v3(plane); const float side = plane_point_side_v3(plane, pt); const float fac = side / len_sq; return sqrtf(len_sq) * fac; } +float dist_to_plane_v3(const float pt[3], const float plane[4]) +{ + return fabsf(dist_signed_to_plane_v3(pt, plane)); +} /* distance v1 to line-piece l1-l2 in 3D */ float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3]) @@ -556,7 +580,7 @@ int isect_seg_seg_v2_point(const float v1[2], const float v2[2], const float v3[ { float a1, a2, b1, b2, c1, c2, d; float u, v; - const float eps = 0.000001f; + const float eps = 1e-6f; const float eps_sq = eps * eps; a1 = v2[0] - v1[0]; @@ -953,7 +977,7 @@ bool isect_line_tri_v3(const float p1[3], const float p2[3], cross_v3_v3v3(p, d, e2); a = dot_v3v3(e1, p); - if ((a > -0.000001f) && (a < 0.000001f)) return 0; + if (a == 0.0f) return 0; f = 1.0f / a; sub_v3_v3v3(s, p1, v0); @@ -992,7 +1016,7 @@ bool isect_line_tri_epsilon_v3(const float p1[3], const float p2[3], cross_v3_v3v3(p, d, e2); a = dot_v3v3(e1, p); - if ((a > -0.000001f) && (a < 0.000001f)) return 0; + if (a == 0.0f) return 0; f = 1.0f / a; sub_v3_v3v3(s, p1, v0); @@ -1266,13 +1290,13 @@ bool isect_plane_plane_v3(float r_isect_co[3], float r_isect_no[3], static bool getLowestRoot(const float a, const float b, const float c, const float maxR, float *root) { /* Check if a solution exists */ - float determinant = b * b - 4.0f * a * c; + const float determinant = b * b - 4.0f * a * c; /* If determinant is negative it means no solutions. */ if (determinant >= 0.0f) { /* calculate the two roots: (if determinant == 0 then * x1==x2 but lets disregard that slight optimization) */ - float sqrtD = sqrtf(determinant); + const float sqrtD = sqrtf(determinant); float r1 = (-b - sqrtD) / (2.0f * a); float r2 = (-b + sqrtD) / (2.0f * a); @@ -1283,18 +1307,18 @@ static bool getLowestRoot(const float a, const float b, const float c, const flo /* Get lowest root: */ if (r1 > 0.0f && r1 < maxR) { *root = r1; - return 1; + return true; } /* It is possible that we want x2 - this can happen */ /* if x1 < 0 */ if (r2 > 0.0f && r2 < maxR) { *root = r2; - return 1; + return true; } } /* No (valid) solutions */ - return 0; + return false; } bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const float radius, @@ -1323,7 +1347,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl if (fabsf(nordotv) < 0.000001f) { if (fabsf(a) >= radius) { - return 0; + return false; } } else { @@ -1365,7 +1389,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl //(((unsigned int)z)& ~(((unsigned int)x)|((unsigned int)y))) & 0x80000000) { *r_lambda = t0; copy_v3_v3(ipoint, point); - return 1; + return true; } } @@ -1382,7 +1406,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl if (getLowestRoot(a, b, c, *r_lambda, r_lambda)) { copy_v3_v3(ipoint, v0); - found_by_sweep = 1; + found_by_sweep = true; } /*v1*/ @@ -1392,7 +1416,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl if (getLowestRoot(a, b, c, *r_lambda, r_lambda)) { copy_v3_v3(ipoint, v1); - found_by_sweep = 1; + found_by_sweep = true; } /*v2*/ @@ -1402,7 +1426,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl if (getLowestRoot(a, b, c, *r_lambda, r_lambda)) { copy_v3_v3(ipoint, v2); - found_by_sweep = 1; + found_by_sweep = true; } /*---test edges---*/ @@ -1428,7 +1452,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl copy_v3_v3(ipoint, e1); mul_v3_fl(ipoint, e); add_v3_v3(ipoint, v0); - found_by_sweep = 1; + found_by_sweep = true; } } @@ -1450,7 +1474,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl copy_v3_v3(ipoint, e2); mul_v3_fl(ipoint, e); add_v3_v3(ipoint, v0); - found_by_sweep = 1; + found_by_sweep = true; } } @@ -1477,7 +1501,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl copy_v3_v3(ipoint, e3); mul_v3_fl(ipoint, e); add_v3_v3(ipoint, v1); - found_by_sweep = 1; + found_by_sweep = true; } } @@ -1496,10 +1520,10 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3 return isect_line_tri_v3(p1, p2, v0, v1, v2, lambda); /* first a simple bounding box test */ - if (min_fff(v0[a1], v1[a1], v2[a1]) > p1[a1]) return 0; - if (min_fff(v0[a2], v1[a2], v2[a2]) > p1[a2]) return 0; - if (max_fff(v0[a1], v1[a1], v2[a1]) < p1[a1]) return 0; - if (max_fff(v0[a2], v1[a2], v2[a2]) < p1[a2]) return 0; + if (min_fff(v0[a1], v1[a1], v2[a1]) > p1[a1]) return false; + if (min_fff(v0[a2], v1[a2], v2[a2]) > p1[a2]) return false; + if (max_fff(v0[a1], v1[a1], v2[a1]) < p1[a1]) return false; + if (max_fff(v0[a2], v1[a2], v2[a2]) < p1[a2]) return false; /* then a full intersection test */ #endif @@ -1509,7 +1533,7 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3 sub_v3_v3v3(p, v0, p1); f = (e2[a1] * e1[a2] - e2[a2] * e1[a1]); - if ((f > -0.000001f) && (f < 0.000001f)) return 0; + if ((f > -0.000001f) && (f < 0.000001f)) return false; v = (p[a2] * e1[a1] - p[a1] * e1[a2]) / f; if ((v < 0.0f) || (v > 1.0f)) return 0; @@ -1517,7 +1541,7 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3 f = e1[a1]; if ((f > -0.000001f) && (f < 0.000001f)) { f = e1[a2]; - if ((f > -0.000001f) && (f < 0.000001f)) return 0; + if ((f > -0.000001f) && (f < 0.000001f)) return false; u = (-p[a2] - v * e2[a2]) / f; } else @@ -1527,9 +1551,9 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3 *r_lambda = (p[a0] + u * e1[a0] + v * e2[a0]) / (p2[a0] - p1[a0]); - if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) return 0; + if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) return false; - return 1; + return true; } /** @@ -1538,7 +1562,10 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3 * 1 - lines are coplanar, i1 is set to intersection * 2 - i1 and i2 are the nearest points on line 1 (v1, v2) and line 2 (v3, v4) respectively */ -int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float i1[3], float i2[3]) +int isect_line_line_epsilon_v3( + const float v1[3], const float v2[3], + const float v3[3], const float v4[3], float i1[3], float i2[3], + const float epsilon) { float a[3], b[3], c[3], ab[3], cb[3], dir1[3], dir2[3]; float d, div; @@ -1564,7 +1591,7 @@ int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3], return 0; } /* test if the two lines are coplanar */ - else if (d > -0.000001f && d < 0.000001f) { + else if (UNLIKELY(fabsf(d) <= epsilon)) { cross_v3_v3v3(cb, c, b); mul_v3_fl(a, dot_v3v3(cb, ab) / div); @@ -1604,9 +1631,17 @@ int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3], } } -/* Intersection point strictly between the two lines - * 0 when no intersection is found - * */ +int isect_line_line_v3( + const float v1[3], const float v2[3], + const float v3[3], const float v4[3], float i1[3], float i2[3]) +{ + const float epsilon = 0.000001f; + return isect_line_line_epsilon_v3(v1, v2, v3, v4, i1, i2, epsilon); +} + +/** Intersection point strictly between the two lines + * \return false when no intersection is found + */ bool isect_line_line_strict_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float vi[3], float *r_lambda) @@ -1623,7 +1658,7 @@ bool isect_line_line_strict_v3(const float v1[3], const float v2[3], d = dot_v3v3(dir1, dir2); if (d == 1.0f || d == -1.0f || d == 0) { /* colinear or one vector is zero-length*/ - return 0; + return false; } cross_v3_v3v3(ab, a, b); @@ -1632,7 +1667,7 @@ bool isect_line_line_strict_v3(const float v1[3], const float v2[3], /* test zero length line */ if (UNLIKELY(div == 0.0f)) { - return 0; + return false; } /* test if the two lines are coplanar */ else if (d > -0.000001f && d < 0.000001f) { @@ -1651,14 +1686,14 @@ bool isect_line_line_strict_v3(const float v1[3], const float v2[3], if (r_lambda) *r_lambda = f1; - return 1; /* intersection found */ + return true; /* intersection found */ } else { - return 0; + return false; } } else { - return 0; + return false; } } @@ -1676,9 +1711,9 @@ void isect_ray_aabb_initialize(IsectRayAABBData *data, const float ray_start[3], data->ray_inv_dir[1] = 1.0f / ray_direction[1]; data->ray_inv_dir[2] = 1.0f / ray_direction[2]; - data->sign[0] = data->ray_inv_dir[0] < 0; - data->sign[1] = data->ray_inv_dir[1] < 0; - data->sign[2] = data->ray_inv_dir[2] < 0; + data->sign[0] = data->ray_inv_dir[0] < 0.0f; + data->sign[1] = data->ray_inv_dir[1] < 0.0f; + data->sign[2] = data->ray_inv_dir[2] < 0.0f; } /* Adapted from http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */ @@ -1796,8 +1831,9 @@ float line_plane_factor_v3(const float plane_co[3], const float plane_no[3], return (dot != 0.0f) ? -dot_v3v3(plane_no, h) / dot : 0.0f; } -/* ensure the distance between these points is no greater then 'dist' - * if it is, scale then both into the center */ +/** 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) { const float dist_old = len_v3v3(v1, v2); @@ -1862,8 +1898,7 @@ static bool point_in_slice(const float p[3], const float v1[3], const float l1[3 sub_v3_v3v3(rp, p, v1); h = dot_v3v3(q, rp) / dot_v3v3(q, q); - if (h < 0.0f || h > 1.0f) return 0; - return 1; + return (h < 0.0f || h > 1.0f) ? false : true; } #if 0 @@ -1892,10 +1927,43 @@ static int point_in_slice_m(float p[3], float origin[3], float normal[3], float bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3]) { - if (!point_in_slice(p, v1, v2, v3)) return 0; - if (!point_in_slice(p, v2, v3, v1)) return 0; - if (!point_in_slice(p, v3, v1, v2)) return 0; - return 1; + if (!point_in_slice(p, v1, v2, v3)) return false; + if (!point_in_slice(p, v2, v3, v1)) return false; + if (!point_in_slice(p, v3, v1, v2)) return false; + return true; +} + +/** + * \param r_vi The point \a p projected onto the triangle. + * \return True when \a p is inside the triangle. + * \note Its up to the caller to check the distance between \a p and \a r_vi against an error margin. + */ +bool isect_point_tri_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3], + float r_vi[3]) +{ + if (isect_point_tri_prism_v3(p, v1, v2, v3)) { + float no[3], n1[3], n2[3]; + + /* Could use normal_tri_v3, but doesn't have to be unit-length */ + sub_v3_v3v3(n1, v1, v2); + sub_v3_v3v3(n2, v2, v3); + cross_v3_v3v3(no, n1, n2); + + if (LIKELY(len_squared_v3(no) != 0.0f)) { + float plane[4]; + plane_from_point_normal_v3(plane, v1, no); + closest_to_plane_v3(r_vi, plane, p); + } + else { + /* degenerate */ + copy_v3_v3(r_vi, p); + } + + return true; + } + else { + return false; + } } bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4]) @@ -1906,7 +1974,7 @@ bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4]) div = dot_v3v3(dp, plane); if (div == 0.0f) /* parallel */ - return 1; + return true; t = -plane_point_side_v3(plane, p1) / div; @@ -1915,34 +1983,34 @@ bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4]) if (t >= 1.0f) { zero_v3(p1); zero_v3(p2); - return 0; + return false; } /* intersect plane */ if (t > 0.0f) { madd_v3_v3v3fl(pc, p1, dp, t); copy_v3_v3(p1, pc); - return 1; + return true; } - return 1; + return true; } else { /* behind plane, completely clipped */ if (t <= 0.0f) { zero_v3(p1); zero_v3(p2); - return 0; + return false; } /* intersect plane */ if (t < 1.0f) { madd_v3_v3v3fl(pc, p1, dp, t); copy_v3_v3(p2, pc); - return 1; + return true; } - return 1; + return true; } } @@ -2171,12 +2239,12 @@ static bool barycentric_weights(const float v1[3], const float v2[3], const floa if (fabsf(wtot) > FLT_EPSILON) { mul_v3_fl(w, 1.0f / wtot); - return 0; + return false; } else { /* zero area triangle */ copy_v3_fl(w, 1.0f / 3.0f); - return 1; + return true; } } @@ -2227,8 +2295,9 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co } } } - else + else { barycentric_weights(v1, v2, v3, co, n, w); + } } } @@ -2254,11 +2323,11 @@ int barycentric_inside_triangle_v2(const float w[3]) /* returns 0 for degenerated triangles */ bool barycentric_coords_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]) { - float x = co[0], y = co[1]; - float x1 = v1[0], y1 = v1[1]; - float x2 = v2[0], y2 = v2[1]; - float x3 = v3[0], y3 = v3[1]; - float det = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3); + const float x = co[0], y = co[1]; + const float x1 = v1[0], y1 = v1[1]; + const float x2 = v2[0], y2 = v2[1]; + const float x3 = v3[0], y3 = v3[1]; + const float det = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3); if (fabsf(det) > FLT_EPSILON) { w[0] = ((y2 - y3) * (x - x3) + (x3 - x2) * (y - y3)) / det; @@ -2307,8 +2376,9 @@ void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const fl if (wtot != 0.0f) { mul_v3_fl(w, 1.0f / wtot); } - else /* dummy values for zero area face */ + else { /* dummy values for zero area face */ w[0] = w[1] = w[2] = 1.0f / 3.0f; + } } /* same as #barycentric_weights_v2 but works with a quad, @@ -2343,8 +2413,7 @@ void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const flo 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 if (UNLIKELY(lens[3] < FLT_EPSILON)) { w[3] = 1.0f; w[0] = w[1] = w[2] = 0.0f; } else { float wtot, area; @@ -2388,9 +2457,10 @@ void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const flo /* given 2 triangles in 3D space, and a point in relation to the first triangle. * calculate the location of a point in relation to the second triangle. * Useful for finding relative positions with geometry */ -void barycentric_transform(float pt_tar[3], float const pt_src[3], - const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3], - const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3]) +void transform_point_by_tri_v3( + float pt_tar[3], float const pt_src[3], + const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3], + const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3]) { /* this works by moving the source triangle so its normal is pointing on the Z * axis where its barycentric weights can be calculated in 2D and its Z offset can @@ -2427,6 +2497,19 @@ void barycentric_transform(float pt_tar[3], float const pt_src[3], madd_v3_v3v3fl(pt_tar, pt_tar, no_tar, (z_ofs_src / area_src) * area_tar); } +/** + * Simply re-interpolates, + * assumes p_src is between \a l_src_p1-l_src_p2 + */ +void transform_point_by_seg_v3( + float p_dst[3], const float p_src[3], + const float l_dst_p1[3], const float l_dst_p2[3], + const float l_src_p1[3], const float l_src_p2[3]) +{ + float t = line_point_factor_v3(p_src, l_src_p1, l_src_p2); + interp_v3_v3v3(p_dst, l_dst_p1, l_dst_p2, t); +} + /* given an array with some invalid values this function interpolates valid values * replacing the invalid ones */ int interp_sparse_array(float *array, const int list_size, const float skipval) @@ -2551,7 +2634,7 @@ static float mean_value_half_tan_v2(const float v1[2], const float v2[2], const void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[3]) { - const float eps = 0.00001f; /* take care, low values cause [#36105] */ + const float eps = 1e-5f; /* take care, low values cause [#36105] */ const float eps_sq = eps * eps; const float *v_curr, *v_next; float ht_prev, ht; /* half tangents */ @@ -2620,7 +2703,7 @@ void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[2]) { - const float eps = 0.00001f; /* take care, low values cause [#36105] */ + const float eps = 1e-5f; /* take care, low values cause [#36105] */ const float eps_sq = eps * eps; const float *v_curr, *v_next; float ht_prev, ht; /* half tangents */ @@ -2690,8 +2773,8 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[ void interp_cubic_v3(float x[3], float v[3], const float x1[3], const float v1[3], const float x2[3], const float v2[3], const float t) { float a[3], b[3]; - float t2 = t * t; - float t3 = t2 * t; + const float t2 = t * t; + const float t3 = t2 * t; /* cubic interpolation */ a[0] = v1[0] + v2[0] + 2 * (x1[0] - x2[0]); @@ -2916,11 +2999,9 @@ void orthographic_m4(float matrix[4][4], const float left, const float right, co void perspective_m4(float mat[4][4], const float left, const float right, const float bottom, const float top, const float nearClip, const float farClip) { - float Xdelta, Ydelta, Zdelta; - - Xdelta = right - left; - Ydelta = top - bottom; - Zdelta = farClip - nearClip; + const float Xdelta = right - left; + const float Ydelta = top - bottom; + const float Zdelta = farClip - nearClip; if (Xdelta == 0.0f || Ydelta == 0.0f || Zdelta == 0.0f) { return; @@ -2934,7 +3015,7 @@ void perspective_m4(float mat[4][4], const float left, const float right, const mat[3][2] = (-2.0f * nearClip * farClip) / Zdelta; mat[0][1] = mat[0][2] = mat[0][3] = mat[1][0] = mat[1][2] = mat[1][3] = - mat[3][0] = mat[3][1] = mat[3][3] = 0.0; + mat[3][0] = mat[3][1] = mat[3][3] = 0.0f; } @@ -2983,7 +3064,6 @@ static void i_multmatrix(float icand[4][4], float Vm[4][4]) void polarview_m4(float Vm[4][4], float dist, float azimuth, float incidence, float twist) { - unit_m4(Vm); translate_m4(Vm, 0.0, 0.0, -dist); @@ -3005,16 +3085,16 @@ void lookat_m4(float mat[4][4], float vx, float vy, float vz, float px, float py dx = px - vx; dy = py - vy; dz = pz - vz; - hyp = dx * dx + dz * dz; /* hyp squared */ + hyp = dx * dx + dz * dz; /* hyp squared */ hyp1 = sqrtf(dy * dy + hyp); - hyp = sqrtf(hyp); /* the real hyp */ + hyp = sqrtf(hyp); /* the real hyp */ - if (hyp1 != 0.0f) { /* rotate X */ + if (hyp1 != 0.0f) { /* rotate X */ sine = -dy / hyp1; cosine = hyp / hyp1; } else { - sine = 0; + sine = 0.0f; cosine = 1.0f; } mat1[1][1] = cosine; @@ -3024,16 +3104,16 @@ void lookat_m4(float mat[4][4], float vx, float vy, float vz, float px, float py i_multmatrix(mat1, mat); - mat1[1][1] = mat1[2][2] = 1.0f; /* be careful here to reinit */ - mat1[1][2] = mat1[2][1] = 0.0; /* those modified by the last */ + mat1[1][1] = mat1[2][2] = 1.0f; /* be careful here to reinit */ + mat1[1][2] = mat1[2][1] = 0.0f; /* those modified by the last */ - /* paragraph */ - if (hyp != 0.0f) { /* rotate Y */ + /* paragraph */ + if (hyp != 0.0f) { /* rotate Y */ sine = dx / hyp; cosine = -dz / hyp; } else { - sine = 0; + sine = 0.0f; cosine = 1.0f; } mat1[0][0] = cosine; @@ -3214,10 +3294,10 @@ void accumulate_vertex_normals_poly(float **vertnos, const float polyno[3], void tangent_from_uv(float uv1[2], float uv2[2], float uv3[3], float co1[3], float co2[3], float co3[3], float n[3], float tang[3]) { - float s1 = uv2[0] - uv1[0]; - float s2 = uv3[0] - uv1[0]; - float t1 = uv2[1] - uv1[1]; - float t2 = uv3[1] - uv1[1]; + const float s1 = uv2[0] - uv1[0]; + const float s2 = uv3[0] - uv1[0]; + const float t1 = uv2[1] - uv1[1]; + const float t2 = uv3[1] - uv1[1]; float det = (s1 * t2 - s2 * t1); if (det != 0.0f) { /* otherwise 'tang' becomes nan */ @@ -3242,7 +3322,7 @@ void tangent_from_uv(float uv1[2], float uv2[2], float uv3[3], float co1[3], flo } } else { - tang[0] = tang[1] = tang[2] = 0.0; + tang[0] = tang[1] = tang[2] = 0.0f; } } @@ -3275,7 +3355,8 @@ void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, fl float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3]) { float accu_com[3] = {0.0f, 0.0f, 0.0f}, accu_rcom[3] = {0.0f, 0.0f, 0.0f}; - float accu_weight = 0.0f, accu_rweight = 0.0f, eps = 0.000001f; + float accu_weight = 0.0f, accu_rweight = 0.0f; + const float eps = 1e-6f; int a; /* first set up a nice default response */ @@ -3369,7 +3450,7 @@ void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, fl /* this is pretty much Polardecompose 'inline' the algo based on Higham's thesis */ /* without the far case ... but seems to work here pretty neat */ - odet = 0.f; + odet = 0.0f; ndet = determinant_m3_array(q); while ((odet - ndet) * (odet - ndet) > eps && i < imax) { invert_m3_m3(qi, q); @@ -3410,9 +3491,8 @@ bool form_factor_visible_quad(const float p[3], const float n[3], float q0[3], float q1[3], float q2[3], float q3[3]) { static const float epsilon = 1e-6f; - float c, sd[3]; - - c = dot_v3v3(n, p); + float sd[3]; + const float c = dot_v3v3(n, p); /* signed distances from the vertices to the plane. */ sd[0] = dot_v3v3(n, v0) - c; @@ -3423,16 +3503,16 @@ bool form_factor_visible_quad(const float p[3], const float n[3], if (fabsf(sd[1]) < epsilon) sd[1] = 0.0f; if (fabsf(sd[2]) < epsilon) sd[2] = 0.0f; - if (sd[0] > 0) { - if (sd[1] > 0) { - if (sd[2] > 0) { + if (sd[0] > 0.0f) { + if (sd[1] > 0.0f) { + if (sd[2] > 0.0f) { /* +++ */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* ++- */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); @@ -3447,15 +3527,15 @@ bool form_factor_visible_quad(const float p[3], const float n[3], copy_v3_v3(q3, q2); } } - else if (sd[1] < 0) { - if (sd[2] > 0) { + else if (sd[1] < 0.0f) { + if (sd[2] > 0.0f) { /* +-+ */ copy_v3_v3(q0, v0); vec_add_dir(q1, v0, v1, (sd[0] / (sd[0] - sd[1]))); vec_add_dir(q2, v1, v2, (sd[1] / (sd[1] - sd[2]))); copy_v3_v3(q3, v2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* +-- */ copy_v3_v3(q0, v0); vec_add_dir(q1, v0, v1, (sd[0] / (sd[0] - sd[1]))); @@ -3471,14 +3551,14 @@ bool form_factor_visible_quad(const float p[3], const float n[3], } } else { - if (sd[2] > 0) { + if (sd[2] > 0.0f) { /* +0+ */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* +0- */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); @@ -3494,16 +3574,16 @@ bool form_factor_visible_quad(const float p[3], const float n[3], } } } - else if (sd[0] < 0) { - if (sd[1] > 0) { - if (sd[2] > 0) { + else if (sd[0] < 0.0f) { + if (sd[1] > 0.0f) { + if (sd[2] > 0.0f) { /* -++ */ vec_add_dir(q0, v0, v1, (sd[0] / (sd[0] - sd[1]))); copy_v3_v3(q1, v1); copy_v3_v3(q2, v2); vec_add_dir(q3, v0, v2, (sd[0] / (sd[0] - sd[2]))); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* -+- */ vec_add_dir(q0, v0, v1, (sd[0] / (sd[0] - sd[1]))); copy_v3_v3(q1, v1); @@ -3518,15 +3598,15 @@ bool form_factor_visible_quad(const float p[3], const float n[3], copy_v3_v3(q3, q2); } } - else if (sd[1] < 0) { - if (sd[2] > 0) { + else if (sd[1] < 0.0f) { + if (sd[2] > 0.0f) { /* --+ */ vec_add_dir(q0, v0, v2, (sd[0] / (sd[0] - sd[2]))); vec_add_dir(q1, v1, v2, (sd[1] / (sd[1] - sd[2]))); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* --- */ return false; } @@ -3536,14 +3616,14 @@ bool form_factor_visible_quad(const float p[3], const float n[3], } } else { - if (sd[2] > 0) { + if (sd[2] > 0.0f) { /* -0+ */ vec_add_dir(q0, v0, v2, (sd[0] / (sd[0] - sd[2]))); copy_v3_v3(q1, v1); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* -0- */ return false; } @@ -3554,15 +3634,15 @@ bool form_factor_visible_quad(const float p[3], const float n[3], } } else { - if (sd[1] > 0) { - if (sd[2] > 0) { + if (sd[1] > 0.0f) { + if (sd[2] > 0.0f) { /* 0++ */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* 0+- */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); @@ -3577,15 +3657,15 @@ bool form_factor_visible_quad(const float p[3], const float n[3], copy_v3_v3(q3, q2); } } - else if (sd[1] < 0) { - if (sd[2] > 0) { + else if (sd[1] < 0.0f) { + if (sd[2] > 0.0f) { /* 0-+ */ copy_v3_v3(q0, v0); vec_add_dir(q1, v1, v2, (sd[1] / (sd[1] - sd[2]))); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* 0-- */ return false; } @@ -3595,14 +3675,14 @@ bool form_factor_visible_quad(const float p[3], const float n[3], } } else { - if (sd[2] > 0) { + if (sd[2] > 0.0f) { /* 00+ */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* 00- */ return false; } @@ -3757,7 +3837,7 @@ static void ff_normalize(float n[3]) d = dot_v3v3(n, n); - if (d > 1.0e-35F) { + if (d > 1.0e-35f) { d = 1.0f / sqrtf(d); n[0] *= d; diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c index 9af1c8677df..4feb954a31a 100644 --- a/source/blender/blenlib/intern/math_interp.c +++ b/source/blender/blenlib/intern/math_interp.c @@ -62,7 +62,11 @@ static float P(float k) /* older, slower function, works the same as above */ static float P(float k) { - return (float)(1.0f / 6.0f) * (pow(MAX2(k + 2.0f, 0), 3.0f) - 4.0f * pow(MAX2(k + 1.0f, 0), 3.0f) + 6.0f * pow(MAX2(k, 0), 3.0f) - 4.0f * pow(MAX2(k - 1.0f, 0), 3.0f)); + return (float)(1.0f / 6.0f) * + (pow(MAX2(k + 2.0f, 0), 3.0f) - 4.0f * + pow(MAX2(k + 1.0f, 0), 3.0f) + 6.0f * + pow(MAX2(k, 0), 3.0f) - 4.0f * + pow(MAX2(k - 1.0f, 0), 3.0f)); } #endif @@ -366,3 +370,192 @@ void BLI_bilinear_interpolation_char(const unsigned char *buffer, unsigned char { bilinear_interpolation(buffer, NULL, output, NULL, width, height, components, u, v); } + +/************************************************************************** + * Filtering method based on + * "Creating raster omnimax images from multiple perspective views using the elliptical weighted average filter" + * by Ned Greene and Paul S. Heckbert (1986) + ***************************************************************************/ + +/* table of (exp(ar) - exp(a)) / (1 - exp(a)) for r in range [0, 1] and a = -2 + * used instead of actual gaussian, otherwise at high texture magnifications circular artifacts are visible */ +#define EWA_MAXIDX 255 +const float EWA_WTS[EWA_MAXIDX + 1] = { + 1.f, 0.990965f, 0.982f, 0.973105f, 0.96428f, 0.955524f, 0.946836f, 0.938216f, 0.929664f, + 0.921178f, 0.912759f, 0.904405f, 0.896117f, 0.887893f, 0.879734f, 0.871638f, 0.863605f, + 0.855636f, 0.847728f, 0.839883f, 0.832098f, 0.824375f, 0.816712f, 0.809108f, 0.801564f, + 0.794079f, 0.786653f, 0.779284f, 0.771974f, 0.76472f, 0.757523f, 0.750382f, 0.743297f, + 0.736267f, 0.729292f, 0.722372f, 0.715505f, 0.708693f, 0.701933f, 0.695227f, 0.688572f, + 0.68197f, 0.67542f, 0.66892f, 0.662471f, 0.656073f, 0.649725f, 0.643426f, 0.637176f, + 0.630976f, 0.624824f, 0.618719f, 0.612663f, 0.606654f, 0.600691f, 0.594776f, 0.588906f, + 0.583083f, 0.577305f, 0.571572f, 0.565883f, 0.56024f, 0.55464f, 0.549084f, 0.543572f, + 0.538102f, 0.532676f, 0.527291f, 0.521949f, 0.516649f, 0.511389f, 0.506171f, 0.500994f, + 0.495857f, 0.490761f, 0.485704f, 0.480687f, 0.475709f, 0.470769f, 0.465869f, 0.461006f, + 0.456182f, 0.451395f, 0.446646f, 0.441934f, 0.437258f, 0.432619f, 0.428017f, 0.42345f, + 0.418919f, 0.414424f, 0.409963f, 0.405538f, 0.401147f, 0.39679f, 0.392467f, 0.388178f, + 0.383923f, 0.379701f, 0.375511f, 0.371355f, 0.367231f, 0.363139f, 0.359079f, 0.355051f, + 0.351055f, 0.347089f, 0.343155f, 0.339251f, 0.335378f, 0.331535f, 0.327722f, 0.323939f, + 0.320186f, 0.316461f, 0.312766f, 0.3091f, 0.305462f, 0.301853f, 0.298272f, 0.294719f, + 0.291194f, 0.287696f, 0.284226f, 0.280782f, 0.277366f, 0.273976f, 0.270613f, 0.267276f, + 0.263965f, 0.26068f, 0.257421f, 0.254187f, 0.250979f, 0.247795f, 0.244636f, 0.241502f, + 0.238393f, 0.235308f, 0.232246f, 0.229209f, 0.226196f, 0.223206f, 0.220239f, 0.217296f, + 0.214375f, 0.211478f, 0.208603f, 0.20575f, 0.20292f, 0.200112f, 0.197326f, 0.194562f, + 0.191819f, 0.189097f, 0.186397f, 0.183718f, 0.18106f, 0.178423f, 0.175806f, 0.17321f, + 0.170634f, 0.168078f, 0.165542f, 0.163026f, 0.16053f, 0.158053f, 0.155595f, 0.153157f, + 0.150738f, 0.148337f, 0.145955f, 0.143592f, 0.141248f, 0.138921f, 0.136613f, 0.134323f, + 0.132051f, 0.129797f, 0.12756f, 0.125341f, 0.123139f, 0.120954f, 0.118786f, 0.116635f, + 0.114501f, 0.112384f, 0.110283f, 0.108199f, 0.106131f, 0.104079f, 0.102043f, 0.100023f, + 0.0980186f, 0.09603f, 0.094057f, 0.0920994f, 0.0901571f, 0.08823f, 0.0863179f, 0.0844208f, + 0.0825384f, 0.0806708f, 0.0788178f, 0.0769792f, 0.0751551f, 0.0733451f, 0.0715493f, 0.0697676f, + 0.0679997f, 0.0662457f, 0.0645054f, 0.0627786f, 0.0610654f, 0.0593655f, 0.0576789f, 0.0560055f, + 0.0543452f, 0.0526979f, 0.0510634f, 0.0494416f, 0.0478326f, 0.0462361f, 0.0446521f, 0.0430805f, + 0.0415211f, 0.039974f, 0.0384389f, 0.0369158f, 0.0354046f, 0.0339052f, 0.0324175f, 0.0309415f, + 0.029477f, 0.0280239f, 0.0265822f, 0.0251517f, 0.0237324f, 0.0223242f, 0.020927f, 0.0195408f, + 0.0181653f, 0.0168006f, 0.0154466f, 0.0141031f, 0.0127701f, 0.0114476f, 0.0101354f, 0.00883339f, + 0.00754159f, 0.00625989f, 0.00498819f, 0.00372644f, 0.00247454f, 0.00123242f, 0.f +}; + +static void radangle2imp(float a2, float b2, float th, float *A, float *B, float *C, float *F) +{ + float ct2 = cosf(th); + const float st2 = 1.0f - ct2 * ct2; /* <- sin(th)^2 */ + ct2 *= ct2; + *A = a2 * st2 + b2 * ct2; + *B = (b2 - a2) * sinf(2.0f * th); + *C = a2 * ct2 + b2 * st2; + *F = a2 * b2; +} + +/* all tests here are done to make sure possible overflows are hopefully minimized */ +void BLI_ewa_imp2radangle(float A, float B, float C, float F, float *a, float *b, float *th, float *ecc) +{ + if (F <= 1e-5f) { /* use arbitrary major radius, zero minor, infinite eccentricity */ + *a = sqrtf(A > C ? A : C); + *b = 0.0f; + *ecc = 1e10f; + *th = 0.5f * (atan2f(B, A - C) + (float)M_PI); + } + else { + const float AmC = A - C, ApC = A + C, F2 = F * 2.0f; + const float r = sqrtf(AmC * AmC + B * B); + float d = ApC - r; + *a = (d <= 0.0f) ? sqrtf(A > C ? A : C) : sqrtf(F2 / d); + d = ApC + r; + if (d <= 0.0f) { + *b = 0.0f; + *ecc = 1e10f; + } + else { + *b = sqrtf(F2 / d); + *ecc = *a / *b; + } + /* incr theta by 0.5*pi (angle of major axis) */ + *th = 0.5f * (atan2f(B, AmC) + (float)M_PI); + } +} + +void BLI_ewa_filter(const int width, const int height, + const bool intpol, + const bool use_alpha, + const float uv[2], + const float du[2], + const float dv[2], + ewa_filter_read_pixel_cb read_pixel_cb, + void *userdata, + float result[4]) +{ + /* scaling dxt/dyt by full resolution can cause overflow because of huge A/B/C and esp. F values, + * scaling by aspect ratio alone does the opposite, so try something in between instead... */ + const float ff2 = (float)width, ff = sqrtf(ff2), q = (float)height / ff; + const float Ux = du[0] * ff, Vx = dv[0] * q, Uy = du[1] * ff, Vy = dv[1] * q; + float A = Vx * Vx + Vy * Vy; + float B = -2.0f * (Ux * Vx + Uy * Vy); + float C = Ux * Ux + Uy * Uy; + float F = A * C - B * B * 0.25f; + float a, b, th, ecc, a2, b2, ue, ve, U0, V0, DDQ, U, ac1, ac2, BU, d; + int u, v, u1, u2, v1, v2; + + /* The so-called 'high' quality ewa method simply adds a constant of 1 to both A & C, + * so the ellipse always covers at least some texels. But since the filter is now always larger, + * it also means that everywhere else it's also more blurry then ideally should be the case. + * So instead here the ellipse radii are modified instead whenever either is too low. + * Use a different radius based on interpolation switch, just enough to anti-alias when interpolation is off, + * and slightly larger to make result a bit smoother than bilinear interpolation when interpolation is on + * (minimum values: const float rmin = intpol ? 1.f : 0.5f;) */ + const float rmin = (intpol ? 1.5625f : 0.765625f) / ff2; + BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc); + if ((b2 = b * b) < rmin) { + if ((a2 = a * a) < rmin) { + B = 0.0f; + A = C = rmin; + F = A * C; + } + else { + b2 = rmin; + radangle2imp(a2, b2, th, &A, &B, &C, &F); + } + } + + ue = ff * sqrtf(C); + ve = ff * sqrtf(A); + d = (float)(EWA_MAXIDX + 1) / (F * ff2); + A *= d; + B *= d; + C *= d; + + U0 = uv[0] * (float)width; + V0 = uv[1] * (float)height; + u1 = (int)(floorf(U0 - ue)); + u2 = (int)(ceilf(U0 + ue)); + v1 = (int)(floorf(V0 - ve)); + v2 = (int)(ceilf(V0 + ve)); + + /* sane clamping to avoid unnecessarily huge loops */ + /* note: if eccentricity gets clamped (see above), + * the ue/ve limits can also be lowered accordingly + */ + if (U0 - (float)u1 > EWA_MAXIDX) u1 = (int)U0 - EWA_MAXIDX; + if ((float)u2 - U0 > EWA_MAXIDX) u2 = (int)U0 + EWA_MAXIDX; + if (V0 - (float)v1 > EWA_MAXIDX) v1 = (int)V0 - EWA_MAXIDX; + if ((float)v2 - V0 > EWA_MAXIDX) v2 = (int)V0 + EWA_MAXIDX; + + /* Early output check for cases the whole region is outside of the buffer. */ + if ((u2 < 0 || u1 >= width) || (v2 < 0 || v1 >= height)) { + zero_v4(result); + return; + } + + U0 -= 0.5f; + V0 -= 0.5f; + DDQ = 2.0f * A; + U = (float)u1 - U0; + ac1 = A * (2.0f * U + 1.0f); + ac2 = A * U * U; + BU = B * U; + + d = 0.0f; + zero_v4(result); + for (v = v1; v <= v2; ++v) { + const float V = (float)v - V0; + float DQ = ac1 + B * V; + float Q = (C * V + BU) * V + ac2; + for (u = u1; u <= u2; ++u) { + if (Q < (float)(EWA_MAXIDX + 1)) { + float tc[4]; + const float wt = EWA_WTS[(Q < 0.0f) ? 0 : (unsigned int)Q]; + read_pixel_cb(userdata, u, v, tc); + madd_v3_v3fl(result, tc, wt); + result[3] += use_alpha ? tc[3] * wt : 0.0f; + d += wt; + } + Q += DQ; + DQ += DDQ; + } + } + + /* d should hopefully never be zero anymore */ + d = 1.0f / d; + mul_v3_fl(result, d); + /* clipping can be ignored if alpha used, texr->ta already includes filtered edge */ + result[3] = use_alpha ? result[3] * d : 1.0f; +} diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index eb73aba6aa8..228bb1008b1 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -35,42 +35,59 @@ /********************************* Init **************************************/ +void zero_m2(float m[2][2]) +{ + memset(m, 0, sizeof(float[2][2])); +} + void zero_m3(float m[3][3]) { - memset(m, 0, 3 * 3 * sizeof(float)); + memset(m, 0, sizeof(float[3][3])); } void zero_m4(float m[4][4]) { - memset(m, 0, 4 * 4 * sizeof(float)); + memset(m, 0, sizeof(float[4][4])); +} + +void unit_m2(float m[2][2]) +{ + m[0][0] = m[1][1] = 1.0f; + m[0][1] = 0.0f; + m[1][0] = 0.0f; } void unit_m3(float m[3][3]) { - m[0][0] = m[1][1] = m[2][2] = 1.0; - m[0][1] = m[0][2] = 0.0; - m[1][0] = m[1][2] = 0.0; - m[2][0] = m[2][1] = 0.0; + m[0][0] = m[1][1] = m[2][2] = 1.0f; + m[0][1] = m[0][2] = 0.0f; + m[1][0] = m[1][2] = 0.0f; + m[2][0] = m[2][1] = 0.0f; } void unit_m4(float m[4][4]) { - m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0; - m[0][1] = m[0][2] = m[0][3] = 0.0; - m[1][0] = m[1][2] = m[1][3] = 0.0; - m[2][0] = m[2][1] = m[2][3] = 0.0; - m[3][0] = m[3][1] = m[3][2] = 0.0; + m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f; + m[0][1] = m[0][2] = m[0][3] = 0.0f; + m[1][0] = m[1][2] = m[1][3] = 0.0f; + m[2][0] = m[2][1] = m[2][3] = 0.0f; + m[3][0] = m[3][1] = m[3][2] = 0.0f; +} + +void copy_m2_m2(float m1[2][2], float m2[2][2]) +{ + memcpy(m1, m2, sizeof(float[2][2])); } void copy_m3_m3(float m1[3][3], float m2[3][3]) { /* destination comes first: */ - memcpy(&m1[0], &m2[0], 9 * sizeof(float)); + memcpy(m1, m2, sizeof(float[3][3])); } void copy_m4_m4(float m1[4][4], float m2[4][4]) { - memcpy(m1, m2, 4 * 4 * sizeof(float)); + memcpy(m1, m2, sizeof(float[4][4])); } void copy_m3_m4(float m1[3][3], float m2[4][4]) @@ -103,14 +120,14 @@ void copy_m4_m3(float m1[4][4], float m2[3][3]) /* no clear */ m1[2][2] = m2[2][2]; /* Reevan's Bugfix */ - m1[0][3] = 0.0F; - m1[1][3] = 0.0F; - m1[2][3] = 0.0F; + m1[0][3] = 0.0f; + m1[1][3] = 0.0f; + m1[2][3] = 0.0f; - m1[3][0] = 0.0F; - m1[3][1] = 0.0F; - m1[3][2] = 0.0F; - m1[3][3] = 1.0F; + m1[3][0] = 0.0f; + m1[3][1] = 0.0f; + m1[3][2] = 0.0f; + m1[3][3] = 1.0f; } @@ -338,38 +355,147 @@ void mul_serie_m3(float answ[3][3], } } -void mul_serie_m4(float answ[4][4], float m1[4][4], - float m2[4][4], float m3[4][4], float m4[4][4], - float m5[4][4], float m6[4][4], float m7[4][4], - float m8[4][4]) -{ - float temp[4][4]; - - if (m1 == NULL || m2 == NULL) return; - - mul_m4_m4m4(answ, m1, m2); - if (m3) { - mul_m4_m4m4(temp, answ, m3); - if (m4) { - mul_m4_m4m4(answ, temp, m4); - if (m5) { - mul_m4_m4m4(temp, answ, m5); - if (m6) { - mul_m4_m4m4(answ, temp, m6); - if (m7) { - mul_m4_m4m4(temp, answ, m7); - if (m8) { - mul_m4_m4m4(answ, temp, m8); - } - else copy_m4_m4(answ, temp); - } - } - else copy_m4_m4(answ, temp); - } - } - else copy_m4_m4(answ, temp); - } -} +/** \name Macro helpers for: mul_m3_series + * \{ */ +void _va_mul_m3_series_3( + float r[3][3], + float m1[3][3], float m2[3][3]) +{ + mul_m3_m3m3(r, m1, m2); +} +void _va_mul_m3_series_4( + float r[3][3], + float m1[3][3], float m2[3][3], float m3[3][3]) +{ + mul_m3_m3m3(r, m1, m2); + mul_m3_m3m3(r, r, m3); +} +void _va_mul_m3_series_5( + float r[3][3], + float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3]) +{ + mul_m3_m3m3(r, m1, m2); + mul_m3_m3m3(r, r, m3); + mul_m3_m3m3(r, r, m4); +} +void _va_mul_m3_series_6( + float r[3][3], + float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3], + float m5[3][3]) +{ + mul_m3_m3m3(r, m1, m2); + mul_m3_m3m3(r, r, m3); + mul_m3_m3m3(r, r, m4); + mul_m3_m3m3(r, r, m5); +} +void _va_mul_m3_series_7( + float r[3][3], + float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3], + float m5[3][3], float m6[3][3]) +{ + mul_m3_m3m3(r, m1, m2); + mul_m3_m3m3(r, r, m3); + mul_m3_m3m3(r, r, m4); + mul_m3_m3m3(r, r, m5); + mul_m3_m3m3(r, r, m6); +} +void _va_mul_m3_series_8( + float r[3][3], + float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3], + float m5[3][3], float m6[3][3], float m7[3][3]) +{ + mul_m3_m3m3(r, m1, m2); + mul_m3_m3m3(r, r, m3); + mul_m3_m3m3(r, r, m4); + mul_m3_m3m3(r, r, m5); + mul_m3_m3m3(r, r, m6); + mul_m3_m3m3(r, r, m7); +} +void _va_mul_m3_series_9( + float r[3][3], + float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3], + float m5[3][3], float m6[3][3], float m7[3][3], float m8[3][3]) +{ + mul_m3_m3m3(r, m1, m2); + mul_m3_m3m3(r, r, m3); + mul_m3_m3m3(r, r, m4); + mul_m3_m3m3(r, r, m5); + mul_m3_m3m3(r, r, m6); + mul_m3_m3m3(r, r, m7); + mul_m3_m3m3(r, r, m8); +} +/** \} */ + +/** \name Macro helpers for: mul_m4_series + * \{ */ +void _va_mul_m4_series_3( + float r[4][4], + float m1[4][4], float m2[4][4]) +{ + mul_m4_m4m4(r, m1, m2); +} +void _va_mul_m4_series_4( + float r[4][4], + float m1[4][4], float m2[4][4], float m3[4][4]) +{ + mul_m4_m4m4(r, m1, m2); + mul_m4_m4m4(r, r, m3); +} +void _va_mul_m4_series_5( + float r[4][4], + float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4]) +{ + mul_m4_m4m4(r, m1, m2); + mul_m4_m4m4(r, r, m3); + mul_m4_m4m4(r, r, m4); +} +void _va_mul_m4_series_6( + float r[4][4], + float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4], + float m5[4][4]) +{ + mul_m4_m4m4(r, m1, m2); + mul_m4_m4m4(r, r, m3); + mul_m4_m4m4(r, r, m4); + mul_m4_m4m4(r, r, m5); +} +void _va_mul_m4_series_7( + float r[4][4], + float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4], + float m5[4][4], float m6[4][4]) +{ + mul_m4_m4m4(r, m1, m2); + mul_m4_m4m4(r, r, m3); + mul_m4_m4m4(r, r, m4); + mul_m4_m4m4(r, r, m5); + mul_m4_m4m4(r, r, m6); +} +void _va_mul_m4_series_8( + float r[4][4], + float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4], + float m5[4][4], float m6[4][4], float m7[4][4]) +{ + mul_m4_m4m4(r, m1, m2); + mul_m4_m4m4(r, r, m3); + mul_m4_m4m4(r, r, m4); + mul_m4_m4m4(r, r, m5); + mul_m4_m4m4(r, r, m6); + mul_m4_m4m4(r, r, m7); +} +void _va_mul_m4_series_9( + float r[4][4], + float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4], + float m5[4][4], float m6[4][4], float m7[4][4], float m8[4][4]) +{ + mul_m4_m4m4(r, m1, m2); + mul_m4_m4m4(r, r, m3); + mul_m4_m4m4(r, r, m4); + mul_m4_m4m4(r, r, m5); + mul_m4_m4m4(r, r, m6); + mul_m4_m4m4(r, r, m7); + mul_m4_m4m4(r, r, m8); +} +/** \} */ void mul_v2_m3v2(float r[2], float m[3][3], float v[2]) { @@ -391,10 +517,9 @@ void mul_m3_v2(float m[3][3], float r[2]) void mul_m4_v3(float mat[4][4], float vec[3]) { - float x, y; + const float x = vec[0]; + const float y = vec[1]; - x = vec[0]; - y = vec[1]; vec[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2] + mat[3][0]; vec[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2] + mat[3][1]; vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2]; @@ -402,10 +527,9 @@ void mul_m4_v3(float mat[4][4], float vec[3]) void mul_v3_m4v3(float r[3], float mat[4][4], const float vec[3]) { - float x, y; + const float x = vec[0]; + const float y = vec[1]; - x = vec[0]; - y = vec[1]; r[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2] + mat[3][0]; r[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2] + mat[3][1]; r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2]; @@ -413,18 +537,16 @@ void mul_v3_m4v3(float r[3], float mat[4][4], const float vec[3]) void mul_v2_m4v3(float r[2], float mat[4][4], const float vec[3]) { - float x; + const float x = vec[0]; - x = vec[0]; r[0] = x * mat[0][0] + vec[1] * mat[1][0] + mat[2][0] * vec[2] + mat[3][0]; r[1] = x * mat[0][1] + vec[1] * mat[1][1] + mat[2][1] * vec[2] + mat[3][1]; } void mul_v2_m2v2(float r[2], float mat[2][2], const float vec[2]) { - float x; + const float x = vec[0]; - x = vec[0]; r[0] = mat[0][0] * x + mat[1][0] * vec[1]; r[1] = mat[0][1] * x + mat[1][1] * vec[1]; } @@ -453,10 +575,9 @@ void mul_v3_m4v3_q(float out[3], float mat[][4], const float vec[3]) /* same as mul_m4_v3() but doesnt apply translation component */ void mul_mat3_m4_v3(float mat[4][4], float vec[3]) { - float x, y; + const float x = vec[0]; + const float y = vec[1]; - x = vec[0]; - y = vec[1]; vec[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2]; vec[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2]; vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2]; @@ -483,11 +604,9 @@ void mul_v2_project_m4_v3(float r[2], float mat[4][4], const float vec[3]) void mul_v4_m4v4(float r[4], float mat[4][4], const float v[4]) { - float x, y, z; - - x = v[0]; - y = v[1]; - z = v[2]; + const float x = v[0]; + const float y = v[1]; + const float z = v[2]; r[0] = x * mat[0][0] + y * mat[1][0] + z * mat[2][0] + mat[3][0] * v[3]; r[1] = x * mat[0][1] + y * mat[1][1] + z * mat[2][1] + mat[3][1] * v[3]; @@ -502,11 +621,9 @@ void mul_m4_v4(float mat[4][4], float r[4]) void mul_v4d_m4v4d(double r[4], float mat[4][4], double v[4]) { - double x, y, z; - - x = v[0]; - y = v[1]; - z = v[2]; + const double x = v[0]; + const double y = v[1]; + const double z = v[2]; r[0] = x * (double)mat[0][0] + y * (double)mat[1][0] + z * (double)mat[2][0] + (double)mat[3][0] * v[3]; r[1] = x * (double)mat[0][1] + y * (double)mat[1][1] + z * (double)mat[2][1] + (double)mat[3][1] * v[3]; @@ -546,10 +663,9 @@ void mul_m3_v3(float M[3][3], float r[3]) void mul_transposed_m3_v3(float mat[3][3], float vec[3]) { - float x, y; + const float x = vec[0]; + const float y = vec[1]; - x = vec[0]; - y = vec[1]; vec[0] = x * mat[0][0] + y * mat[0][1] + mat[0][2] * vec[2]; vec[1] = x * mat[1][0] + y * mat[1][1] + mat[1][2] * vec[2]; vec[2] = x * mat[2][0] + y * mat[2][1] + mat[2][2] * vec[2]; @@ -557,10 +673,9 @@ void mul_transposed_m3_v3(float mat[3][3], float vec[3]) void mul_transposed_mat3_m4_v3(float mat[4][4], float vec[3]) { - float x, y; + const float x = vec[0]; + const float y = vec[1]; - x = vec[0]; - y = vec[1]; vec[0] = x * mat[0][0] + y * mat[0][1] + mat[0][2] * vec[2]; vec[1] = x * mat[1][0] + y * mat[1][1] + mat[1][2] * vec[2]; vec[2] = x * mat[2][0] + y * mat[2][1] + mat[2][2] * vec[2]; @@ -613,10 +728,9 @@ void negate_m4(float m[4][4]) void mul_m3_v3_double(float mat[3][3], double vec[3]) { - double x, y; + const double x = vec[0]; + const double y = vec[1]; - x = vec[0]; - y = vec[1]; vec[0] = x * (double)mat[0][0] + y * (double)mat[1][0] + (double)mat[2][0] * vec[2]; vec[1] = x * (double)mat[0][1] + y * (double)mat[1][1] + (double)mat[2][1] * vec[2]; vec[2] = x * (double)mat[0][2] + y * (double)mat[1][2] + (double)mat[2][2] * vec[2]; @@ -668,11 +782,9 @@ float determinant_m3_array(float m[3][3]) bool invert_m3_ex(float m[3][3], const float epsilon) { float tmp[3][3]; - bool success; + const bool success = invert_m3_m3_ex(tmp, m, epsilon); - success = invert_m3_m3_ex(tmp, m, epsilon); copy_m3_m3(m, tmp); - return success; } @@ -706,11 +818,9 @@ bool invert_m3_m3_ex(float m1[3][3], float m2[3][3], const float epsilon) bool invert_m3(float m[3][3]) { float tmp[3][3]; - bool success; + const bool success = invert_m3_m3(tmp, m); - success = invert_m3_m3(tmp, m); copy_m3_m3(m, tmp); - return success; } @@ -743,11 +853,9 @@ bool invert_m3_m3(float m1[3][3], float m2[3][3]) bool invert_m4(float m[4][4]) { float tmp[4][4]; - bool success; + const bool success = invert_m4_m4(tmp, m); - success = invert_m4_m4(tmp, m); copy_m4_m4(m, tmp); - return success; } @@ -1348,7 +1456,7 @@ float mat3_to_scale(float mat[3][3]) { /* unit length vector */ float unit_vec[3]; - copy_v3_fl(unit_vec, 0.577350269189626f); + copy_v3_fl(unit_vec, (float)(1.0 / M_SQRT3)); mul_m3_v3(mat, unit_vec); return len_v3(unit_vec); } @@ -1357,7 +1465,7 @@ float mat4_to_scale(float mat[4][4]) { /* unit length vector */ float unit_vec[3]; - copy_v3_fl(unit_vec, 0.577350269189626f); + copy_v3_fl(unit_vec, (float)(1.0 / M_SQRT3)); mul_mat3_m4_v3(mat, unit_vec); return len_v3(unit_vec); } @@ -2224,7 +2332,7 @@ void pseudoinverse_m4_m4(float Ainv[4][4], float A[4][4], float epsilon) transpose_m4(V); - mul_serie_m4(Ainv, U, Wm, V, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(Ainv, U, Wm, V); } void mat4_ortho_set(float m[][4], float left, float right, float bottom, float top, float nearVal, float farVal) @@ -2300,3 +2408,51 @@ void invert_m4_m4_safe(float Ainv[4][4], float A[4][4]) } } } + +/** + * SpaceTransform struct encapsulates all needed data to convert between two coordinate spaces + * (where conversion can be represented by a matrix multiplication). + * + * A SpaceTransform is initialized using: + * BLI_SPACE_TRANSFORM_SETUP(&data, ob1, ob2) + * + * After that the following calls can be used: + * BLI_space_transform_apply(&data, co); // converts a coordinate in ob1 space to the corresponding ob2 space + * BLI_space_transform_invert(&data, co); // converts a coordinate in ob2 space to the corresponding ob1 space + * + * Same concept as BLI_space_transform_apply and BLI_space_transform_invert, but no is normalized after conversion + * (and not translated at all!): + * BLI_space_transform_apply_normal(&data, no); + * BLI_space_transform_invert_normal(&data, no); + * + */ + +void BLI_space_transform_from_matrices(SpaceTransform *data, float local[4][4], float target[4][4]) +{ + float itarget[4][4]; + invert_m4_m4(itarget, target); + mul_m4_m4m4(data->local2target, itarget, local); + invert_m4_m4(data->target2local, data->local2target); +} + +void BLI_space_transform_apply(const SpaceTransform *data, float co[3]) +{ + mul_v3_m4v3(co, ((SpaceTransform *)data)->local2target, co); +} + +void BLI_space_transform_invert(const SpaceTransform *data, float co[3]) +{ + mul_v3_m4v3(co, ((SpaceTransform *)data)->target2local, co); +} + +void BLI_space_transform_apply_normal(const SpaceTransform *data, float no[3]) +{ + mul_mat3_m4_v3(((SpaceTransform *)data)->local2target, no); + normalize_v3(no); +} + +void BLI_space_transform_invert_normal(const SpaceTransform *data, float no[3]) +{ + mul_mat3_m4_v3(((SpaceTransform *)data)->target2local, no); + normalize_v3(no); +} diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index dce2e9d54e3..141f9201689 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -139,7 +139,7 @@ float dot_qtqt(const float q1[4], const float q2[4]) void invert_qt(float q[4]) { - float f = dot_qtqt(q, q); + const float f = dot_qtqt(q, q); if (f == 0.0f) return; @@ -380,9 +380,8 @@ void mat3_to_quat_is_ok(float q[4], float wmat[3][3]) float normalize_qt(float q[4]) { - float len; + const float len = sqrtf(dot_qtqt(q, q)); - len = sqrtf(dot_qtqt(q, q)); if (len != 0.0f) { mul_qt_fl(q, 1.0f / len); } @@ -520,7 +519,7 @@ float angle_qtqt(const float q1[4], const float q2[4]) void vec_to_quat(float q[4], const float vec[3], short axis, const short upflag) { - const float eps = 0.0001f; + const float eps = 1e-4f; float nor[3], tvec[3]; float angle, si, co, len; @@ -669,7 +668,7 @@ void QuatInterpolW(float *result, float quat1[4], float quat2[4], float t) */ void interp_dot_slerp(const float t, const float cosom, float r_w[2]) { - const float eps = 0.0001f; + const float eps = 1e-4f; BLI_assert(IN_RANGE_INCL(cosom, -1.0001f, 1.0001f)); @@ -783,9 +782,8 @@ void tri_to_quat_ex(float quat[4], const float v1[3], const float v2[3], const f float tri_to_quat(float quat[4], const float v1[3], const float v2[3], const float v3[3]) { float vec[3]; - float len; + const float len = normal_tri_v3(vec, v1, v2, v3); - len = normal_tri_v3(vec, v1, v2, v3); tri_to_quat_ex(quat, v1, v2, v3, vec); return len; } @@ -1606,7 +1604,7 @@ void mat4_to_dquat(DualQuat *dq, float basemat[4][4], float mat[4][4]) mul_m4_m4m4(S, baseRinv, baseRS); /* set scaling part */ - mul_serie_m4(dq->scale, basemat, S, baseinv, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(dq->scale, basemat, S, baseinv); dq->scale_weight = 1.0f; } else { @@ -1658,7 +1656,7 @@ void add_weighted_dq_dq(DualQuat *dqsum, const DualQuat *dq, float weight) /* make sure we interpolate quats in the right direction */ if (dot_qtqt(dq->quat, dqsum->quat) < 0) { - flipped = 1; + flipped = true; weight = -weight; } @@ -1689,7 +1687,7 @@ void add_weighted_dq_dq(DualQuat *dqsum, const DualQuat *dq, float weight) void normalize_dq(DualQuat *dq, float totweight) { - float scale = 1.0f / totweight; + const float scale = 1.0f / totweight; mul_qt_fl(dq->quat, scale); mul_qt_fl(dq->trans, scale); diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index 38cbb39f36d..c904b963e54 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -35,7 +35,7 @@ void interp_v2_v2v2(float target[2], const float a[2], const float b[2], const float t) { - float s = 1.0f - t; + const float s = 1.0f - t; target[0] = s * a[0] + t * b[0]; target[1] = s * a[1] + t * b[1]; @@ -51,7 +51,7 @@ void interp_v2_v2v2v2(float p[2], const float v1[2], const float v2[2], const fl void interp_v3_v3v3(float target[3], const float a[3], const float b[3], const float t) { - float s = 1.0f - t; + const float s = 1.0f - t; target[0] = s * a[0] + t * b[0]; target[1] = s * a[1] + t * b[1]; @@ -60,7 +60,7 @@ void interp_v3_v3v3(float target[3], const float a[3], const float b[3], const f void interp_v4_v4v4(float target[4], const float a[4], const float b[4], const float t) { - float s = 1.0f - t; + const float s = 1.0f - t; target[0] = s * a[0] + t * b[0]; target[1] = s * a[1] + t * b[1]; @@ -119,8 +119,7 @@ bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], c } /** - * Same as #interp_v3_v3v3_slerp buy uses fallback values - * for opposite vectors. + * Same as #interp_v3_v3v3_slerp but uses fallback values for opposite vectors. */ void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t) { @@ -208,7 +207,7 @@ void interp_v3_v3v3v3_uv(float p[3], const float v1[3], const float v2[3], const void interp_v3_v3v3_uchar(char unsigned target[3], const unsigned char a[3], const unsigned char b[3], const float t) { - float s = 1.0f - t; + const float s = 1.0f - t; target[0] = (char)floorf(s * a[0] + t * b[0]); target[1] = (char)floorf(s * a[1] + t * b[1]); @@ -221,7 +220,7 @@ void interp_v3_v3v3_char(char target[3], const char a[3], const char b[3], const void interp_v4_v4v4_uchar(char unsigned target[4], const unsigned char a[4], const unsigned char b[4], const float t) { - float s = 1.0f - t; + const float s = 1.0f - t; target[0] = (char)floorf(s * a[0] + t * b[0]); target[1] = (char)floorf(s * a[1] + t * b[1]); @@ -550,8 +549,7 @@ void angle_poly_v3(float *angles, const float *verts[3], int len) /* Project v1 on v2 */ void project_v2_v2v2(float c[2], const float v1[2], const float v2[2]) { - float mul; - mul = dot_v2v2(v1, v2) / dot_v2v2(v2, v2); + const float mul = dot_v2v2(v1, v2) / dot_v2v2(v2, v2); c[0] = mul * v2[0]; c[1] = mul * v2[1]; @@ -560,8 +558,7 @@ void project_v2_v2v2(float c[2], const float v1[2], const float v2[2]) /* Project v1 on v2 */ void project_v3_v3v3(float c[3], const float v1[3], const float v2[3]) { - float mul; - mul = dot_v3v3(v1, v2) / dot_v3v3(v2, v2); + const float mul = dot_v3v3(v1, v2) / dot_v3v3(v2, v2); c[0] = mul * v2[0]; c[1] = mul * v2[1]; @@ -837,7 +834,7 @@ double len_squared_vn(const float *array, const int size) float normalize_vn_vn(float *array_tar, const float *array_src, const int size) { - double d = len_squared_vn(array_src, size); + const double d = len_squared_vn(array_src, size); float d_sqrt; if (d > 1.0e-35) { d_sqrt = (float)sqrt(d); diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index 2639767fcb1..3ed4a561698 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -479,7 +479,7 @@ MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3]) } /** - * Has the effect of mul_m3_v3(), on a single axis. + * Has the effect of #mul_m3_v3(), on a single axis. */ MINLINE float dot_m3_v3_row_x(float M[3][3], const float a[3]) { @@ -495,7 +495,8 @@ MINLINE float dot_m3_v3_row_z(float M[3][3], const float a[3]) } /** - * Almost like mul_m4_v3(), misses adding translation. + * Has the effect of #mul_mat3_m4_v3(), on a single axis. + * (no adding translation) */ MINLINE float dot_m4_v3_row_x(float M[4][4], const float a[3]) { @@ -863,17 +864,17 @@ MINLINE void normal_float_to_short_v3(short out[3], const float in[3]) MINLINE bool is_zero_v2(const float v[2]) { - return (v[0] == 0 && v[1] == 0); + return (v[0] == 0.0f && v[1] == 0.0f); } MINLINE bool is_zero_v3(const float v[3]) { - return (v[0] == 0 && v[1] == 0 && v[2] == 0); + return (v[0] == 0.0f && v[1] == 0.0f && v[2] == 0.0f); } MINLINE bool is_zero_v4(const float v[4]) { - return (v[0] == 0 && v[1] == 0 && v[2] == 0 && v[3] == 0); + return (v[0] == 0.0f && v[1] == 0.0f && v[2] == 0.0f && v[3] == 0.0f); } MINLINE bool is_finite_v2(const float v[2]) @@ -893,9 +894,15 @@ MINLINE bool is_finite_v4(const float v[4]) MINLINE bool is_one_v3(const float v[3]) { - return (v[0] == 1 && v[1] == 1 && v[2] == 1); + return (v[0] == 1.0f && v[1] == 1.0f && v[2] == 1.0f); } + +/** \name Vector Comparison + * + * \note use ``value <= limit``, so a limit of zero doesn't fail on an exact match. + * \{ */ + MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) { return ((v1[0] == v2[0]) && (v1[1] == v2[1])); @@ -913,8 +920,8 @@ MINLINE bool equals_v4v4(const float v1[4], const float v2[4]) 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) + if (fabsf(v1[0] - v2[0]) <= limit) + if (fabsf(v1[1] - v2[1]) <= limit) return true; return false; @@ -922,9 +929,9 @@ MINLINE bool compare_v2v2(const float v1[2], const float v2[2], const float limi 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) + if (fabsf(v1[0] - v2[0]) <= limit) + if (fabsf(v1[1] - v2[1]) <= limit) + if (fabsf(v1[2] - v2[2]) <= limit) return true; return false; @@ -938,15 +945,26 @@ MINLINE bool compare_len_v3v3(const float v1[3], const float v2[3], const float y = v1[1] - v2[1]; z = v1[2] - v2[2]; - return ((x * x + y * y + z * z) < (limit * limit)); + return ((x * x + y * y + z * z) <= (limit * limit)); +} + +MINLINE bool compare_len_squared_v3v3(const float v1[3], const float v2[3], const float limit_sq) +{ + float x, y, z; + + x = v1[0] - v2[0]; + y = v1[1] - v2[1]; + z = v1[2] - v2[2]; + + return ((x * x + y * y + z * z) <= limit_sq); } 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) + 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 true; return false; @@ -958,4 +976,6 @@ MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const flo ((l2[0] - pt[0]) * (l1[1] - pt[1]))); } +/** \} */ + #endif /* __MATH_VECTOR_INLINE_C__ */ diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 0b89ec1f0d0..a7fa443cfc4 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -1175,7 +1175,13 @@ static bool get_path_local(char *targetpath, const char *folder_name, const char } /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */ +#ifdef __APPLE__ + static char osx_resourses[FILE_MAX]; /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */ + sprintf(osx_resourses, "%s../Resources", bprogdir); + return test_path(targetpath, osx_resourses, blender_version_decimal(ver), relfolder); +#else return test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder); +#endif } /** @@ -1415,7 +1421,7 @@ const char *BLI_get_folder_create(int folder_id, const char *subfolder) const char *path; /* only for user folders */ - if (!ELEM4(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE)) + if (!ELEM(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE)) return NULL; path = BLI_get_folder(folder_id, subfolder); @@ -1515,21 +1521,6 @@ void BLI_setenv_if_new(const char *env, const char *val) BLI_setenv(env, val); } - -/** - * Changes to the path separators to the native ones for this OS. - */ -void BLI_clean(char *path) -{ -#ifdef WIN32 - if (path && BLI_strnlen(path, 3) > 2) { - BLI_char_switch(path + 2, '/', '\\'); - } -#else - BLI_char_switch(path + BLI_path_unc_prefix_len(path), '\\', '/'); -#endif -} - /** * Change every \a from in \a string into \a to. The * result will be in \a string @@ -1681,7 +1672,7 @@ void BLI_make_file_string(const char *relabase, char *string, const char *dir, c strcat(string, file); /* Push all slashes to the system preferred direction */ - BLI_clean(string); + BLI_path_native_slash(string); } static bool testextensie_ex(const char *str, const size_t str_len, @@ -1783,7 +1774,7 @@ bool BLI_replace_extension(char *path, size_t maxlen, const char *ext) ssize_t a; for (a = path_len - 1; a >= 0; a--) { - if (ELEM3(path[a], '.', '/', '\\')) { + if (ELEM(path[a], '.', '/', '\\')) { break; } } @@ -2146,6 +2137,20 @@ void BLI_del_slash(char *string) } /** + * Changes to the path separators to the native ones for this OS. + */ +void BLI_path_native_slash(char *path) +{ +#ifdef WIN32 + if (path && BLI_strnlen(path, 3) > 2) { + BLI_char_switch(path + 2, '/', '\\'); + } +#else + BLI_char_switch(path + BLI_path_unc_prefix_len(path), '\\', '/'); +#endif +} + +/** * Tries appending each of the semicolon-separated extensions in the PATHEXT * environment variable (Windows-only) onto *name in turn until such a file is found. * Returns success/failure. diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c index 71cda92842a..dd829e5d80a 100644 --- a/source/blender/blenlib/intern/polyfill2d.c +++ b/source/blender/blenlib/intern/polyfill2d.c @@ -387,7 +387,7 @@ static bool kdtree2d_isect_tri_recursive( (span_tri_v2_sign(tri_coords[1], tri_coords[2], co) != CONCAVE) && (span_tri_v2_sign(tri_coords[2], tri_coords[0], co) != CONCAVE)) { - if (!ELEM3(node->index, tri_index[0], tri_index[1], tri_index[2])) { + if (!ELEM(node->index, tri_index[0], tri_index[1], tri_index[2])) { return true; } } diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c index 410f98897ce..3dff0b31091 100644 --- a/source/blender/blenlib/intern/rand.c +++ b/source/blender/blenlib/intern/rand.c @@ -95,15 +95,20 @@ void BLI_rng_srandom(RNG *rng, unsigned int seed) BLI_rng_seed(rng, seed + hash[seed & 255]); } -int BLI_rng_get_int(RNG *rng) +BLI_INLINE void rng_step(RNG *rng) { rng->X = (MULTIPLIER * rng->X + ADDEND) & MASK; +} + +int BLI_rng_get_int(RNG *rng) +{ + rng_step(rng); return (int) (rng->X >> 17); } unsigned int BLI_rng_get_uint(RNG *rng) { - rng->X = (MULTIPLIER * rng->X + ADDEND) & MASK; + rng_step(rng); return (unsigned int) (rng->X >> 17); } @@ -167,10 +172,9 @@ void BLI_rng_shuffle_array(RNG *rng, void *data, unsigned int elem_size_i, unsig void BLI_rng_skip(RNG *rng, int n) { - int i; - - for (i = 0; i < n; i++) - BLI_rng_get_int(rng); + while (n--) { + rng_step(rng); + } } /***/ diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c index 05e4984d9a3..cf0d8cff870 100644 --- a/source/blender/blenlib/intern/scanfill.c +++ b/source/blender/blenlib/intern/scanfill.c @@ -865,6 +865,9 @@ unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const /* Newell's Method */ /* Similar code used elsewhere, but this checks for double ups * which historically this function supports so better not change */ + + /* warning: this only gives stable direction with single polygons, + * ideally we'd calculate connectivity and each polys normal, see T41047 */ const float *v_prev; zero_v3(n); diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c index d6b2383bd47..0cf9f69b9ae 100644 --- a/source/blender/blenlib/intern/smallhash.c +++ b/source/blender/blenlib/intern/smallhash.c @@ -44,8 +44,6 @@ * * Note that the values and keys are often pointers or index values, * use the maximum values to avoid real pointers colliding with magic numbers. - * - * \note these have the SMHASH prefix because we may want to make them public. */ #include <string.h> @@ -86,6 +84,11 @@ BLI_INLINE bool smallhash_val_is_used(const void *val) extern const unsigned int hashsizes[]; +BLI_INLINE unsigned int smallhash_key(const uintptr_t key) +{ + return (unsigned int)key; +} + /** * Check if the number of items in the smallhash is large enough to require more buckets. */ @@ -118,7 +121,7 @@ BLI_INLINE void smallhash_buckets_reserve(SmallHash *sh, const unsigned int nent BLI_INLINE SmallHashEntry *smallhash_lookup(SmallHash *sh, const uintptr_t key) { SmallHashEntry *e; - unsigned int h = (unsigned int)key; + unsigned int h = smallhash_key(key); unsigned int hoff = 1; BLI_assert(key != SMHASH_KEY_UNUSED); @@ -142,7 +145,7 @@ BLI_INLINE SmallHashEntry *smallhash_lookup(SmallHash *sh, const uintptr_t key) BLI_INLINE SmallHashEntry *smallhash_lookup_first_free(SmallHash *sh, const uintptr_t key) { SmallHashEntry *e; - unsigned int h = (unsigned int)key; + unsigned int h = smallhash_key(key); unsigned int hoff = 1; for (e = &sh->buckets[h % sh->nbuckets]; @@ -312,6 +315,9 @@ void *BLI_smallhash_iternew(SmallHash *sh, SmallHashIter *iter, uintptr_t *key) return BLI_smallhash_iternext(iter, key); } +/** \name Debugging & Introspection + * \{ */ + /* note, this was called _print_smhash in knifetool.c * it may not be intended for general use - campbell */ #if 0 @@ -345,3 +351,41 @@ void BLI_smallhash_print(SmallHash *sh) fflush(stdout); } #endif + +#ifdef DEBUG +/** + * Measure how well the hash function performs + * (1.0 is perfect - no stepping needed). + * + * Smaller is better! + */ +double BLI_smallhash_calc_quality(SmallHash *sh) +{ + uint64_t sum = 0; + unsigned int i; + + if (sh->nentries == 0) + return -1.0; + + for (i = 0; i < sh->nbuckets; i++) { + if (sh->buckets[i].key != SMHASH_KEY_UNUSED) { + uint64_t count = 0; + SmallHashEntry *e, *e_final = &sh->buckets[i]; + unsigned int h = smallhash_key(e_final->key); + unsigned int hoff = 1; + + for (e = &sh->buckets[h % sh->nbuckets]; + e != e_final; + h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) + { + count += 1; + } + + sum += count; + } + } + return ((double)(sh->nentries + sum) / (double)sh->nentries); +} +#endif + +/** \} */ diff --git a/source/blender/blenlib/intern/stack.c b/source/blender/blenlib/intern/stack.c index c2ee73d9693..58029120de9 100644 --- a/source/blender/blenlib/intern/stack.c +++ b/source/blender/blenlib/intern/stack.c @@ -35,7 +35,7 @@ #include "BLI_strict_flags.h" -// #define USE_TOTELEM +#define USE_TOTELEM #define CHUNK_EMPTY ((size_t)-1) /* target chunks size: 64kb */ @@ -135,7 +135,7 @@ void BLI_stack_free(BLI_Stack *stack) * Copies the source value onto the stack (note that it copies * elem_size bytes from 'src', the pointer itself is not stored) */ -void BLI_stack_push(BLI_Stack *stack, const void *src) +void *BLI_stack_push_r(BLI_Stack *stack) { stack->chunk_index++; @@ -161,8 +161,14 @@ void BLI_stack_push(BLI_Stack *stack, const void *src) stack->totelem++; #endif - /* Copy source to end of stack */ - memcpy(CHUNK_LAST_ELEM(stack), src, stack->elem_size); + /* Return end of stack */ + return CHUNK_LAST_ELEM(stack); +} + +void BLI_stack_push(BLI_Stack *stack, const void *src) +{ + void *dst = BLI_stack_push_r(stack); + memcpy(dst, src, stack->elem_size); } /** @@ -175,29 +181,62 @@ void BLI_stack_pop(BLI_Stack *stack, void *dst) { BLI_assert(BLI_stack_is_empty(stack) == false); - if (!BLI_stack_is_empty(stack)) { - memcpy(dst, CHUNK_LAST_ELEM(stack), stack->elem_size); + memcpy(dst, CHUNK_LAST_ELEM(stack), stack->elem_size); #ifdef USE_TOTELEM - stack->totelem--; + stack->totelem--; #endif - if (--stack->chunk_index == CHUNK_EMPTY) { - struct StackChunk *chunk_free; + if (UNLIKELY(--stack->chunk_index == CHUNK_EMPTY)) { + struct StackChunk *chunk_free; - chunk_free = stack->chunk_curr; - stack->chunk_curr = stack->chunk_curr->next; + chunk_free = stack->chunk_curr; + stack->chunk_curr = stack->chunk_curr->next; - chunk_free->next = stack->chunk_free; - stack->chunk_free = chunk_free; + chunk_free->next = stack->chunk_free; + stack->chunk_free = chunk_free; - stack->chunk_index = stack->chunk_elem_max - 1; - } + stack->chunk_index = stack->chunk_elem_max - 1; + } +} + +void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n) +{ + BLI_assert(n <= BLI_stack_count(stack)); + + while (n--) { + BLI_stack_pop(stack, dst); + dst = (void *)((char *)dst + stack->elem_size); } } +size_t BLI_stack_count(const BLI_Stack *stack) +{ +#ifdef USE_TOTELEM + return stack->totelem; +#else + struct StackChunk *data = stack->chunk_curr; + size_t totelem = stack->chunk_index + 1; + size_t i; + if (totelem != stack->chunk_elem_max) { + data = data->next; + } + else { + totelem = 0; + } + for (i = 0; data; data = data->next) { + i++; + } + totelem += stack->chunk_elem_max * i; + return totelem; +#endif +} + /** * Returns true if the stack is empty, false otherwise */ bool BLI_stack_is_empty(const BLI_Stack *stack) { +#ifdef USE_TOTELEM + BLI_assert((stack->chunk_curr == NULL) == (stack->totelem == 0)); +#endif return (stack->chunk_curr == NULL); } diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index 453b0cc939f..f3ecc799e1e 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -515,7 +515,7 @@ int BLI_stat(const char *path, BLI_stat_t *buffer) int BLI_wstat(const wchar_t *path, BLI_stat_t *buffer) { -#if (defined(_MSC_VER) && (_MSC_VER >= 1500)) || defined(__MINGW64__) +#if defined(_MSC_VER) || defined(__MINGW64__) return _wstat64(path, buffer); #elif defined(__MINGW32__) return _wstati64(path, buffer); diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index f396abbeb8d..eeafc1a9e8f 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -648,7 +648,7 @@ int BLI_str_rstrip_float_zero(char *str, const char pad) * \param str_array_len The length of the array, or -1 for a NULL-terminated array. * \return The index of str in str_array or -1. */ -int BLI_str_index_in_array_n(const char *str, const char **str_array, const int str_array_len) +int BLI_str_index_in_array_n(const char *__restrict str, const char **__restrict str_array, const int str_array_len) { int index; const char **str_iter = str_array; @@ -668,7 +668,7 @@ int BLI_str_index_in_array_n(const char *str, const char **str_array, const int * \param str_array Array of strings, (must be NULL-terminated). * \return The index of str in str_array or -1. */ -int BLI_str_index_in_array(const char *str, const char **str_array) +int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array) { int index; const char **str_iter = str_array; @@ -741,3 +741,38 @@ size_t BLI_str_partition_ex(const char *str, const char delim[], char **sep, cha return strlen(str); } + +/** + * Format ints with decimal grouping. + * 1000 -> 1,000 + * + * \param dst The resulting string + * \param num Number to format + * \return The length of \a dst + */ +size_t BLI_str_format_int_grouped(char dst[16], int num) +{ + char src[16]; + char *p_src = src; + char *p_dst = dst; + + const char separator = ','; + int num_len, commas; + + num_len = sprintf(src, "%d", num); + + if (*p_src == '-') { + *p_dst++ = *p_src++; + num_len--; + } + + for (commas = 2 - num_len % 3; *p_src; commas = (commas + 1) % 3) { + *p_dst++ = *p_src++; + if (commas == 1) { + *p_dst++ = separator; + } + } + *--p_dst = '\0'; + + return (size_t)(p_dst - dst); +} diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c index 65ded37eb7b..a67e116969e 100644 --- a/source/blender/blenlib/intern/winstuff.c +++ b/source/blender/blenlib/intern/winstuff.c @@ -92,6 +92,7 @@ void RegisterBlendExtension(void) const char *ThumbHandlerDLL; char RegCmd[MAX_PATH * 2]; char MBox[256]; + char *blender_app; #ifndef WIN64 BOOL IsWOW64; #endif @@ -99,6 +100,12 @@ void RegisterBlendExtension(void) printf("Registering file extension..."); GetModuleFileName(0, BlPath, MAX_PATH); + /* Replace the actual app name with the wrapper. */ + blender_app = strstr(BlPath, "blender-app.exe"); + if (blender_app != NULL) { + strcpy(blender_app, "blender.exe"); + } + /* root is HKLM by default */ lresult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Classes", 0, KEY_ALL_ACCESS, &root); if (lresult != ERROR_SUCCESS) { diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 4fb983c119b..4b7b9cecb17 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -275,7 +275,8 @@ void BLO_main_expander(void (*expand_doit_func)(void *, struct Main *, void *)); */ void BLO_expand_main(void *fdhandle, struct Main *mainvar); -/* Update defaults in startup.blend, without having to save and embed it */ +/* Update defaults in startup.blend & userprefs.blend, without having to save and embed it */ +void BLO_update_defaults_userpref_blend(void); void BLO_update_defaults_startup_blend(struct Main *mainvar); #ifdef __cplusplus diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 91753158d02..b2e49be1a5e 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -434,8 +434,7 @@ void blo_join_main(ListBase *mainlist) while ((tojoin = mainl->next)) { add_main_to_main(mainl, tojoin); BLI_remlink(mainlist, tojoin); - MEM_freeN(tojoin->eval_ctx); - MEM_freeN(tojoin); + BKE_main_free(tojoin); } } @@ -1824,6 +1823,7 @@ static void lib_link_brush(FileData *fd, Main *main) brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex); brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex); brush->clone.image = newlibadr_us(fd, brush->id.lib, brush->clone.image); + brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve); } } } @@ -1834,6 +1834,8 @@ static void direct_link_brush(FileData *fd, Brush *brush) /* fallof curve */ brush->curve = newdataadr(fd, brush->curve); + brush->gradient = newdataadr(fd, brush->gradient); + if (brush->curve) direct_link_curvemapping(fd, brush->curve); else @@ -1843,6 +1845,43 @@ static void direct_link_brush(FileData *fd, Brush *brush) brush->icon_imbuf = NULL; } +/* ************ READ Palette *************** */ +static void lib_link_palette(FileData *UNUSED(fd), Main *main) +{ + Palette *palette; + + /* only link ID pointers */ + for (palette = main->palettes.first; palette; palette = palette->id.next) { + if (palette->id.flag & LIB_NEED_LINK) { + palette->id.flag -= LIB_NEED_LINK; + } + } +} + +static void direct_link_palette(FileData *fd, Palette *palette) +{ + /* palette itself has been read */ + link_list(fd, &palette->colors); +} + +static void lib_link_paint_curve(FileData *UNUSED(fd), Main *main) +{ + PaintCurve *pc; + + /* only link ID pointers */ + for (pc = main->paintcurves.first; pc; pc = pc->id.next) { + if (pc->id.flag & LIB_NEED_LINK) { + pc->id.flag -= LIB_NEED_LINK; + } + } +} + +static void direct_link_paint_curve(FileData *fd, PaintCurve *pc) +{ + pc->points = newdataadr(fd, pc->points); +} + + static void direct_link_script(FileData *UNUSED(fd), Script *script) { script->id.us = 1; @@ -2664,9 +2703,9 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree) } } else if (ntree->type==NTREE_COMPOSIT) { - if (ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) + if (ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) direct_link_curvemapping(fd, node->storage); - else if (ELEM3(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) + else if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) ((ImageUser *)node->storage)->ok = 1; } else if ( ntree->type==NTREE_TEXTURE) { @@ -3516,7 +3555,8 @@ static void direct_link_material(FileData *fd, Material *ma) for (a = 0; a < MAX_MTEX; a++) { ma->mtex[a] = newdataadr(fd, ma->mtex[a]); } - + ma->texpaintslot = NULL; + ma->ramp_col = newdataadr(fd, ma->ramp_col); ma->ramp_spec = newdataadr(fd, ma->ramp_spec); @@ -5059,6 +5099,7 @@ static void link_paint(FileData *fd, Scene *sce, Paint *p) { if (p) { p->brush = newlibadr_us(fd, sce->id.lib, p->brush); + p->palette = newlibadr_us(fd, sce->id.lib, p->palette); p->paint_cursor = NULL; } } @@ -5107,6 +5148,18 @@ static void lib_link_scene(FileData *fd, Main *main) sce->toolsettings->sculpt->gravity_object = newlibadr_us(fd, sce->id.lib, sce->toolsettings->sculpt->gravity_object); + if (sce->toolsettings->imapaint.stencil) + sce->toolsettings->imapaint.stencil = + newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.stencil); + + if (sce->toolsettings->imapaint.clone) + sce->toolsettings->imapaint.clone = + newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.clone); + + if (sce->toolsettings->imapaint.canvas) + sce->toolsettings->imapaint.canvas = + newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.canvas); + sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template); for (base = sce->base.first; base; base = next) { @@ -5355,7 +5408,7 @@ static void direct_link_scene(FileData *fd, Scene *sce) if (seq->strip && seq->strip->done==0) { seq->strip->done = true; - if (ELEM4(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { + if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { seq->strip->stripdata = newdataadr(fd, seq->strip->stripdata); } else { @@ -5789,9 +5842,9 @@ static void lib_link_screen(FileData *fd, Main *main) /* how to handle user count on pointer restore */ typedef enum ePointerUserMode { - USER_IGNORE, /* ignore user count */ - USER_ONE, /* ensure at least one user (fake also counts) */ - USER_REAL /* ensure at least one real user (fake user ignored) */ + USER_IGNORE = 0, /* ignore user count */ + USER_ONE = 1, /* ensure at least one user (fake also counts) */ + USER_REAL = 2, /* ensure at least one real user (fake user ignored) */ } ePointerUserMode; static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user) @@ -5816,9 +5869,9 @@ static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user) * Only for undo files, or to restore a screen after reading without UI... * * user - * - 0: no usercount change - * - 1: ensure a user - * - 2: ensure a real user (even if a fake one is set) + * - USER_IGNORE: no usercount change + * - USER_ONE: ensure a user + * - USER_REAL: ensure a real user (even if a fake one is set) */ static void *restore_pointer_by_name(Main *mainp, ID *id, ePointerUserMode user) { @@ -5915,8 +5968,12 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc v3d->ob_centre = restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, USER_ONE); for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) { - bgpic->ima = restore_pointer_by_name(newmain, (ID *)bgpic->ima, USER_ONE); - bgpic->clip = restore_pointer_by_name(newmain, (ID *)bgpic->clip, USER_ONE); + if ((bgpic->ima = restore_pointer_by_name(newmain, (ID *)bgpic->ima, USER_IGNORE))) { + id_us_plus((ID *)bgpic->ima); + } + if ((bgpic->clip = restore_pointer_by_name(newmain, (ID *)bgpic->clip, USER_IGNORE))) { + id_us_plus((ID *)bgpic->clip); + } } if (v3d->localvd) { /*Base *base;*/ @@ -6290,6 +6347,9 @@ static bool direct_link_screen(FileData *fd, bScreen *sc) else if (sa->spacetype == SPACE_VIEW3D) blo_do_versions_view3d_split_250(sa->spacedata.first, &sa->regionbase); + /* incase we set above */ + sa->butspacetype = sa->spacetype; + for (sl = sa->spacedata.first; sl; sl = sl->next) { link_list(fd, &(sl->regionbase)); @@ -7138,6 +7198,8 @@ static const char *dataname(short id_code) case ID_NT: return "Data from NT"; case ID_BR: return "Data from BR"; case ID_PA: return "Data from PA"; + case ID_PAL: return "Data from PAL"; + case ID_PC: return "Data from PCRV"; case ID_GD: return "Data from GD"; case ID_WM: return "Data from WM"; case ID_MC: return "Data from MC"; @@ -7323,6 +7385,12 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID case ID_LS: direct_link_linestyle(fd, (FreestyleLineStyle *)id); break; + case ID_PAL: + direct_link_palette(fd, (Palette *)id); + break; + case ID_PC: + direct_link_paint_curve(fd, (PaintCurve *)id); + break; } oldnewmap_free_unused(fd->datamap); @@ -7487,8 +7555,9 @@ static void lib_link_all(FileData *fd, Main *main) /* No load UI for undo memfiles */ if (fd->memfile == NULL) { lib_link_windowmanager(fd, main); - lib_link_screen(fd, main); } + /* DO NOT skip screens here, 3Dview may contains pointers to other ID data (like bgpic)! See T41411. */ + lib_link_screen(fd, main); lib_link_scene(fd, main); lib_link_object(fd, main); lib_link_curve(fd, main); @@ -7511,6 +7580,8 @@ static void lib_link_all(FileData *fd, Main *main) lib_link_vfont(fd, main); lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */ lib_link_brush(fd, main); + lib_link_palette(fd, main); + lib_link_paint_curve(fd, main); lib_link_particlesettings(fd, main); lib_link_movieclip(fd, main); lib_link_mask(fd, main); @@ -8050,6 +8121,7 @@ static void expand_brush(FileData *fd, Main *mainvar, Brush *brush) expand_doit(fd, mainvar, brush->mtex.tex); expand_doit(fd, mainvar, brush->mask_mtex.tex); expand_doit(fd, mainvar, brush->clone.image); + expand_doit(fd, mainvar, brush->paint_curve); } static void expand_material(FileData *fd, Main *mainvar, Material *ma) diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 3890e07bb65..7c6b6ec7249 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -2454,9 +2454,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) if (sl->spacetype == SPACE_OUTLINER) { SpaceOops *so = (SpaceOops *)sl; - if (!ELEM11(so->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_SELECTED, SO_ACTIVE, - SO_SAME_TYPE, SO_GROUPS, SO_LIBRARIES, SO_SEQUENCE, SO_DATABLOCKS, - SO_USERDEF)) + if (!ELEM(so->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_SELECTED, SO_ACTIVE, + SO_SAME_TYPE, SO_GROUPS, SO_LIBRARIES, SO_SEQUENCE, SO_DATABLOCKS, + SO_USERDEF)) { so->outlinevis = SO_ALL_SCENES; } diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 103f9b76ba7..8e760a9c9f6 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -34,6 +34,8 @@ /* allow readfile to use deprecated functionality */ #define DNA_DEPRECATED_ALLOW +#include "DNA_brush_types.h" +#include "DNA_cloth_types.h" #include "DNA_constraint_types.h" #include "DNA_sdna_types.h" #include "DNA_space_types.h" @@ -41,7 +43,9 @@ #include "DNA_object_types.h" #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" +#include "DNA_particle_types.h" #include "DNA_linestyle_types.h" +#include "DNA_actuator_types.h" #include "DNA_genfile.h" @@ -308,6 +312,44 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) mat->line_col[3] = mat->alpha; } } + + if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "int", "preview_start_resolution")) { + Scene *scene; + for (scene = main->scene.first; scene; scene = scene->id.next) { + scene->r.preview_start_resolution = 64; + } + } + } + + if (!MAIN_VERSION_ATLEAST(main, 271, 2)) { + /* init up & track axis property of trackto actuators */ + Object *ob; + + for (ob = main->object.first; ob; ob = ob->id.next) { + bActuator *act; + for (act = ob->actuators.first; act; act = act->next) { + if (act->type == ACT_EDIT_OBJECT) { + bEditObjectActuator *eoact = act->data; + eoact->trackflag = ob->trackflag; + /* if trackflag is pointing +-Z axis then upflag should point Y axis. + * Rest of trackflag cases, upflag should be point z axis */ + if ((ob->trackflag == OB_POSZ) || (ob->trackflag == OB_NEGZ)) { + eoact->upflag = 1; + } + else { + eoact->upflag = 2; + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(main, 271, 3)) { + Brush *br; + + for (br = main->brush.first; br; br = br->id.next) { + br->fill_threshold = 0.2f; + } } if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "int", "preview_start_resolution")) { @@ -316,4 +358,20 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) scene->r.preview_start_resolution = 64; } } + + if (!MAIN_VERSION_ATLEAST(main, 271, 6)) { + Object *ob; + 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_ParticleSystem) { + ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md; + if (pmd->psys && pmd->psys->clmd) { + pmd->psys->clmd->sim_parms->vel_damping = 1.0f; + } + } + } + } + } } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index fdedd3f4edd..217d1f0821f 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -26,8 +26,10 @@ */ #include "BLI_utildefines.h" +#include "BLI_listbase.h" #include "BLI_math.h" +#include "DNA_brush_types.h" #include "DNA_freestyle_types.h" #include "DNA_linestyle_types.h" #include "DNA_scene_types.h" @@ -36,14 +38,34 @@ #include "DNA_userdef_types.h" #include "DNA_mesh_types.h" #include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "BKE_brush.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BLO_readfile.h" -/* Update defaults in startup.blend, without having to save and embed the file. + +/** + * Override values in in-memory startup.blend, avoids resaving for small changes. + */ +void BLO_update_defaults_userpref_blend(void) +{ + /* defaults from T37518 */ + + U.uiflag |= USER_ZBUF_CURSOR; + U.uiflag |= USER_QUIT_PROMPT; + U.uiflag |= USER_CONTINUOUS_MOUSE; + + U.versions = 1; + U.savetime = 2; +} + +/** + * 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) +void BLO_update_defaults_startup_blend(Main *bmain) { Scene *scene; SceneRenderLayer *srl; @@ -51,7 +73,7 @@ void BLO_update_defaults_startup_blend(Main *main) Mesh *me; Material *mat; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { scene->r.im_format.planes = R_IMF_PLANES_RGBA; scene->r.im_format.compress = 15; @@ -59,9 +81,20 @@ void BLO_update_defaults_startup_blend(Main *main) srl->freestyleConfig.sphere_radius = 0.1f; srl->pass_alpha_threshold = 0.5f; } + + if (scene->toolsettings) { + ToolSettings *ts = scene->toolsettings; + + if (ts->sculpt) { + Sculpt *sculpt = ts->sculpt; + sculpt->paint.symmetry_flags |= PAINT_SYMM_X; + sculpt->flags |= SCULPT_DYNTOPO_COLLAPSE; + sculpt->detail_size = 12; + } + } } - for (linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) { + for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) { linestyle->flag = LS_SAME_OBJECT | LS_NO_SORTING | LS_TEXTURE; linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA; linestyle->integration_type = LS_INTEGRATION_MEAN; @@ -71,27 +104,48 @@ void BLO_update_defaults_startup_blend(Main *main) { bScreen *screen; - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { ScrArea *area; for (area = screen->areabase.first; area; area = area->next) { SpaceLink *space_link; + ARegion *ar; + for (space_link = area->spacedata.first; space_link; space_link = space_link->next) { if (space_link->spacetype == SPACE_CLIP) { SpaceClip *space_clip = (SpaceClip *) space_link; space_clip->flag &= ~SC_MANUAL_CALIBRATION; } } + + /* Remove all stored panels, we want to use defaults (order, open/closed) as defined by UI code here! */ + for (ar = area->regionbase.first; ar; ar = ar->next) { + BLI_freelistN(&ar->panels); + } } } } - for (me = main->mesh.first; me; me = me->id.next) { + for (me = bmain->mesh.first; me; me = me->id.next) { me->smoothresh = DEG2RADF(180.0f); + me->flag &= ~ME_TWOSIDED; } - for (mat = main->mat.first; mat; mat = mat->id.next) { + for (mat = bmain->mat.first; mat; mat = mat->id.next) { mat->line_col[0] = mat->line_col[1] = mat->line_col[2] = 0.0f; mat->line_col[3] = 1.0f; } + + { + Brush *br; + br = BKE_brush_add(bmain, "Fill"); + br->imagepaint_tool = PAINT_TOOL_FILL; + br->ob_mode = OB_MODE_TEXTURE_PAINT; + + br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Mask"); + if (br) { + br->imagepaint_tool = PAINT_TOOL_MASK; + br->ob_mode |= OB_MODE_TEXTURE_PAINT; + } + } } diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 572c6d0a02d..557cc147f19 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -473,7 +473,7 @@ static void do_version_ntree_242_2(bNodeTree *ntree) if (ntree->type == NTREE_COMPOSIT) { for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM3(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { /* only image had storage */ if (node->storage) { NodeImageAnim *nia = node->storage; @@ -2232,7 +2232,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } if (sce->r.mode & R_PANORAMA) { - /* all these checks to ensure saved files with svn version keep working... */ + /* all these checks to ensure saved files between released versions keep working... */ if (sce->r.xsch < sce->r.ysch) { Object *obc = blo_do_versions_newlibadr(fd, lib, sce->camera); if (obc && obc->type == OB_CAMERA) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index a0198a687a2..59f12657703 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -183,6 +183,114 @@ #define MYWRITE_BUFFER_SIZE 100000 #define MYWRITE_MAX_CHUNK 32768 + + +/** \name Small API to handle compression. + * \{ */ + +typedef enum { + WW_WRAP_NONE = 1, + WW_WRAP_ZLIB, +} eWriteWrapType; + +typedef struct WriteWrap WriteWrap; +struct WriteWrap { + /* callbacks */ + bool (*open)(WriteWrap *ww, const char *filepath); + bool (*close)(WriteWrap *ww); + size_t (*write)(WriteWrap *ww, const char *data, size_t data_len); + + /* internal */ + union { + int file_handle; + gzFile gz_handle; + } _user_data; +}; + +/* none */ +#define FILE_HANDLE(ww) \ + (ww)->_user_data.file_handle + +static bool ww_open_none(WriteWrap *ww, const char *filepath) +{ + int file; + + file = BLI_open(filepath, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666); + + if (file != -1) { + FILE_HANDLE(ww) = file; + return true; + } + else { + return false; + } +} +static bool ww_close_none(WriteWrap *ww) +{ + return (close(FILE_HANDLE(ww)) != -1); +} +static size_t ww_write_none(WriteWrap *ww, const char *buf, size_t buf_len) +{ + return write(FILE_HANDLE(ww), buf, buf_len); +} +#undef FILE_HANDLE + +/* zlib */ +#define FILE_HANDLE(ww) \ + (ww)->_user_data.gz_handle + +static bool ww_open_zlib(WriteWrap *ww, const char *filepath) +{ + gzFile file; + + file = BLI_gzopen(filepath, "wb1"); + + if (file != Z_NULL) { + FILE_HANDLE(ww) = file; + return true; + } + else { + return false; + } +} +static bool ww_close_zlib(WriteWrap *ww) +{ + return (gzclose(FILE_HANDLE(ww)) == Z_OK); +} +static size_t ww_write_zlib(WriteWrap *ww, const char *buf, size_t buf_len) +{ + return gzwrite(FILE_HANDLE(ww), buf, buf_len); +} +#undef FILE_HANDLE + +/* --- end compression types --- */ + +static void ww_handle_init(eWriteWrapType ww_type, WriteWrap *r_ww) +{ + memset(r_ww, 0, sizeof(*r_ww)); + + switch (ww_type) { + case WW_WRAP_ZLIB: + { + r_ww->open = ww_open_zlib; + r_ww->close = ww_close_zlib; + r_ww->write = ww_write_zlib; + break; + } + default: + { + r_ww->open = ww_open_none; + r_ww->close = ww_close_none; + r_ww->write = ww_write_none; + break; + } + } +} + +/** \} */ + + + typedef struct { struct SDNA *sdna; @@ -192,12 +300,17 @@ typedef struct { int tot, count, error, memsize; + /* Wrap writing, so we can use zlib or + * other compression types later, see: G_FILE_COMPRESS + * Will be NULL for UNDO. */ + WriteWrap *ww; + #ifdef USE_BMESH_SAVE_AS_COMPAT char use_mesh_compat; /* option to save with older mesh format */ #endif } WriteData; -static WriteData *writedata_new(int file) +static WriteData *writedata_new(WriteWrap *ww) { WriteData *wd= MEM_callocN(sizeof(*wd), "writedata"); @@ -209,7 +322,7 @@ static WriteData *writedata_new(int file) wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false); - wd->file= file; + wd->ww = ww; wd->buf= MEM_mallocN(MYWRITE_BUFFER_SIZE, "wd->buf"); @@ -226,9 +339,9 @@ static void writedata_do_write(WriteData *wd, const void *mem, int memlen) add_memfilechunk(NULL, wd->current, mem, memlen); } else { - if (write(wd->file, mem, memlen) != memlen) - wd->error= 1; - + if (wd->ww->write(wd->ww, mem, memlen) != memlen) { + wd->error = 1; + } } } @@ -302,9 +415,9 @@ static void mywrite(WriteData *wd, const void *adr, int len) * \param current The current memory file (can be NULL). * \warning Talks to other functions with global parameters */ -static WriteData *bgnwrite(int file, MemFile *compare, MemFile *current) +static WriteData *bgnwrite(WriteWrap *ww, MemFile *compare, MemFile *current) { - WriteData *wd= writedata_new(file); + WriteData *wd= writedata_new(ww); if (wd == NULL) return NULL; @@ -767,7 +880,7 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree) writedata(wd, DATA, strlen(nss->bytecode)+1, nss->bytecode); writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage); } - else if (ntree->type==NTREE_COMPOSIT && ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) + else if (ntree->type==NTREE_COMPOSIT && ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) write_curvemapping(wd, node->storage); else if (ntree->type==NTREE_TEXTURE && (node->type==TEX_NODE_CURVE_RGB || node->type==TEX_NODE_CURVE_TIME) ) write_curvemapping(wd, node->storage); @@ -2256,6 +2369,9 @@ static void write_scenes(WriteData *wd, ListBase *scebase) case SEQ_TYPE_TRANSFORM: writestruct(wd, DATA, "TransformVars", 1, seq->effectdata); break; + case SEQ_TYPE_GAUSSIAN_BLUR: + writestruct(wd, DATA, "GaussianBlurVars", 1, seq->effectdata); + break; } } @@ -2921,6 +3037,38 @@ static void write_brushes(WriteData *wd, ListBase *idbase) if (brush->curve) write_curvemapping(wd, brush->curve); + if (brush->curve) + writestruct(wd, DATA, "ColorBand", 1, brush->gradient); + } + } +} + +static void write_palettes(WriteData *wd, ListBase *idbase) +{ + Palette *palette; + + for (palette = idbase->first; palette; palette = palette->id.next) { + if (palette->id.us > 0 || wd->current) { + PaletteColor *color; + writestruct(wd, ID_PAL, "Palette", 1, palette); + if (palette->id.properties) IDP_WriteProperty(palette->id.properties, wd); + + for (color = palette->colors.first; color; color= color->next) + writestruct(wd, DATA, "PaletteColor", 1, color); + } + } +} + +static void write_paintcurves(WriteData *wd, ListBase *idbase) +{ + PaintCurve *pc; + + for (pc = idbase->first; pc; pc = pc->id.next) { + if (pc->id.us > 0 || wd->current) { + writestruct(wd, ID_PC, "PaintCurve", 1, pc); + + writestruct(wd, DATA, "PaintCurvePoint", pc->tot_points, pc->points); + if (pc->id.properties) IDP_WriteProperty(pc->id.properties, wd); } } } @@ -3334,8 +3482,11 @@ static void write_thumb(WriteData *wd, const int *img) } /* if MemFile * there's filesave to memory */ -static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFile *current, - int write_user_block, int write_flags, const int *thumb) +static int write_file_handle( + Main *mainvar, + WriteWrap *ww, + MemFile *compare, MemFile *current, + int write_user_block, int write_flags, const int *thumb) { BHead bhead; ListBase mainlist; @@ -3344,7 +3495,7 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil blo_split_main(&mainlist, mainvar); - wd= bgnwrite(handle, compare, current); + wd = bgnwrite(ww, compare, current); #ifdef USE_BMESH_SAVE_AS_COMPAT wd->use_mesh_compat = (write_flags & G_FILE_MESH_COMPAT) != 0; @@ -3396,6 +3547,8 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil write_particlesettings(wd, &mainvar->particle); write_nodetrees(wd, &mainvar->nodetree); write_brushes (wd, &mainvar->brush); + write_palettes (wd, &mainvar->palettes); + write_paintcurves (wd, &mainvar->paintcurves); write_scripts (wd, &mainvar->script); write_gpencils (wd, &mainvar->gpencil); write_linestyles(wd, &mainvar->linestyle); @@ -3468,7 +3621,9 @@ static bool do_history(const char *name, ReportList *reports) int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportList *reports, const int *thumb) { char tempname[FILE_MAX+1]; - int file, err, write_user_block; + int err, write_user_block; + eWriteWrapType ww_type; + WriteWrap ww; /* path backup/restore */ void *path_list_backup = NULL; @@ -3477,8 +3632,16 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL /* open temporary file, so we preserve the original in case we crash */ BLI_snprintf(tempname, sizeof(tempname), "%s@", filepath); - file = BLI_open(tempname, O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666); - if (file == -1) { + if (write_flags & G_FILE_COMPRESS) { + ww_type = WW_WRAP_ZLIB; + } + else { + ww_type = WW_WRAP_NONE; + } + + ww_handle_init(ww_type, &ww); + + if (ww.open(&ww, tempname) == false) { BKE_reportf(reports, RPT_ERROR, "Cannot open file %s for writing: %s", tempname, strerror(errno)); return 0; } @@ -3519,8 +3682,9 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL BKE_bpath_relative_convert(mainvar, filepath, NULL); /* note, making relative to something OTHER then G.main->name */ /* actual file writing */ - err= write_file_handle(mainvar, file, NULL, NULL, write_user_block, write_flags, thumb); - close(file); + err = write_file_handle(mainvar, &ww, NULL, NULL, write_user_block, write_flags, thumb); + + ww.close(&ww); if (UNLIKELY(path_list_backup)) { BKE_bpath_list_restore(mainvar, path_list_flag, path_list_backup); @@ -3544,34 +3708,7 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL } } - if (write_flags & G_FILE_COMPRESS) { - /* compressed files have the same ending as regular files... only from 2.4!!! */ - char gzname[FILE_MAX+4]; - int ret; - - /* first write compressed to separate @.gz */ - BLI_snprintf(gzname, sizeof(gzname), "%s@.gz", filepath); - ret = BLI_file_gzip(tempname, gzname); - - if (0==ret) { - /* now rename to real file name, and delete temp @ file too */ - if (BLI_rename(gzname, filepath) != 0) { - BKE_report(reports, RPT_ERROR, "Cannot change old file (file saved with @)"); - return 0; - } - - BLI_delete(tempname, false, false); - } - else if (-1==ret) { - BKE_report(reports, RPT_ERROR, "Failed opening .gz file"); - return 0; - } - else if (-2==ret) { - BKE_report(reports, RPT_ERROR, "Failed opening .blend file for compression"); - return 0; - } - } - else if (BLI_rename(tempname, filepath) != 0) { + if (BLI_rename(tempname, filepath) != 0) { BKE_report(reports, RPT_ERROR, "Cannot change old file (file saved with @)"); return 0; } @@ -3584,7 +3721,7 @@ int BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int wr { int err; - err= write_file_handle(mainvar, 0, compare, current, 0, write_flags, NULL); + err = write_file_handle(mainvar, NULL, compare, current, 0, write_flags, NULL); if (err==0) return 1; return 0; diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index 2cd256e2346..a43e835f022 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -136,6 +136,8 @@ set(SRC tools/bmesh_edgenet.h tools/bmesh_edgesplit.c tools/bmesh_edgesplit.h + tools/bmesh_intersect.c + tools/bmesh_intersect.h tools/bmesh_path.c tools/bmesh_path.h tools/bmesh_triangulate.c diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index 01745396cd1..39359b97a4e 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -285,8 +285,8 @@ extern void bpy_bm_generic_invalidate(struct BPy_BMGeneric *self); typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data); /* defines */ -#define BM_ELEM_CD_SET_INT(ele, offset, f) \ - { assert(offset != -1); *((int *)((char *)(ele)->head.data + (offset))) = (f); } (void)0 +#define BM_ELEM_CD_SET_INT(ele, offset, f) { CHECK_TYPE_NONCONST(ele); \ + assert(offset != -1); *((int *)((char *)(ele)->head.data + (offset))) = (f); } (void)0 #define BM_ELEM_CD_GET_INT(ele, offset) \ (assert(offset != -1), *((int *)((char *)(ele)->head.data + (offset)))) @@ -294,8 +294,8 @@ typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data); #define BM_ELEM_CD_GET_VOID_P(ele, offset) \ (assert(offset != -1), (void *)((char *)(ele)->head.data + (offset))) -#define BM_ELEM_CD_SET_FLOAT(ele, offset, f) \ - { assert(offset != -1); *((float *)((char *)(ele)->head.data + (offset))) = (f); } (void)0 +#define BM_ELEM_CD_SET_FLOAT(ele, offset, f) { CHECK_TYPE_NONCONST(ele); \ + assert(offset != -1); *((float *)((char *)(ele)->head.data + (offset))) = (f); } (void)0 #define BM_ELEM_CD_GET_FLOAT(ele, offset) \ (assert(offset != -1), *((float *)((char *)(ele)->head.data + (offset)))) diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 1c93eccf8bd..1f942dad048 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -62,6 +62,8 @@ BMVert *BM_vert_create(BMesh *bm, const float co[3], { BMVert *v = BLI_mempool_alloc(bm->vpool); + BLI_assert((v_example == NULL) || (v_example->head.htype == BM_VERT)); + BLI_assert(!(create_flag & 1)); /* --- assign all members --- */ v->head.data = NULL; @@ -136,6 +138,8 @@ BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, BLI_assert(v1 != v2); BLI_assert(v1->head.htype == BM_VERT && v2->head.htype == BM_VERT); + BLI_assert((e_example == NULL) || (e_example->head.htype == BM_EDGE)); + BLI_assert(!(create_flag & 1)); if ((create_flag & BM_CREATE_NO_DOUBLE) && (e = BM_edge_exists(v1, v2))) return e; @@ -191,12 +195,15 @@ BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, } static BMLoop *bm_loop_create(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f, - const BMLoop *example, const eBMCreateFlag create_flag) + const BMLoop *l_example, const eBMCreateFlag create_flag) { BMLoop *l = NULL; l = BLI_mempool_alloc(bm->lpool); + BLI_assert((l_example == NULL) || (l_example->head.htype == BM_LOOP)); + BLI_assert(!(create_flag & 1)); + /* --- assign all members --- */ l->head.data = NULL; @@ -226,8 +233,8 @@ static BMLoop *bm_loop_create(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f, bm->totloop++; if (!(create_flag & BM_CREATE_SKIP_CD)) { - if (example) { - CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, example->head.data, &l->head.data); + if (l_example) { + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_example->head.data, &l->head.data); } else { CustomData_bmesh_set_default(&bm->ldata, &l->head.data); @@ -388,7 +395,10 @@ BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len, BMFace *f = NULL; BMLoop *l, *startl, *lastl; int i; - + + BLI_assert((f_example == NULL) || (f_example->head.htype == BM_FACE)); + BLI_assert(!(create_flag & 1)); + if (len == 0) { /* just return NULL for now */ return NULL; @@ -956,54 +966,38 @@ bool bmesh_loop_reverse(BMesh *bm, BMFace *f) #endif } -static void bm_elements_systag_enable(void *veles, int tot, int flag) +static void bm_elements_systag_enable(void *veles, int tot, const char api_flag) { BMHeader **eles = veles; int i; for (i = 0; i < tot; i++) { - BM_ELEM_API_FLAG_ENABLE((BMElemF *)eles[i], flag); + BM_ELEM_API_FLAG_ENABLE((BMElemF *)eles[i], api_flag); } } -static void bm_elements_systag_disable(void *veles, int tot, int flag) +static void bm_elements_systag_disable(void *veles, int tot, const char api_flag) { BMHeader **eles = veles; int i; for (i = 0; i < tot; i++) { - BM_ELEM_API_FLAG_DISABLE((BMElemF *)eles[i], flag); + BM_ELEM_API_FLAG_DISABLE((BMElemF *)eles[i], api_flag); } } -static int count_flagged_radial(BMesh *bm, BMLoop *l, int flag) +static int bm_loop_systag_count_radial(BMLoop *l, const char api_flag) { - BMLoop *l2 = l; - int i = 0, c = 0; - + BMLoop *l_iter = l; + int i = 0; do { - if (UNLIKELY(!l2)) { - BMESH_ASSERT(0); - goto error; - } - - i += BM_ELEM_API_FLAG_TEST(l2->f, flag) ? 1 : 0; - l2 = l2->radial_next; - if (UNLIKELY(c >= BM_LOOP_RADIAL_MAX)) { - BMESH_ASSERT(0); - goto error; - } - c++; - } while (l2 != l); + i += BM_ELEM_API_FLAG_TEST(l_iter->f, api_flag) ? 1 : 0; + } while ((l_iter = l_iter->radial_next) != l); return i; - -error: - BMO_error_raise(bm, bm->currentop, BMERR_MESH_ERROR, NULL); - return 0; } -static int UNUSED_FUNCTION(count_flagged_disk)(BMVert *v, int flag) +static int UNUSED_FUNCTION(bm_vert_systag_count_disk)(BMVert *v, const char api_flag) { BMEdge *e = v->e; int i = 0; @@ -1012,13 +1006,13 @@ static int UNUSED_FUNCTION(count_flagged_disk)(BMVert *v, int flag) return 0; do { - i += BM_ELEM_API_FLAG_TEST(e, flag) ? 1 : 0; + i += BM_ELEM_API_FLAG_TEST(e, api_flag) ? 1 : 0; } while ((e = bmesh_disk_edge_next(e, v)) != v->e); return i; } -static bool disk_is_flagged(BMVert *v, int flag) +static bool disk_is_flagged(BMVert *v, const char api_flag) { BMEdge *e = v->e; @@ -1036,7 +1030,7 @@ static bool disk_is_flagged(BMVert *v, int flag) return false; do { - if (!BM_ELEM_API_FLAG_TEST(l->f, flag)) + if (!BM_ELEM_API_FLAG_TEST(l->f, api_flag)) return false; } while ((l = l->radial_next) != e->l); } while ((e = bmesh_disk_edge_next(e, v)) != v->e); @@ -1093,7 +1087,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) f = faces[i]; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - int rlen = count_flagged_radial(bm, l_iter, _FLAG_JF); + int rlen = bm_loop_systag_count_radial(l_iter, _FLAG_JF); if (rlen > 2) { err = N_("Input faces do not form a contiguous manifold region"); @@ -1318,7 +1312,7 @@ BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2, #ifdef USE_BMESH_HOLES ListBase *holes, #endif - BMEdge *example, + BMEdge *e_example, const bool no_double ) { @@ -1338,7 +1332,7 @@ BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2, BLI_assert(f == l_v1->f && f == l_v2->f); /* allocate new edge between v1 and v2 */ - e = BM_edge_create(bm, v1, v2, example, no_double ? BM_CREATE_NO_DOUBLE : BM_CREATE_NOP); + e = BM_edge_create(bm, v1, v2, e_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); @@ -1748,8 +1742,7 @@ BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, l_kill = l_kill->radial_next; } for (i = 0; i < radlen; i++) { - bm->totloop--; - BLI_mempool_free(bm->lpool, loops[i]); + bm_kill_only_loop(bm, loops[i]); } } #ifndef NDEBUG @@ -1957,6 +1950,44 @@ BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e) } /** + * Check if splicing vertices would create any double edges. + * + * \note assume caller will handle case where verts share an edge. + */ +bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b) +{ + bool is_double = false; + + BLI_assert(BM_edge_exists(v_a, v_b) == false); + + if (v_a->e && v_b->e) { + SmallHash visit; + BMEdge *e, *e_first; + + BLI_smallhash_init(&visit); + + e = e_first = v_a->e; + do { + BMVert *v_other = BM_edge_other_vert(e, v_a); + BLI_smallhash_insert(&visit, (uintptr_t)v_other, NULL); + } while ((e = BM_DISK_EDGE_NEXT(e, v_a)) != e_first); + + e = e_first = v_b->e; + do { + BMVert *v_other = BM_edge_other_vert(e, v_b); + if (BLI_smallhash_haskey(&visit, (uintptr_t)v_other)) { + is_double = true; + break; + } + } while ((e = BM_DISK_EDGE_NEXT(e, v_b)) != e_first); + + BLI_smallhash_release(&visit); + } + + return is_double; +} + +/** * \brief Splice Vert * * Merges two verts into one (\a v into \a vtarget). @@ -1969,10 +2000,6 @@ BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e) */ bool BM_vert_splice(BMesh *bm, BMVert *v, BMVert *v_target) { - void *loops_stack[BM_DEFAULT_ITER_STACK_SIZE]; - BMLoop **loops; - int i, loops_tot; - BMEdge *e; /* verts already spliced */ @@ -1980,21 +2007,25 @@ bool BM_vert_splice(BMesh *bm, BMVert *v, BMVert *v_target) return false; } - /* we can't modify the vert while iterating so first allocate an array of loops */ - loops = BM_iter_as_arrayN(bm, BM_LOOPS_OF_VERT, v, &loops_tot, - loops_stack, BM_DEFAULT_ITER_STACK_SIZE); - - if (LIKELY(loops != NULL)) { - for (i = 0; i < loops_tot; i++) { - loops[i]->v = v_target; - } - if (loops != (BMLoop **)loops_stack) { - MEM_freeN(loops); - } - } + BLI_assert(BM_vert_pair_share_face_check(v, v_target) == false); /* move all the edges from v's disk to vtarget's disk */ while ((e = v->e)) { + + /* loop */ + BMLoop *l_first; + if ((l_first = e->l)) { + BMLoop *l_iter = l_first; + do { + if (l_iter->v == v) { + l_iter->v = v_target; + } + /* else if (l_iter->prev->v == v) {...} + * (this case will be handled by a different edge) */ + } while ((l_iter = l_iter->radial_next) != l_first); + } + + /* disk */ bmesh_disk_edge_remove(e, v); bmesh_edge_swapverts(e, v, v_target); bmesh_disk_edge_append(e, v_target); @@ -2048,15 +2079,16 @@ void bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len /* Considering only edges and faces incident on vertex v, walk * the edges & faces and assign an index to each connected set */ + BLI_smallhash_insert(&visithash, (uintptr_t)e, SET_INT_IN_POINTER(maxindex)); do { - BLI_smallhash_insert(&visithash, (uintptr_t)e, SET_INT_IN_POINTER(maxindex)); - if (e->l) { BMLoop *l_iter, *l_first; l_iter = l_first = e->l; do { l_new = (l_iter->v == v) ? l_iter->prev : l_iter->next; + BLI_assert(BM_vert_in_edge(l_new->e, v)); if (!BLI_smallhash_haskey(&visithash, (uintptr_t)l_new->e)) { + BLI_smallhash_insert(&visithash, (uintptr_t)l_new->e, SET_INT_IN_POINTER(maxindex)); STACK_PUSH(stack, l_new->e); } } while ((l_iter = l_iter->radial_next) != l_first); diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h index 4a2b4b7feca..ab847fc82eb 100644 --- a/source/blender/bmesh/intern/bmesh_core.h +++ b/source/blender/bmesh/intern/bmesh_core.h @@ -61,6 +61,7 @@ void bmesh_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select); bool BM_edge_splice(BMesh *bm, BMEdge *e, BMEdge *e_target); bool BM_vert_splice(BMesh *bm, BMVert *v, BMVert *v_target); +bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b); void bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select); diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c index f01e1197bb7..e83a1d5b00a 100644 --- a/source/blender/bmesh/intern/bmesh_edgeloop.c +++ b/source/blender/bmesh/intern/bmesh_edgeloop.c @@ -682,12 +682,12 @@ void BM_edgeloop_expand(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store, int el_sto LinkData *node_curr_init = node_curr; LinkData *node_curr_copy; int i = 0; - LISTBASE_CIRCULAR_FORWARD_BEGIN (&el_store->verts, node_curr, node_curr_init) { + BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (&el_store->verts, node_curr, node_curr_init) { if (i++ < step) { break; } } - LISTBASE_CIRCULAR_FORWARD_END (&el_store->verts, node_curr, node_curr_init); + BLI_LISTBASE_CIRCULAR_FORWARD_END (&el_store->verts, node_curr, node_curr_init); node_curr_copy = MEM_dupallocN(node_curr); BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy); diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index 2250b8135d7..306b6e74350 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -397,8 +397,8 @@ static float bm_loop_flip_equotion(float mat[2][2], float b[2], const float targ return mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]; } -static void bm_loop_flip_disp(float source_axis_x[3], float source_axis_y[3], - float target_axis_x[3], float target_axis_y[3], float disp[3]) +static void bm_loop_flip_disp(const float source_axis_x[3], const float source_axis_y[3], + const float target_axis_x[3], const float target_axis_y[3], float disp[3]) { float vx[3], vy[3], coord[3]; float n[3], vec[3]; diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h index 2a3b5190ece..c605ad31ae7 100644 --- a/source/blender/bmesh/intern/bmesh_interp.h +++ b/source/blender/bmesh/intern/bmesh_interp.h @@ -33,9 +33,9 @@ void BM_vert_interp_from_face(BMesh *bm, BMVert *v, BMFace *source); void BM_data_interp_from_verts(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, const float fac); void BM_data_interp_from_edges(BMesh *bm, BMEdge *e1, BMEdge *e2, BMEdge *e, const float fac); void BM_data_interp_face_vert_edge(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, BMEdge *e1, const float fac); -void BM_data_layer_add(BMesh *em, CustomData *data, int type); +void BM_data_layer_add(BMesh *bm, CustomData *data, int type); void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name); -void BM_data_layer_free(BMesh *em, CustomData *data, int type); +void BM_data_layer_free(BMesh *bm, CustomData *data, int type); void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n); void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int dst_n); diff --git a/source/blender/bmesh/intern/bmesh_iterators_inline.h b/source/blender/bmesh/intern/bmesh_iterators_inline.h index 6a0eb0e0a30..b9733d4702f 100644 --- a/source/blender/bmesh/intern/bmesh_iterators_inline.h +++ b/source/blender/bmesh/intern/bmesh_iterators_inline.h @@ -80,60 +80,70 @@ BLI_INLINE bool BM_iter_init(BMIter *iter, BMesh *bm, const char itype, void *da break; case BM_EDGES_OF_VERT: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_VERT); iter->begin = (BMIter__begin_cb)bmiter__edge_of_vert_begin; iter->step = (BMIter__step_cb)bmiter__edge_of_vert_step; iter->data.edge_of_vert.vdata = (BMVert *)data; break; case BM_FACES_OF_VERT: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_VERT); iter->begin = (BMIter__begin_cb)bmiter__face_of_vert_begin; iter->step = (BMIter__step_cb)bmiter__face_of_vert_step; iter->data.face_of_vert.vdata = (BMVert *)data; break; case BM_LOOPS_OF_VERT: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_VERT); iter->begin = (BMIter__begin_cb)bmiter__loop_of_vert_begin; iter->step = (BMIter__step_cb)bmiter__loop_of_vert_step; iter->data.loop_of_vert.vdata = (BMVert *)data; break; case BM_VERTS_OF_EDGE: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_EDGE); iter->begin = (BMIter__begin_cb)bmiter__vert_of_edge_begin; iter->step = (BMIter__step_cb)bmiter__vert_of_edge_step; iter->data.vert_of_edge.edata = (BMEdge *)data; break; case BM_FACES_OF_EDGE: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_EDGE); iter->begin = (BMIter__begin_cb)bmiter__face_of_edge_begin; iter->step = (BMIter__step_cb)bmiter__face_of_edge_step; iter->data.face_of_edge.edata = (BMEdge *)data; break; case BM_VERTS_OF_FACE: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_FACE); iter->begin = (BMIter__begin_cb)bmiter__vert_of_face_begin; iter->step = (BMIter__step_cb)bmiter__vert_of_face_step; iter->data.vert_of_face.pdata = (BMFace *)data; break; case BM_EDGES_OF_FACE: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_FACE); iter->begin = (BMIter__begin_cb)bmiter__edge_of_face_begin; iter->step = (BMIter__step_cb)bmiter__edge_of_face_step; iter->data.edge_of_face.pdata = (BMFace *)data; break; case BM_LOOPS_OF_FACE: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_FACE); iter->begin = (BMIter__begin_cb)bmiter__loop_of_face_begin; iter->step = (BMIter__step_cb)bmiter__loop_of_face_step; iter->data.loop_of_face.pdata = (BMFace *)data; break; case BM_LOOPS_OF_LOOP: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_LOOP); iter->begin = (BMIter__begin_cb)bmiter__loop_of_loop_begin; iter->step = (BMIter__step_cb)bmiter__loop_of_loop_step; iter->data.loop_of_loop.ldata = (BMLoop *)data; break; case BM_LOOPS_OF_EDGE: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_EDGE); iter->begin = (BMIter__begin_cb)bmiter__loop_of_edge_begin; iter->step = (BMIter__step_cb)bmiter__loop_of_edge_step; iter->data.loop_of_edge.edata = (BMEdge *)data; diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index e23a5721234..19e6f646564 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -864,7 +864,9 @@ void BM_select_history_validate(BMesh *bm) } } -/* utility function */ +/** + * Get the active mesh element (with active-face fallback). + */ bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese) { BMEditSelection *ese_last = bm->selected.last; @@ -887,7 +889,8 @@ bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese) ese->htype = ese_last->htype; } } - else if (efa) { /* no */ + else if (efa) { + /* no edit-selection, fallback to active face */ ese->ele = (BMElem *)efa; ese->htype = BM_FACE; } @@ -899,6 +902,27 @@ bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese) return true; } +/** + * Return a map from BMVert/Edge/Face -> BMEditSelection + */ +GHash *BM_select_history_map_create(BMesh *bm) +{ + BMEditSelection *ese; + GHash *map; + + if (BLI_listbase_is_empty(&bm->selected)) { + return NULL; + } + + map = BLI_ghash_ptr_new(__func__); + + for (ese = bm->selected.first; ese; ese = ese->next) { + BLI_ghash_insert(map, ese->ele, ese); + } + + return map; +} + void BM_mesh_elem_hflag_disable_test(BMesh *bm, const char htype, const char hflag, const bool respecthide, const bool overwrite, const char hflag_test) { diff --git a/source/blender/bmesh/intern/bmesh_marking.h b/source/blender/bmesh/intern/bmesh_marking.h index 99456ea2c98..9e0c0923164 100644 --- a/source/blender/bmesh/intern/bmesh_marking.h +++ b/source/blender/bmesh/intern/bmesh_marking.h @@ -98,7 +98,14 @@ void _bm_select_history_store_after(BMesh *bm, BMEditSelection *ese_ref, BMHead void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele); void BM_select_history_validate(BMesh *bm); -void BM_select_history_clear(BMesh *em); +void BM_select_history_clear(BMesh *bm); bool BM_select_history_active_get(BMesh *bm, struct BMEditSelection *ese); +struct GHash *BM_select_history_map_create(BMesh *bm); + +#define BM_SELECT_HISTORY_BACKUP(bm) { \ + ListBase _bm_prev_selected = (bm)->selected; BLI_listbase_clear(&(bm)->selected) + +#define BM_SELECT_HISTORY_RESTORE(bm) \ + (bm)->selected = _bm_prev_selected; } (void)0 #endif /* __BMESH_MARKING_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index e66d1263578..b16ea42304a 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -641,11 +641,13 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const copy_v3_v3(nor, lnor); } } + else { + /* We still have to clear the stack! */ + while (BLI_SMALLSTACK_POP(normal)); + } } } while ((l_curr = l_curr->next) != l_first); } - - BLI_SMALLSTACK_FREE(normal); } #if 0 /* Unused currently */ @@ -764,6 +766,8 @@ void bmesh_edit_begin(BMesh *UNUSED(bm), BMOpTypeFlag UNUSED(type_flag)) */ void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag) { + ListBase select_history; + /* BMO_OPTYPE_FLAG_UNTAN_MULTIRES disabled for now, see comment above in bmesh_edit_begin. */ #ifdef BMOP_UNTAN_MULTIRES_ENABLED /* switch multires data into tangent space */ @@ -782,9 +786,19 @@ void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag) BM_mesh_normals_update(bm); } + + if ((type_flag & BMO_OPTYPE_FLAG_SELECT_VALIDATE) == 0) { + select_history = bm->selected; + BLI_listbase_clear(&bm->selected); + } + if (type_flag & BMO_OPTYPE_FLAG_SELECT_FLUSH) { BM_mesh_select_mode_flush(bm); } + + if ((type_flag & BMO_OPTYPE_FLAG_SELECT_VALIDATE) == 0) { + bm->selected = select_history; + } } void BM_mesh_elem_index_ensure(BMesh *bm, const char htype) @@ -800,7 +814,7 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype) } /* skip if we only need to operate on one element */ -#pragma omp parallel sections if ((!ELEM5(htype_needed, BM_VERT, BM_EDGE, BM_FACE, BM_LOOP, BM_FACE | BM_LOOP)) && \ +#pragma omp parallel sections if ((!ELEM(htype_needed, BM_VERT, BM_EDGE, BM_FACE, BM_LOOP, BM_FACE | BM_LOOP)) && \ (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)) { #pragma omp section @@ -1054,7 +1068,7 @@ void BM_mesh_elem_table_ensure(BMesh *bm, const char htype) } /* skip if we only need to operate on one element */ -#pragma omp parallel sections if ((!ELEM3(htype_needed, BM_VERT, BM_EDGE, BM_FACE)) && \ +#pragma omp parallel sections if ((!ELEM(htype_needed, BM_VERT, BM_EDGE, BM_FACE)) && \ (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)) { #pragma omp section @@ -1179,7 +1193,11 @@ int BM_mesh_elem_count(BMesh *bm, const char htype) * * WARNING: Be careful if you keep pointers to affected BM elements, or arrays, when using this func! */ -void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, unsigned int *face_idx) +void BM_mesh_remap( + BMesh *bm, + const unsigned int *vert_idx, + const unsigned int *edge_idx, + const unsigned int *face_idx) { /* Mapping old to new pointers. */ GHash *vptr_map = NULL, *eptr_map = NULL, *fptr_map = NULL; @@ -1192,18 +1210,23 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un if (!(vert_idx || edge_idx || face_idx)) return; + BM_mesh_elem_table_ensure( + bm, + (vert_idx ? BM_VERT : 0) | + (edge_idx ? BM_EDGE : 0) | + (face_idx ? BM_FACE : 0)); + /* Remap Verts */ if (vert_idx) { BMVert **verts_pool, *verts_copy, **vep; int i, totvert = bm->totvert; - unsigned int *new_idx = NULL; + const unsigned int *new_idx; /* Init the old-to-new 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"); - BM_iter_as_array(bm, BM_VERTS_OF_MESH, NULL, (void **)verts_pool, totvert); + verts_pool = bm->vtable; verts_copy = MEM_mallocN(sizeof(BMVert) * totvert, "BM_mesh_remap verts copy"); for (i = totvert, ve = verts_copy + totvert - 1, vep = verts_pool + totvert - 1; i--; ve--, vep--) { *ve = **vep; @@ -1221,8 +1244,8 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un BLI_ghash_insert(vptr_map, (void *)*vep, (void *)new_vep); } bm->elem_index_dirty |= BM_VERT; + bm->elem_table_dirty |= BM_VERT; - MEM_freeN(verts_pool); MEM_freeN(verts_copy); } @@ -1230,14 +1253,13 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un if (edge_idx) { BMEdge **edges_pool, *edges_copy, **edp; int i, totedge = bm->totedge; - unsigned int *new_idx = NULL; + const unsigned int *new_idx; /* Init the old-to-new vert 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"); - BM_iter_as_array(bm, BM_EDGES_OF_MESH, NULL, (void **)edges_pool, totedge); + edges_pool = bm->etable; edges_copy = MEM_mallocN(sizeof(BMEdge) * totedge, "BM_mesh_remap edges copy"); for (i = totedge, ed = edges_copy + totedge - 1, edp = edges_pool + totedge - 1; i--; ed--, edp--) { *ed = **edp; @@ -1254,8 +1276,8 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un /* printf("mapping edge from %d to %d (%p/%p to %p)\n", i, *new_idx, *edp, edges_pool[i], new_edp);*/ } bm->elem_index_dirty |= BM_EDGE; + bm->elem_table_dirty |= BM_EDGE; - MEM_freeN(edges_pool); MEM_freeN(edges_copy); } @@ -1263,14 +1285,13 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un if (face_idx) { BMFace **faces_pool, *faces_copy, **fap; int i, totface = bm->totface; - unsigned int *new_idx = NULL; + const unsigned int *new_idx; /* Init the old-to-new vert 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"); - BM_iter_as_array(bm, BM_FACES_OF_MESH, NULL, (void **)faces_pool, totface); + faces_pool = bm->ftable; faces_copy = MEM_mallocN(sizeof(BMFace) * totface, "BM_mesh_remap faces copy"); for (i = totface, fa = faces_copy + totface - 1, fap = faces_pool + totface - 1; i--; fa--, fap--) { *fa = **fap; @@ -1287,8 +1308,8 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un } bm->elem_index_dirty |= BM_FACE | BM_LOOP; + bm->elem_table_dirty |= BM_FACE; - MEM_freeN(faces_pool); MEM_freeN(faces_copy); } diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h index 3923c2515a3..22e50502aee 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.h +++ b/source/blender/bmesh/intern/bmesh_mesh.h @@ -50,7 +50,7 @@ void BM_mesh_elem_index_validate(BMesh *bm, const char *location, const char *fu const char *msg_a, const char *msg_b); #ifndef NDEBUG -bool BM_mesh_elem_table_check(BMesh *em); +bool BM_mesh_elem_table_check(BMesh *bm); #endif void BM_mesh_elem_table_ensure(BMesh *bm, const char htype); @@ -69,7 +69,11 @@ BMFace *BM_face_at_index_find(BMesh *bm, const int index); int BM_mesh_elem_count(BMesh *bm, const char htype); -void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, unsigned int *face_idx); +void BM_mesh_remap( + BMesh *bm, + const unsigned int *vert_idx, + const unsigned int *edge_idx, + const unsigned int *face_idx); typedef struct BMAllocTemplate { int totvert, totedge, totloop, totface; diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index 2d7a2cf93d6..6e8591da0f3 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -32,12 +32,19 @@ #include "BLI_math.h" #include "BLI_array.h" +#include "BLI_alloca.h" +#include "BLI_stackdefines.h" +#include "BLI_linklist_stack.h" +#include "BLI_sort_utils.h" #include "BKE_customdata.h" #include "bmesh.h" #include "intern/bmesh_private.h" +// #define DEBUG_PRINT + + /** * \brief Dissolve Vert * @@ -416,6 +423,547 @@ BMFace *BM_face_split_n(BMesh *bm, BMFace *f, return f_new; } + +/* -------------------------------------------------------------------- */ +/* Face Split Edge-Net */ + +/** \name BM_face_split_edgenet and helper functions. + * + * \note Don't use #BM_edge_is_wire or #BM_edge_is_boundary + * since we need to take flagged faces into account. + * Also take care accessing e->l directly. + * + * \{ */ + +/* Note: All these flags _must_ be cleared on exit */ + +/* face is apart of the edge-net (including the original face we're splitting) */ +#define FACE_NET _FLAG_WALK +/* edge is apart of the edge-net we're filling */ +#define EDGE_NET _FLAG_WALK +/* tag verts we've visit */ +#define VERT_VISIT _FLAG_WALK + +struct VertOrder { + float angle; + BMVert *v; +}; + +static unsigned int bm_edge_flagged_radial_count(BMEdge *e) +{ + unsigned int count = 0; + BMLoop *l; + + if ((l = e->l)) { + do { + if (BM_ELEM_API_FLAG_TEST(l->f, FACE_NET)) { + count++; + } + } while ((l = l->radial_next) != e->l); + } + return count; +} + +static BMLoop *bm_edge_flagged_radial_first(BMEdge *e) +{ + BMLoop *l; + + if ((l = e->l)) { + do { + if (BM_ELEM_API_FLAG_TEST(l->f, FACE_NET)) { + return l; + } + } while ((l = l->radial_next) != e->l); + } + return NULL; +} + +static bool bm_face_split_edgenet_find_loop_pair( + BMVert *v_init, const float face_normal[3], + BMEdge *e_pair[2]) +{ + /* Always find one boundary edge (to determine winding) + * and one wire (if available), otherwise another boundary. + */ + BMIter iter; + BMEdge *e; + + /* detect winding */ + BMLoop *l_walk; + bool swap; + + BLI_SMALLSTACK_DECLARE(edges_boundary, BMEdge *); + BLI_SMALLSTACK_DECLARE(edges_wire, BMEdge *); + int edges_boundary_len = 0; + int edges_wire_len = 0; + + BM_ITER_ELEM (e, &iter, v_init, BM_EDGES_OF_VERT) { + if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) { + const unsigned int count = bm_edge_flagged_radial_count(e); + if (count == 1) { + BLI_SMALLSTACK_PUSH(edges_boundary, e); + edges_boundary_len++; + } + else if (count == 0) { + BLI_SMALLSTACK_PUSH(edges_wire, e); + edges_wire_len++; + } + } + } + + /* first edge should always be boundary */ + if (edges_boundary_len == 0) { + return false; + } + e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary); + + /* attempt one boundary and one wire, or 2 boundary */ + if (edges_wire_len == 0) { + if (edges_boundary_len >= 2) { + e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary); + } + else { + /* one boundary and no wire */ + return false; + } + } + else { + e_pair[1] = BLI_SMALLSTACK_POP(edges_wire); + + if (edges_wire_len > 1) { + BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init); + BMVert *v_next; + float angle_best; + + v_next = BM_edge_other_vert(e_pair[1], v_init); + angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); + + while ((e = BLI_SMALLSTACK_POP(edges_wire))) { + float angle_test; + v_next = BM_edge_other_vert(e, v_init); + angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); + if (angle_test < angle_best) { + angle_best = angle_test; + e_pair[1] = e; + } + } + } + } + + + /* flip based on winding */ + l_walk = bm_edge_flagged_radial_first(e_pair[0]); + swap = false; + if (face_normal == l_walk->f->no) { + swap = !swap; + } + if (l_walk->v != v_init) { + swap = !swap; + } + if (swap) { + SWAP(BMEdge *, e_pair[0], e_pair[1]); + } + + return true; +} + +static bool bm_face_split_edgenet_find_loop_walk( + BMVert *v_init, const float face_normal[3], + /* cache to avoid realloc every time */ + struct VertOrder *edge_order, const unsigned int edge_order_len, + BMEdge *e_pair[2]) +{ + /* fast-path for the common case (avoid push-pop). + * Also avoids tagging as visited since we know we + * can't reach these verts some other way */ +#define USE_FASTPATH_NOFORK + + BMVert *v; + BMVert *v_dst; + bool found = false; + + struct VertOrder *eo; + STACK_DECLARE(edge_order); + + /* store visited verts so we can clear the visit flag after execution */ + BLI_SMALLSTACK_DECLARE(vert_visit, BMVert *); + + /* likely this will stay very small + * all verts pushed into this stack _must_ have their previous edges set! */ + BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *); + BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *); + + STACK_INIT(edge_order, edge_order_len); + + /* start stepping */ + v = BM_edge_other_vert(e_pair[0], v_init); + v->e = e_pair[0]; + BLI_SMALLSTACK_PUSH(vert_stack, v); + + v_dst = BM_edge_other_vert(e_pair[1], v_init); + +#ifdef DEBUG_PRINT + printf("%s: vert (search) %d\n", __func__, BM_elem_index_get(v_init)); +#endif + + /* This loop will keep stepping over the best possible edge, + * in most cases it finds the direct route to close the face. + * + * In cases where paths can't be closed, + * alternatives are stored in the 'vert_stack'. + */ + while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) { + BMIter eiter; + BMEdge *e_next; + +#ifdef USE_FASTPATH_NOFORK +walk_nofork: +#else + BLI_SMALLSTACK_PUSH(vert_visit, v); + BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT); +#endif + + BLI_assert(STACK_SIZE(edge_order) == 0); + + /* check if we're done! */ + if (v == v_dst) { + found = true; + goto finally; + } + + BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) { + if ((v->e != e_next) && + (BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) && + (bm_edge_flagged_radial_count(e_next) < 2)) + { + BMVert *v_next; + + v_next = BM_edge_other_vert(e_next, v); + +#ifdef DEBUG_PRINT + /* indent and print */ + { + BMVert *_v = v; + do { + printf(" "); + } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init); + printf("vert %d -> %d (add=%d)\n", + BM_elem_index_get(v), BM_elem_index_get(v_next), + BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0); + } +#endif + + if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) { + eo = STACK_PUSH_RET_PTR(edge_order); + eo->v = v_next; + + v_next->e = e_next; + } + } + } + +#ifdef USE_FASTPATH_NOFORK + if (STACK_SIZE(edge_order) == 1) { + eo = STACK_POP_PTR(edge_order); + v = eo->v; + + goto walk_nofork; + } +#endif + + /* sort by angle if needed */ + if (STACK_SIZE(edge_order) > 1) { + unsigned int j; + BMVert *v_prev = BM_edge_other_vert(v->e, v); + + for (j = 0; j < STACK_SIZE(edge_order); j++) { + edge_order[j].angle = angle_signed_on_axis_v3v3v3_v3(v_prev->co, v->co, edge_order[j].v->co, face_normal); + } + qsort(edge_order, STACK_SIZE(edge_order), sizeof(struct VertOrder), BLI_sortutil_cmp_float_reverse); + +#ifdef USE_FASTPATH_NOFORK + /* only tag forks */ + BLI_SMALLSTACK_PUSH(vert_visit, v); + BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT); +#endif + } + + while ((eo = STACK_POP_PTR(edge_order))) { + BLI_SMALLSTACK_PUSH(vert_stack_next, eo->v); + } + + if (!BLI_SMALLSTACK_IS_EMPTY(vert_stack_next)) { + BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next); + } + } + + +finally: + /* clear flag for next execution */ + while ((v = BLI_SMALLSTACK_POP(vert_visit))) { + BM_ELEM_API_FLAG_DISABLE(v, VERT_VISIT); + } + + return found; + +#undef USE_FASTPATH_NOFORK +} + +static bool bm_face_split_edgenet_find_loop( + BMVert *v_init, const float face_normal[3], + /* cache to avoid realloc every time */ + struct VertOrder *edge_order, const unsigned int edge_order_len, + BMVert **r_face_verts, int *r_face_verts_len) +{ + BMEdge *e_pair[2]; + BMVert *v; + + if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) { + return false; + } + + BLI_assert((bm_edge_flagged_radial_count(e_pair[0]) == 1) || + (bm_edge_flagged_radial_count(e_pair[1]) == 1)); + + if (bm_face_split_edgenet_find_loop_walk(v_init, face_normal, edge_order, edge_order_len, e_pair)) { + unsigned int i = 0; + + r_face_verts[i++] = v_init; + v = BM_edge_other_vert(e_pair[1], v_init); + do { + r_face_verts[i++] = v; + } while ((v = BM_edge_other_vert(v->e, v)) != v_init); + *r_face_verts_len = i; + return (i > 2) ? true : false; + } + else { + return false; + } +} + +/** + * Splits a face into many smaller faces defined by an edge-net. + * handle customdata and degenerate cases. + * + * - isolated holes or unsupported face configurations, will be ignored. + * - customdata calculations aren't efficient + * (need to calculate weights for each vert). + */ +bool BM_face_split_edgenet( + BMesh *bm, + BMFace *f, BMEdge **edge_net, const int edge_net_len, + BMFace ***r_face_arr, int *r_face_arr_len) +{ + /* re-use for new face verts */ + BMVert **face_verts; + int face_verts_len; + + BMFace **face_arr = NULL; + BLI_array_declare(face_arr); + + BMVert **vert_queue; + STACK_DECLARE(vert_queue); + int i; + + struct VertOrder *edge_order; + const unsigned int edge_order_len = edge_net_len + 2; + + BMVert *v; + + BMLoop *l_iter, *l_first; + + + if (!edge_net_len) { + if (r_face_arr) { + *r_face_arr = NULL; + *r_face_arr_len = 0; + } + return false; + } + + /* over-alloc (probably 2-4 is only used in most cases), for the biggest-fan */ + edge_order = BLI_array_alloca(edge_order, edge_order_len); + + /* use later */ + face_verts = BLI_array_alloca(face_verts, edge_net_len + f->len); + + vert_queue = BLI_array_alloca(vert_queue, edge_net_len + f->len); + STACK_INIT(vert_queue, f->len + edge_net_len); + + BLI_assert(BM_ELEM_API_FLAG_TEST(f, FACE_NET) == 0); + BM_ELEM_API_FLAG_ENABLE(f, FACE_NET); + +#ifdef DEBUG + for (i = 0; i < edge_net_len; i++) { + BLI_assert(BM_ELEM_API_FLAG_TEST(edge_net[i], EDGE_NET) == 0); + BLI_assert(BM_edge_in_face(edge_net[i], f) == false); + } + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BLI_assert(BM_ELEM_API_FLAG_TEST(l_iter->e, EDGE_NET) == 0); + } while ((l_iter = l_iter->next) != l_first); +#endif + + + for (i = 0; i < edge_net_len; i++) { + BM_ELEM_API_FLAG_ENABLE(edge_net[i], EDGE_NET); + } + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET); + } while ((l_iter = l_iter->next) != l_first); + + + /* any vert can be used to begin with */ + STACK_PUSH(vert_queue, l_first->v); + + while ((v = STACK_POP(vert_queue))) { + if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) { + BMFace *f_new; + + f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false); + + for (i = 0; i < edge_net_len; i++) { + BLI_assert(BM_ELEM_API_FLAG_TEST(edge_net[i], EDGE_NET)); + } + + if (f_new) { + bool l_prev_is_boundary; + BLI_array_append(face_arr, f_new); + copy_v3_v3(f_new->no, f->no); + + BM_ELEM_API_FLAG_ENABLE(f_new, FACE_NET); + + /* add new verts to keep finding loops for + * (verts between boundary and manifold edges) */ + l_iter = l_first = BM_FACE_FIRST_LOOP(f_new); + l_prev_is_boundary = (bm_edge_flagged_radial_count(l_iter->prev->e) == 1); + do { + bool l_iter_is_boundary = (bm_edge_flagged_radial_count(l_iter->e) == 1); + if (l_prev_is_boundary != l_iter_is_boundary) { + STACK_PUSH(vert_queue, l_iter->v); + } + l_prev_is_boundary = l_iter_is_boundary; + } while ((l_iter = l_iter->next) != l_first); + } + } + } + + + if (CustomData_has_math(&bm->ldata)) { + /* reuse VERT_VISIT here to tag vert's already interpolated */ + BMIter iter; + BMLoop *l_other; + + /* see: #BM_loop_interp_from_face for similar logic */ + void **blocks = BLI_array_alloca(blocks, f->len); + float (*cos_2d)[2] = BLI_array_alloca(cos_2d, f->len); + float *w = BLI_array_alloca(w, f->len); + float axis_mat[3][3]; + float co[2]; + + /* interior loops */ + axis_dominant_v3_to_m3(axis_mat, f->no); + + + /* first simply copy from existing face */ + i = 0; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BM_ITER_ELEM (l_other, &iter, l_iter->v, BM_LOOPS_OF_VERT) { + if ((l_other->f != f) && BM_ELEM_API_FLAG_TEST(l_other->f, FACE_NET)) { + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, + l_iter->head.data, &l_other->head.data); + } + } + /* tag not to interpolate */ + BM_ELEM_API_FLAG_ENABLE(l_iter->v, VERT_VISIT); + + + mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co); + blocks[i] = l_iter->head.data; + + } while (i++, (l_iter = l_iter->next) != l_first); + + + for (i = 0; i < edge_net_len; i++) { + BM_ITER_ELEM (v, &iter, edge_net[i], BM_VERTS_OF_EDGE) { + if (!BM_ELEM_API_FLAG_TEST(v, VERT_VISIT)) { + BMIter liter; + + BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT); + + /* interpolate this loop, then copy to the rest */ + l_first = NULL; + + BM_ITER_ELEM (l_iter, &liter, v, BM_LOOPS_OF_VERT) { + if (BM_ELEM_API_FLAG_TEST(l_iter->f, FACE_NET)) { + if (l_first == NULL) { + mul_v2_m3v3(co, axis_mat, v->co); + interp_weights_poly_v2(w, cos_2d, f->len, co); + CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, f->len, l_iter->head.data); + l_first = l_iter; + } + else { + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, + l_first->head.data, &l_iter->head.data); + } + } + } + } + } + } + } + + + + /* cleanup */ + for (i = 0; i < edge_net_len; i++) { + BM_ELEM_API_FLAG_DISABLE(edge_net[i], EDGE_NET); + /* from interp only */ + BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v1, VERT_VISIT); + BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v2, VERT_VISIT); + } + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BM_ELEM_API_FLAG_DISABLE(l_iter->e, EDGE_NET); + /* from interp only */ + BM_ELEM_API_FLAG_DISABLE(l_iter->v, VERT_VISIT); + } while ((l_iter = l_iter->next) != l_first); + + if (BLI_array_count(face_arr)) { + bmesh_face_swap_data(f, face_arr[0]); + BM_face_kill(bm, face_arr[0]); + face_arr[0] = f; + } + else { + BM_ELEM_API_FLAG_DISABLE(f, FACE_NET); + } + + for (i = 0; i < BLI_array_count(face_arr); i++) { + BM_ELEM_API_FLAG_DISABLE(face_arr[i], FACE_NET); + } + + if (r_face_arr) { + *r_face_arr = face_arr; + *r_face_arr_len = BLI_array_count(face_arr); + } + else { + if (face_arr) { + MEM_freeN(face_arr); + } + } + + return true; +} + +#undef FACE_NET +#undef VERT_VISIT +#undef EDGE_NET + +/** \} */ + + /** * \brief Vert Collapse Faces * @@ -589,22 +1137,32 @@ BMEdge *BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, /** * \brief Edge Split * - * Splits an edge. \a v should be one of the vertices in \a e and defines - * the "from" end of the splitting operation: the new vertex will be - * \a percent of the way from \a v to the other end. - * The newly created edge is attached to \a v and is returned in \a r_e. - * The original edge \a e will be the other half of the split. + * <pre> + * Before: v + * +-----------------------------------+ + * e + * + * After: v v_new (returned) + * +-----------------+-----------------+ + * r_e e + * </pre> * - * \return The new vert + * \param e The edge to split. + * \param v One of the vertices in \a e and defines the the "from" end of the splitting operation, + * the new vertex will be \a fac of the way from \a v to the other end. + * \param r_e The newly created edge. + * \return The new vertex. */ -BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float percent) +BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) { - BMVert *v_new, *v2; + BMVert *v_new, *v_other; BMFace **oldfaces = NULL; BMEdge *e_dummy; BLI_array_staticdeclare(oldfaces, 32); const bool do_mdisp = (e->l && CustomData_has_layer(&bm->ldata, CD_MDISPS)); + BLI_assert(BM_vert_in_edge(e, v) == true); + /* we need this for handling multi-res */ if (!r_e) { r_e = &e_dummy; @@ -629,22 +1187,22 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float perce } } - v2 = BM_edge_other_vert(e, v); + v_other = BM_edge_other_vert(e, v); v_new = bmesh_semv(bm, v, e, r_e); BLI_assert(v_new != NULL); + BLI_assert(BM_vert_in_edge(*r_e, v) && BM_vert_in_edge(*r_e, v_new)); + BLI_assert(BM_vert_in_edge(e, v_new) && BM_vert_in_edge(e, v_other)); - sub_v3_v3v3(v_new->co, v2->co, v->co); - madd_v3_v3v3fl(v_new->co, v->co, v_new->co, percent); + sub_v3_v3v3(v_new->co, v_other->co, v->co); + madd_v3_v3v3fl(v_new->co, v->co, v_new->co, fac); - if (r_e) { - (*r_e)->head.hflag = e->head.hflag; - BM_elem_attrs_copy(bm, bm, e, *r_e); - } + (*r_e)->head.hflag = e->head.hflag; + BM_elem_attrs_copy(bm, bm, e, *r_e); /* v->v_new->v2 */ - BM_data_interp_face_vert_edge(bm, v2, v, v_new, e, percent); - BM_data_interp_from_verts(bm, v, v2, v_new, percent); + BM_data_interp_face_vert_edge(bm, v_other, v, v_new, e, fac); + BM_data_interp_from_verts(bm, v, v_other, v_new, fac); if (do_mdisp) { int i, j; diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h index 7c81e6b750e..59aee323bba 100644 --- a/source/blender/bmesh/intern/bmesh_mods.h +++ b/source/blender/bmesh/intern/bmesh_mods.h @@ -45,6 +45,10 @@ BMFace *BM_face_split_n(BMesh *bm, BMFace *f, float cos[][3], int n, BMLoop **r_l, BMEdge *example); +bool BM_face_split_edgenet(BMesh *bm, BMFace *f, + BMEdge **edge_net, const int edge_net_len, + BMFace ***r_face_arr, int *r_face_arr_len); + BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac, const bool do_del, const bool join_faces, const bool kill_degenerate_faces); BMEdge *BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 7c77302c942..74bd9110d8c 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -115,7 +115,7 @@ static BMOpDefine bmo_smooth_vert_def = { }, {{{'\0'}}}, /* no output */ bmo_smooth_vert_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC, + (BMO_OPTYPE_FLAG_NORMALS_CALC), }; /* @@ -138,7 +138,7 @@ static BMOpDefine bmo_smooth_laplacian_vert_def = { }, {{{'\0'}}}, /* no output */ bmo_smooth_laplacian_vert_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC, + (BMO_OPTYPE_FLAG_NORMALS_CALC), }; /* @@ -154,7 +154,8 @@ static BMOpDefine bmo_recalc_face_normals_def = { }, {{{'\0'}}}, /* no output */ bmo_recalc_face_normals_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC), }; /* @@ -180,7 +181,8 @@ static BMOpDefine bmo_region_extend_def = { {{'\0'}}, }, bmo_region_extend_exec, - BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -201,7 +203,10 @@ static BMOpDefine bmo_rotate_edges_def = { {{'\0'}}, }, bmo_rotate_edges_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -218,7 +223,8 @@ static BMOpDefine bmo_reverse_faces_def = { }, {{{'\0'}}}, /* no output */ bmo_reverse_faces_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC), }; /* @@ -240,7 +246,10 @@ static BMOpDefine bmo_bisect_edges_def = { {{'\0'}}, }, bmo_bisect_edges_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -266,7 +275,9 @@ static BMOpDefine bmo_mirror_def = { {{'\0'}}, }, bmo_mirror_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -291,7 +302,7 @@ static BMOpDefine bmo_find_doubles_def = { {{'\0'}}, }, bmo_find_doubles_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NOP), }; /* @@ -309,7 +320,10 @@ static BMOpDefine bmo_remove_doubles_def = { }, {{{'\0'}}}, /* no output */ bmo_remove_doubles_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -328,7 +342,10 @@ static BMOpDefine bmo_automerge_def = { }, {{{'\0'}}}, /* no output */ bmo_automerge_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -344,7 +361,10 @@ static BMOpDefine bmo_collapse_def = { }, {{{'\0'}}}, /* no output */ bmo_collapse_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -361,7 +381,7 @@ static BMOpDefine bmo_pointmerge_facedata_def = { }, {{{'\0'}}}, /* no output */ bmo_pointmerge_facedata_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NOP), }; /* @@ -379,7 +399,7 @@ static BMOpDefine bmo_average_vert_facedata_def = { }, {{{'\0'}}}, /* no output */ bmo_average_vert_facedata_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NOP), }; /* @@ -396,7 +416,10 @@ static BMOpDefine bmo_pointmerge_def = { }, {{{'\0'}}}, /* no output */ bmo_pointmerge_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -412,7 +435,7 @@ static BMOpDefine bmo_collapse_uvs_def = { }, {{{'\0'}}}, /* no output */ bmo_collapse_uvs_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NOP), }; /* @@ -431,7 +454,10 @@ static BMOpDefine bmo_weld_verts_def = { }, {{{'\0'}}}, /* no output */ bmo_weld_verts_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -451,7 +477,7 @@ static BMOpDefine bmo_create_vert_def = { {{'\0'}}, }, bmo_create_vert_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NOP), }; /* @@ -476,7 +502,10 @@ static BMOpDefine bmo_join_triangles_def = { {{'\0'}}, }, bmo_join_triangles_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -504,7 +533,10 @@ static BMOpDefine bmo_contextual_create_def = { {{'\0'}}, }, bmo_contextual_create_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -527,7 +559,9 @@ static BMOpDefine bmo_bridge_loops_def = { {{'\0'}}, }, bmo_bridge_loops_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -551,7 +585,8 @@ static BMOpDefine bmo_grid_fill_def = { {{'\0'}}, }, bmo_grid_fill_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; @@ -573,7 +608,8 @@ static BMOpDefine bmo_holes_fill_def = { {{'\0'}}, }, bmo_holes_fill_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; @@ -596,7 +632,7 @@ static BMOpDefine bmo_face_attribute_fill_def = { {{'\0'}}, }, bmo_face_attribute_fill_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC), }; /* @@ -619,7 +655,8 @@ static BMOpDefine bmo_edgeloop_fill_def = { {{'\0'}}, }, bmo_edgeloop_fill_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; @@ -643,7 +680,8 @@ static BMOpDefine bmo_edgenet_fill_def = { {{'\0'}}, }, bmo_edgenet_fill_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -667,7 +705,7 @@ static BMOpDefine bmo_edgenet_prepare_def = { {{'\0'}}, }, bmo_edgenet_prepare_exec, - BMO_OPTYPE_FLAG_NOP, + (BMO_OPTYPE_FLAG_NOP), }; /* @@ -686,7 +724,7 @@ static BMOpDefine bmo_rotate_def = { }, {{{'\0'}}}, /* no output */ bmo_rotate_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC, + (BMO_OPTYPE_FLAG_NORMALS_CALC), }; /* @@ -704,7 +742,7 @@ static BMOpDefine bmo_translate_def = { }, {{{'\0'}}}, /* no output */ bmo_translate_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC, + (BMO_OPTYPE_FLAG_NORMALS_CALC), }; /* @@ -722,7 +760,7 @@ static BMOpDefine bmo_scale_def = { }, {{{'\0'}}}, /* no output */ bmo_scale_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC, + (BMO_OPTYPE_FLAG_NORMALS_CALC), }; @@ -742,7 +780,7 @@ static BMOpDefine bmo_transform_def = { }, {{{'\0'}}}, /* no output */ bmo_transform_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC, + (BMO_OPTYPE_FLAG_NORMALS_CALC), }; /* @@ -760,7 +798,7 @@ static BMOpDefine bmo_object_load_bmesh_def = { }, {{{'\0'}}}, /* no output */ bmo_object_load_bmesh_exec, - BMO_OPTYPE_FLAG_NOP, + (BMO_OPTYPE_FLAG_NOP), }; @@ -782,7 +820,7 @@ static BMOpDefine bmo_bmesh_to_mesh_def = { }, {{{'\0'}}}, /* no output */ bmo_bmesh_to_mesh_exec, - BMO_OPTYPE_FLAG_NOP, + (BMO_OPTYPE_FLAG_NOP), }; /* @@ -804,7 +842,7 @@ static BMOpDefine bmo_mesh_to_bmesh_def = { }, {{{'\0'}}}, /* no output */ bmo_mesh_to_bmesh_exec, - BMO_OPTYPE_FLAG_NOP, + (BMO_OPTYPE_FLAG_NOP), }; /* @@ -816,6 +854,7 @@ static BMOpDefine bmo_extrude_discrete_faces_def = { "extrude_discrete_faces", /* slots_in */ {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */ + {"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */ {{'\0'}}, }, /* slots_out */ @@ -823,7 +862,7 @@ static BMOpDefine bmo_extrude_discrete_faces_def = { {{'\0'}}, }, bmo_extrude_discrete_faces_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC), }; /* @@ -836,6 +875,7 @@ static BMOpDefine bmo_extrude_edge_only_def = { "extrude_edge_only", /* slots_in */ {{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input vertices */ + {"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */ {{'\0'}}, }, /* slots_out */ @@ -843,7 +883,7 @@ static BMOpDefine bmo_extrude_edge_only_def = { {{'\0'}}, }, bmo_extrude_edge_only_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC), }; /* @@ -855,6 +895,7 @@ static BMOpDefine bmo_extrude_vert_indiv_def = { "extrude_vert_indiv", /* slots_in */ {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */ + {"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */ {{'\0'}}, }, /* slots_out */ @@ -863,7 +904,7 @@ static BMOpDefine bmo_extrude_vert_indiv_def = { {{'\0'}}, }, bmo_extrude_vert_indiv_exec, - BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -875,6 +916,7 @@ static BMOpDefine bmo_connect_verts_def = { "connect_verts", /* slots_in */ {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, + {"faces_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, {"check_degenerate", BMO_OP_SLOT_BOOL}, /* prevent splits with overlaps & intersections */ {{'\0'}}, }, @@ -883,7 +925,9 @@ static BMOpDefine bmo_connect_verts_def = { {{'\0'}}, }, bmo_connect_verts_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -904,7 +948,9 @@ static BMOpDefine bmo_connect_verts_nonplanar_def = { {{'\0'}}, }, bmo_connect_verts_nonplanar_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -916,6 +962,8 @@ static BMOpDefine bmo_connect_vert_pair_def = { "connect_vert_pair", /* slots_in */ {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, + {"verts_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, + {"faces_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, {{'\0'}}, }, /* slots_out */ @@ -923,7 +971,9 @@ static BMOpDefine bmo_connect_vert_pair_def = { {{'\0'}}, }, bmo_connect_vert_pair_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; @@ -938,6 +988,7 @@ static BMOpDefine bmo_extrude_face_region_def = { {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* edges and faces */ {"edges_exclude", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_EMPTY}}, {"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry */ + {"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */ {{'\0'}}, }, /* slots_out */ @@ -945,7 +996,7 @@ static BMOpDefine bmo_extrude_face_region_def = { {{'\0'}}, }, bmo_extrude_face_region_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC), }; /* @@ -956,11 +1007,15 @@ static BMOpDefine bmo_dissolve_verts_def = { /* slots_in */ {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, {"use_face_split", BMO_OP_SLOT_BOOL}, + {"use_boundary_tear", BMO_OP_SLOT_BOOL}, {{'\0'}}, }, {{{'\0'}}}, /* no output */ bmo_dissolve_verts_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -979,7 +1034,10 @@ static BMOpDefine bmo_dissolve_edges_def = { {{'\0'}}, }, bmo_dissolve_edges_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -997,7 +1055,10 @@ static BMOpDefine bmo_dissolve_faces_def = { {{'\0'}}, }, bmo_dissolve_faces_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -1019,7 +1080,10 @@ static BMOpDefine bmo_dissolve_limit_def = { {{"region.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, {{'\0'}}}, bmo_dissolve_limit_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -1037,7 +1101,10 @@ static BMOpDefine bmo_dissolve_degenerate_def = { /* slots_out */ {{{'\0'}}}, bmo_dissolve_degenerate_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -1058,7 +1125,9 @@ static BMOpDefine bmo_triangulate_def = { {{'\0'}}, }, bmo_triangulate_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1075,7 +1144,10 @@ static BMOpDefine bmo_unsubdivide_def = { }, {{{'\0'}}}, /* no output */ bmo_unsubdivide_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -1113,7 +1185,10 @@ static BMOpDefine bmo_subdivide_edges_def = { {{'\0'}}, }, bmo_subdivide_edges_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -1135,7 +1210,10 @@ static BMOpDefine bmo_subdivide_edgering_def = { {{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* output faces */ {{'\0'}}}, bmo_subdivide_edgering_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -1159,7 +1237,10 @@ static BMOpDefine bmo_bisect_plane_def = { {"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, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -1176,7 +1257,9 @@ static BMOpDefine bmo_delete_def = { }, {{{'\0'}}}, /* no output */ bmo_delete_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -1191,6 +1274,7 @@ static BMOpDefine bmo_duplicate_def = { {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* destination bmesh, if NULL will use current on */ {"dest", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_BMESH}}, + {"use_select_history", BMO_OP_SLOT_BOOL}, {{'\0'}}, }, /* slots_out */ @@ -1206,7 +1290,8 @@ static BMOpDefine bmo_duplicate_def = { {{'\0'}}, }, bmo_duplicate_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1231,7 +1316,8 @@ static BMOpDefine bmo_split_def = { {{'\0'}}, }, bmo_split_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1258,7 +1344,8 @@ static BMOpDefine bmo_spin_def = { {{'\0'}}, }, bmo_spin_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; @@ -1281,7 +1368,7 @@ static BMOpDefine bmo_similar_faces_def = { {{'\0'}}, }, bmo_similar_faces_exec, - BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1303,7 +1390,7 @@ static BMOpDefine bmo_similar_edges_def = { {{'\0'}}, }, bmo_similar_edges_exec, - BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1325,7 +1412,7 @@ static BMOpDefine bmo_similar_verts_def = { {{'\0'}}, }, bmo_similar_verts_exec, - BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1342,7 +1429,7 @@ static BMOpDefine bmo_rotate_uvs_def = { }, {{{'\0'}}}, /* no output */ bmo_rotate_uvs_exec, - BMO_OPTYPE_FLAG_NOP, + (BMO_OPTYPE_FLAG_NOP), }; /* @@ -1358,7 +1445,7 @@ static BMOpDefine bmo_reverse_uvs_def = { }, {{{'\0'}}}, /* no output */ bmo_reverse_uvs_exec, - BMO_OPTYPE_FLAG_NOP, + (BMO_OPTYPE_FLAG_NOP), }; /* @@ -1375,7 +1462,7 @@ static BMOpDefine bmo_rotate_colors_def = { }, {{{'\0'}}}, /* no output */ bmo_rotate_colors_exec, - BMO_OPTYPE_FLAG_NOP, + (BMO_OPTYPE_FLAG_NOP), }; /* @@ -1391,7 +1478,7 @@ static BMOpDefine bmo_reverse_colors_def = { }, {{{'\0'}}}, /* no output */ bmo_reverse_colors_exec, - BMO_OPTYPE_FLAG_NOP, + (BMO_OPTYPE_FLAG_NOP), }; /* @@ -1413,7 +1500,9 @@ static BMOpDefine bmo_split_edges_def = { {{'\0'}}, }, bmo_split_edges_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1435,7 +1524,8 @@ static BMOpDefine bmo_create_grid_def = { {{'\0'}}, }, bmo_create_grid_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1457,7 +1547,8 @@ static BMOpDefine bmo_create_uvsphere_def = { {{'\0'}}, }, bmo_create_uvsphere_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1478,7 +1569,8 @@ static BMOpDefine bmo_create_icosphere_def = { {{'\0'}}, }, bmo_create_icosphere_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1497,7 +1589,8 @@ static BMOpDefine bmo_create_monkey_def = { {{'\0'}}, }, bmo_create_monkey_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1522,7 +1615,8 @@ static BMOpDefine bmo_create_cone_def = { {{'\0'}}, }, bmo_create_cone_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1543,7 +1637,8 @@ static BMOpDefine bmo_create_circle_def = { {{'\0'}}, }, bmo_create_circle_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1563,7 +1658,8 @@ static BMOpDefine bmo_create_cube_def = { {{'\0'}}, }, bmo_create_cube_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1580,6 +1676,7 @@ static BMOpDefine bmo_bevel_def = { {"segments", BMO_OP_SLOT_INT}, /* number of segments in bevel */ {"profile", BMO_OP_SLOT_FLT}, /* profile shape, 0->1 (.5=>round) */ {"vertex_only", BMO_OP_SLOT_BOOL}, /* only bevel vertices, not edges */ + {"material", BMO_OP_SLOT_INT}, /* material for bevel faces, -1 means get from adjacent faces */ {{'\0'}}, }, /* slots_out */ @@ -1588,7 +1685,10 @@ static BMOpDefine bmo_bevel_def = { }, bmo_bevel_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -1610,7 +1710,10 @@ static BMOpDefine bmo_beautify_fill_def = { {{'\0'}}, }, bmo_beautify_fill_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -1632,7 +1735,9 @@ static BMOpDefine bmo_triangle_fill_def = { {{'\0'}}, }, bmo_triangle_fill_exec, - BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_UNTAN_MULTIRES | + BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1652,7 +1757,8 @@ static BMOpDefine bmo_solidify_def = { {{'\0'}}, }, bmo_solidify_face_region_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1676,7 +1782,8 @@ static BMOpDefine bmo_inset_individual_def = { {{'\0'}}, }, bmo_inset_individual_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC, /* caller needs to handle BMO_OPTYPE_FLAG_SELECT_FLUSH */ + /* caller needs to handle BMO_OPTYPE_FLAG_SELECT_FLUSH */ + (BMO_OPTYPE_FLAG_NORMALS_CALC), }; /* @@ -1703,7 +1810,8 @@ static BMOpDefine bmo_inset_region_def = { {{'\0'}}, }, bmo_inset_region_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH), }; /* @@ -1732,7 +1840,9 @@ static BMOpDefine bmo_wireframe_def = { {{'\0'}}, }, bmo_wireframe_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; /* @@ -1755,7 +1865,9 @@ static BMOpDefine bmo_poke_def = { {{'\0'}}, }, bmo_poke_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; #ifdef WITH_BULLET @@ -1789,7 +1901,9 @@ static BMOpDefine bmo_convex_hull_def = { {{'\0'}}, }, bmo_convex_hull_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; #endif @@ -1816,7 +1930,9 @@ static BMOpDefine bmo_symmetrize_def = { {{'\0'}}, }, bmo_symmetrize_exec, - BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH, + (BMO_OPTYPE_FLAG_NORMALS_CALC | + BMO_OPTYPE_FLAG_SELECT_FLUSH | + BMO_OPTYPE_FLAG_SELECT_VALIDATE), }; const BMOpDefine *bmo_opdefines[] = { diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h index 7fad3a8c20e..287aafc8f9f 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api.h +++ b/source/blender/bmesh/intern/bmesh_operator_api.h @@ -182,8 +182,9 @@ typedef struct BMOpSlot { typedef enum { BMO_OPTYPE_FLAG_NOP = 0, BMO_OPTYPE_FLAG_UNTAN_MULTIRES = (1 << 0), /* switch from multires tangent space to absolute coordinates */ - BMO_OPTYPE_FLAG_NORMALS_CALC = (1 << 1), /*switch from multires tangent space to absolute coordinates*/ - BMO_OPTYPE_FLAG_SELECT_FLUSH = (1 << 2) /*switch from multires tangent space to absolute coordinates*/ + BMO_OPTYPE_FLAG_NORMALS_CALC = (1 << 1), + BMO_OPTYPE_FLAG_SELECT_FLUSH = (1 << 2), + BMO_OPTYPE_FLAG_SELECT_VALIDATE = (1 << 3), } BMOpTypeFlag; typedef struct BMOperator { @@ -337,7 +338,8 @@ void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, const char htype, cons void BMO_mesh_selected_remap(BMesh *bm, BMOpSlot *slot_vert_map, BMOpSlot *slot_edge_map, - BMOpSlot *slot_face_map); + BMOpSlot *slot_face_map, + const bool check_select); /* 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, \ diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c index 7f872613896..b041c010c22 100644 --- a/source/blender/bmesh/intern/bmesh_operators.c +++ b/source/blender/bmesh/intern/bmesh_operators.c @@ -605,7 +605,8 @@ 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) + BMOpSlot *slot_face_map, + const bool check_select) { if (bm->selected.first) { BMEditSelection *ese, *ese_next; @@ -623,7 +624,7 @@ void BMO_mesh_selected_remap(BMesh *bm, 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))) + (check_select && (BM_elem_flag_test(ese->ele, BM_ELEM_SELECT) == false)))) { BLI_remlink(&bm->selected, ese); MEM_freeN(ese); @@ -764,6 +765,9 @@ void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_ BMOpSlot *output = BMO_slot_get(slot_args, slot_name); int totelement = 0, i = 0; + BLI_assert(output->slot_type == BMO_OP_SLOT_ELEMENT_BUF); + BLI_assert(((output->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype); + if (htype & BM_VERT) totelement += bm->totvert; if (htype & BM_EDGE) totelement += bm->totedge; if (htype & BM_FACE) totelement += bm->totface; @@ -811,7 +815,11 @@ static void bmo_slot_buffer_from_hflag(BMesh *bm, BMOperator *op, BMOpSlot slot_ { BMOpSlot *output = BMO_slot_get(slot_args, slot_name); int totelement = 0, i = 0; - const int respecthide = (op->flag & BMO_FLAG_RESPECT_HIDE) != 0; + const bool respecthide = ((op->flag & BMO_FLAG_RESPECT_HIDE) != 0) && ((hflag & BM_ELEM_HIDDEN) == 0); + + BLI_assert(output->slot_type == BMO_OP_SLOT_ELEMENT_BUF); + BLI_assert(((output->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype); + BLI_assert((output->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) == 0); if (test_for_enabled) totelement = BM_mesh_elem_hflag_count_enabled(bm, htype, hflag, respecthide); @@ -951,14 +959,15 @@ static void bmo_slot_buffer_from_flag(BMesh *bm, BMOperator *op, BLI_assert(op->slots_in == slot_args || op->slots_out == slot_args); + BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF); + BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype); + BLI_assert((slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) == 0); + if (test_for_enabled) totelement = BMO_mesh_enabled_flag_count(bm, htype, oflag); else totelement = BMO_mesh_disabled_flag_count(bm, htype, oflag); - BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF); - BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype); - if (totelement) { BMIter iter; BMHeader *ele; @@ -1034,6 +1043,7 @@ void BMO_slot_buffer_hflag_enable(BMesh *bm, BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF); BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype); + BLI_assert((slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) == 0); for (i = 0; i < slot->len; i++, data++) { if (!(htype & (*data)->head.htype)) @@ -1654,7 +1664,6 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, char slot_name[64] = {0}; int i, type; bool noslot, state; - char htype; /* basic useful info to help find where bmop formatting strings fail */ @@ -1729,9 +1738,8 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, break; case 'm': { - int size, c; - - c = NEXT_CHAR(fmt); + int size; + const char c = NEXT_CHAR(fmt); fmt++; if (c == '3') size = 3; @@ -1800,22 +1808,23 @@ 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; + char htype = 0; - htype = 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 = true; - break; - } - if (stop) { + char htype_set; + const char c = NEXT_CHAR(fmt); + if (c == 'f') htype_set = BM_FACE; + else if (c == 'e') htype_set = BM_EDGE; + else if (c == 'v') htype_set = BM_VERT; + else { break; } + if (UNLIKELY(htype & htype_set)) { + GOTO_ERROR("htype duplicated"); + } + + htype |= htype_set; fmt++; } diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index 307c391a406..9a0fce9dba0 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -854,7 +854,7 @@ void BM_face_triangulate(BMesh *bm, BMFace *f, l_tri[1]->v, l_tri[2]->v}; - f_new = BM_face_create_verts(bm, v_tri, 3, f, false, true); + f_new = BM_face_create_verts(bm, v_tri, 3, f, BM_CREATE_NOP, true); l_new = BM_FACE_FIRST_LOOP(f_new); BLI_assert(v_tri[0] == l_new->v); diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h index 731c36437d5..102a677943b 100644 --- a/source/blender/bmesh/intern/bmesh_private.h +++ b/source/blender/bmesh/intern/bmesh_private.h @@ -64,7 +64,8 @@ enum { _FLAG_JF = (1 << 0), /* join faces */ _FLAG_MF = (1 << 1), /* make face */ _FLAG_MV = (1 << 1), /* make face, vertex */ - _FLAG_OVERLAP = (1 << 2) /* general overlap flag */ + _FLAG_OVERLAP = (1 << 2), /* general overlap flag */ + _FLAG_WALK = (1 << 3), /* general walk flag (keep clean) */ }; #define BM_ELEM_API_FLAG_ENABLE(element, f) { ((element)->head.api_flag |= (f)); } (void)0 diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 606e93d4a85..685e5443583 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -183,6 +183,26 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) } /** + * Check if verts share a face. + */ +bool BM_vert_pair_share_face_check( + BMVert *v_a, BMVert *v_b) +{ + if (v_a->e && v_b->e) { + BMIter iter; + BMFace *f; + + BM_ITER_ELEM (f, &iter, v_a, BM_FACES_OF_VERT) { + if (BM_vert_in_face(f, v_b)) { + return true; + } + } + } + + return false; +} + +/** * Given 2 verts, find the smallest face they share and give back both loops. */ BMFace *BM_vert_pair_share_face_by_len( diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 21d20976901..0d47633dc73 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -27,29 +27,31 @@ * \ingroup bmesh */ -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); - -bool BM_edge_in_face(BMEdge *e, BMFace *f); -BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l); - -BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v); -BLI_INLINE bool BM_verts_in_edge(const BMVert *v1, const BMVert *v2, const BMEdge *e); - -float BM_edge_calc_length(BMEdge *e); -float BM_edge_calc_length_squared(BMEdge *e); -bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb); -bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb); -BLI_INLINE BMVert *BM_edge_other_vert(BMEdge *e, const BMVert *v); -BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l); -BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v); -BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v); -BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v); -BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v); -BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step); -BMLoop *BM_vert_find_first_loop(BMVert *v); - +bool BM_vert_in_face(BMFace *f, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int BM_verts_in_face_count(BMFace *f, BMVert **varr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_verts_in_face(BMFace *f, BMVert **varr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); + +bool BM_edge_in_face(BMEdge *e, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); + +BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BLI_INLINE bool BM_verts_in_edge(const BMVert *v1, const BMVert *v2, const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); + +float BM_edge_calc_length(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_edge_calc_length_squared(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb) ATTR_NONNULL(); +bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb) ATTR_NONNULL(); +BLI_INLINE BMVert *BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *BM_vert_find_first_loop(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); + +bool BM_vert_pair_share_face_check( + BMVert *v_a, BMVert *v_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMFace *BM_vert_pair_share_face_by_len( BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, @@ -59,95 +61,95 @@ BMFace *BM_vert_pair_share_face_by_angle( BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent) ATTR_NONNULL(); -int BM_vert_edge_count_nonwire(BMVert *v); -int BM_vert_edge_count(BMVert *v); -int BM_edge_face_count(BMEdge *e); -int BM_vert_face_count(BMVert *v); -BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e); +int BM_vert_edge_count_nonwire(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int BM_vert_edge_count(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int BM_edge_face_count(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int BM_vert_face_count(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_vert_is_edge_pair(BMVert *v); -bool BM_vert_is_wire(const BMVert *v); -BLI_INLINE bool BM_edge_is_wire(const BMEdge *e); +bool BM_vert_is_edge_pair(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_vert_is_manifold(const BMVert *v); -BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e); -bool BM_vert_is_boundary(const BMVert *v); -BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e); -BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e); -bool BM_edge_is_convex(const BMEdge *e); +bool BM_vert_is_manifold(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_vert_is_boundary(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_edge_is_convex(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_loop_is_convex(const BMLoop *l); -BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b); +bool BM_loop_is_convex(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -float BM_loop_calc_face_angle(BMLoop *l); -void BM_loop_calc_face_normal(BMLoop *l, float r_normal[3]); +float BM_loop_calc_face_angle(BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void BM_loop_calc_face_normal(BMLoop *l, float r_normal[3]) ATTR_NONNULL(); void BM_loop_calc_face_direction(BMLoop *l, float r_normal[3]); void BM_loop_calc_face_tangent(BMLoop *l, float r_tangent[3]); -float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback); -float BM_edge_calc_face_angle(const BMEdge *e); -float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback); -float BM_edge_calc_face_angle_signed(const BMEdge *e); -void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3]); +float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_edge_calc_face_angle(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_edge_calc_face_angle_signed(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3]) ATTR_NONNULL(); -float BM_vert_calc_edge_angle(BMVert *v); -float BM_vert_calc_shell_factor(BMVert *v); -float BM_vert_calc_shell_factor_ex(BMVert *v, const char hflag); -float BM_vert_calc_mean_tagged_edge_length(BMVert *v); +float BM_vert_calc_edge_angle(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_vert_calc_shell_factor(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_vert_calc_shell_factor_ex(BMVert *v, const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_vert_calc_mean_tagged_edge_length(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -BMLoop *BM_face_find_shortest_loop(BMFace *f); -BMLoop *BM_face_find_longest_loop(BMFace *f); +BMLoop *BM_face_find_shortest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2); -BMEdge *BM_edge_find_double(BMEdge *e); +BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface); +bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) ATTR_NONNULL(1); -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_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -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); +bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +bool BM_face_exists_overlap_subset(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -int BM_face_share_face_count(BMFace *f_a, BMFace *f_b); -int BM_face_share_edge_count(BMFace *f1, BMFace *f2); +int BM_face_share_face_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int BM_face_share_edge_count(BMFace *f1, BMFace *f2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_face_share_face_check(BMFace *f1, BMFace *f2); -bool BM_face_share_edge_check(BMFace *f1, BMFace *f2); -bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2); -bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2); -bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2); +bool BM_face_share_face_check(BMFace *f1, BMFace *f2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_face_share_edge_check(BMFace *f1, BMFace *f2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -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); +BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2); +void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2) ATTR_NONNULL(); void BM_edge_ordered_verts_ex(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2, - const BMLoop *edge_loop); + const BMLoop *edge_loop) ATTR_NONNULL(); -bool BM_vert_is_all_edge_flag_test(const BMVert *v, const char hflag, const bool respect_hide); -bool BM_vert_is_all_face_flag_test(const BMVert *v, const char hflag, const bool respect_hide); -bool BM_edge_is_all_face_flag_test(const BMEdge *e, const char hflag, const bool respect_hide); +bool BM_vert_is_all_edge_flag_test(const BMVert *v, const char hflag, const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_vert_is_all_face_flag_test(const BMVert *v, const char hflag, const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_edge_is_all_face_flag_test(const BMEdge *e, const char hflag, const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag); -bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag); -bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag); +bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_face_is_normal_valid(const BMFace *f); +bool BM_face_is_normal_valid(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -float BM_mesh_calc_volume(BMesh *bm, bool is_signed); +float BM_mesh_calc_volume(BMesh *bm, bool is_signed) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2], BMElemFilterFunc filter_fn, void *user_data, - const char hflag_test, const char htype_step); + const char hflag_test, const char htype_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3); int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int (**r_group_index)[2], BMElemFilterFunc filter_fn, void *user_data, - const char hflag_test); + const char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3); /* not really any good place to put this */ -float bmesh_subd_falloff_calc(const int falloff, float val); +float bmesh_subd_falloff_calc(const int falloff, float val) ATTR_WARN_UNUSED_RESULT; #include "bmesh_queries_inline.h" diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h index 8e721ddd229..d2ad655ae75 100644 --- a/source/blender/bmesh/intern/bmesh_structure.h +++ b/source/blender/bmesh/intern/bmesh_structure.h @@ -39,39 +39,37 @@ * descriptive comments. but seriously, don't use this stuff. */ -struct ListBase; - /* LOOP CYCLE MANAGEMENT */ -bool bmesh_loop_validate(BMFace *f); +bool bmesh_loop_validate(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* DISK CYCLE MANAGMENT */ -void bmesh_disk_edge_append(BMEdge *e, BMVert *v); -void bmesh_disk_edge_remove(BMEdge *e, BMVert *v); -BLI_INLINE BMEdge *bmesh_disk_edge_next_safe(const BMEdge *e, const BMVert *v); -BLI_INLINE BMEdge *bmesh_disk_edge_prev_safe(const BMEdge *e, const BMVert *v); -BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v); -BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v); -int bmesh_disk_facevert_count(const BMVert *v); -BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v); -BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v); +void bmesh_disk_edge_append(BMEdge *e, BMVert *v) ATTR_NONNULL(); +void bmesh_disk_edge_remove(BMEdge *e, BMVert *v) ATTR_NONNULL(); +BLI_INLINE BMEdge *bmesh_disk_edge_next_safe(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BLI_INLINE BMEdge *bmesh_disk_edge_prev_safe(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* RADIAL CYCLE MANAGMENT */ -void bmesh_radial_append(BMEdge *e, BMLoop *l); -void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e); +void bmesh_radial_append(BMEdge *e, BMLoop *l) ATTR_NONNULL(); +void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) ATTR_NONNULL(1); /* note: * bmesh_radial_loop_next(BMLoop *l) / prev. * just use member access l->radial_next, l->radial_prev now */ -int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v); -BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v); -BMLoop *bmesh_radial_faceloop_find_next(const BMLoop *l, const BMVert *v); -BMLoop *bmesh_radial_faceloop_find_vert(const BMFace *f, const BMVert *v); -bool bmesh_radial_validate(int radlen, BMLoop *l); +int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *bmesh_radial_faceloop_find_next(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *bmesh_radial_faceloop_find_vert(const BMFace *f, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool bmesh_radial_validate(int radlen, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* EDGE UTILITIES */ -bool bmesh_edge_swapverts(BMEdge *e, BMVert *orig, BMVert *newv); /* relink edge */ -BMEdge *bmesh_disk_edge_exists(const BMVert *v1, const BMVert *v2); -bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v); +bool bmesh_edge_swapverts(BMEdge *e, BMVert *v_orig, BMVert *v_new) ATTR_NONNULL(); +BMEdge *bmesh_disk_edge_exists(const BMVert *v1, const BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); #include "intern/bmesh_structure_inline.h" diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c index 8f74e98e762..6a5efbe70ac 100644 --- a/source/blender/bmesh/intern/bmesh_walkers.c +++ b/source/blender/bmesh/intern/bmesh_walkers.c @@ -47,7 +47,7 @@ * * basic design pattern: the walker step function goes through it's * list of possible choices for recursion, and recurses (by pushing a new state) - * using the first non-visited one. this choise is the flagged as visited using + * using the first non-visited one. This choice is the flagged as visited using * the ghash. each step may push multiple new states onto the worklist at once. * * - Walkers use tool flags, not header flags. diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 07a2e674863..213a0830e63 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -40,6 +40,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) const int seg = BMO_slot_int_get(op->slots_in, "segments"); const bool vonly = BMO_slot_bool_get(op->slots_in, "vertex_only"); const float profile = BMO_slot_float_get(op->slots_in, "profile"); + const int material = BMO_slot_int_get(op->slots_in, "material"); if (offset > 0) { BMOIter siter; @@ -60,7 +61,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) } } - BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, false, NULL, -1); + BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, false, NULL, -1, material); BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); } diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index 9e9cd0d66e2..e4417477e76 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -119,7 +119,7 @@ static void bm_bridge_best_rotation(struct BMEdgeLoopStore *el_store_a, struct B } if (el_b_best) { - BLI_rotatelist_first(lb_b, el_b_best); + BLI_listbase_rotate_first(lb_b, el_b_best); } } @@ -272,7 +272,7 @@ static void bridge_loop_pair(BMesh *bm, const int len_b = BM_edgeloop_length_get(el_store_b); ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); LinkData *el_b = BLI_rfindlink(lb_b, mod_i(twist_offset, len_b)); - BLI_rotatelist_first(lb_b, el_b); + BLI_listbase_rotate_first(lb_b, el_b); } } diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c index 4cf6e82fc8e..0213329118c 100644 --- a/source/blender/bmesh/operators/bmo_connect.c +++ b/source/blender/bmesh/operators/bmo_connect.c @@ -36,54 +36,68 @@ #include "intern/bmesh_operators_private.h" /* own include */ #define VERT_INPUT 1 + #define EDGE_OUT 1 -#define FACE_TAG 2 +/* Edge spans 2 VERT_INPUT's, its a nop, + * but include in "edges.out" */ +#define EDGE_OUT_ADJ 2 + +#define FACE_TAG 2 +#define FACE_EXCLUDE 4 static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenerate) { - BMLoop *(*loops_split)[2] = BLI_array_alloca(loops_split, f->len); + const unsigned pair_split_max = f->len / 2; + BMLoop *(*loops_split)[2] = BLI_array_alloca(loops_split, pair_split_max); STACK_DECLARE(loops_split); - BMVert *(*verts_pair)[2] = BLI_array_alloca(verts_pair, f->len); + BMVert *(*verts_pair)[2] = BLI_array_alloca(verts_pair, pair_split_max); STACK_DECLARE(verts_pair); - BMIter liter; - BMFace *f_new; - BMLoop *l; - BMLoop *l_last; + BMLoop *l_tag_prev = NULL, *l_tag_first = NULL; + BMLoop *l_iter, *l_first; unsigned int i; - STACK_INIT(loops_split, f->len); - STACK_INIT(verts_pair, f->len); + STACK_INIT(loops_split, pair_split_max); + STACK_INIT(verts_pair, pair_split_max); - l_last = NULL; - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (BMO_elem_flag_test(bm, l->v, VERT_INPUT)) { - if (!l_last) { - l_last = l; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BMO_elem_flag_test(bm, l_iter->v, VERT_INPUT) && + /* ensure this vertex isnt part of a contiguous group */ + ((BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) || + (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0))) + { + if (!l_tag_prev) { + l_tag_prev = l_tag_first = l_iter; continue; } - if (!BM_loop_is_adjacent(l_last, l)) { + if (!BM_loop_is_adjacent(l_tag_prev, l_iter)) { BMEdge *e; - e = BM_edge_exists(l_last->v, l->v); + e = BM_edge_exists(l_tag_prev->v, l_iter->v); if (e == NULL || !BMO_elem_flag_test(bm, e, EDGE_OUT)) { BMLoop **l_pair = STACK_PUSH_RET(loops_split); - l_pair[0] = l_last; - l_pair[1] = l; + l_pair[0] = l_tag_prev; + l_pair[1] = l_iter; } } - l_last = l; + + l_tag_prev = l_iter; } - } + } while ((l_iter = l_iter->next) != l_first); if (STACK_SIZE(loops_split) == 0) { return 0; } - if (STACK_SIZE(loops_split) > 1) { + if (!BM_loop_is_adjacent(l_tag_first, l_tag_prev) && + /* ensure we don't add the same pair twice */ + (((loops_split[0][0] == l_tag_first) && + (loops_split[0][1] == l_tag_prev)) == 0)) + { BMLoop **l_pair = STACK_PUSH_RET(loops_split); - l_pair[0] = loops_split[STACK_SIZE(loops_split) - 2][1]; - l_pair[1] = loops_split[0][0]; + l_pair[0] = l_tag_first; + l_pair[1] = l_tag_prev; } if (check_degenerate) { @@ -105,6 +119,7 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera } for (i = 0; i < STACK_SIZE(verts_pair); i++) { + BMFace *f_new; BMLoop *l_new; BMLoop *l_a, *l_b; @@ -134,7 +149,6 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) { BMOIter siter; - BMIter iter; BMVert *v; BMFace *f; const bool check_degenerate = BMO_slot_bool_get(op->slots_in, "check_degenerate"); @@ -142,16 +156,35 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) BLI_LINKSTACK_INIT(faces); + /* tag so we won't touch ever (typically hidden faces) */ + BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces_exclude", BM_FACE, FACE_EXCLUDE); + /* add all faces connected to verts */ BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { + BMIter iter; + BMLoop *l_iter; + BMO_elem_flag_enable(bm, v, VERT_INPUT); - BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f, FACE_TAG)) { - BMO_elem_flag_enable(bm, f, FACE_TAG); - if (f->len > 3) { - BLI_LINKSTACK_PUSH(faces, f); + BM_ITER_ELEM (l_iter, &iter, v, BM_LOOPS_OF_VERT) { + f = l_iter->f; + if (!BMO_elem_flag_test(bm, f, FACE_EXCLUDE)) { + if (!BMO_elem_flag_test(bm, f, FACE_TAG)) { + BMO_elem_flag_enable(bm, f, FACE_TAG); + if (f->len > 3) { + BLI_LINKSTACK_PUSH(faces, f); + } } } + + /* flag edges even if these are not newly created + * this way cut-pairs that include co-linear edges will get + * predictable output. */ + if (BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT)) { + BMO_elem_flag_enable(bm, l_iter->prev->e, EDGE_OUT_ADJ); + } + if (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT)) { + BMO_elem_flag_enable(bm, l_iter->e, EDGE_OUT_ADJ); + } } } @@ -164,5 +197,5 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) BLI_LINKSTACK_FREE(faces); - 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, "edges.out", BM_EDGE, EDGE_OUT | EDGE_OUT_ADJ); } diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c index b497ab2f693..a0acf6ed2c5 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.c +++ b/source/blender/bmesh/operators/bmo_connect_pair.c @@ -51,6 +51,15 @@ #define CONNECT_EPS 0.0001f #define VERT_OUT 1 +#define VERT_EXCLUDE 2 + +/* typically hidden faces */ +#define FACE_EXCLUDE 2 + +#define FACE_WALK_TEST(f) (CHECK_TYPE_INLINE(f, BMFace *), \ + BMO_elem_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0) +#define VERT_WALK_TEST(v) (CHECK_TYPE_INLINE(v, BMVert *), \ + BMO_elem_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0) // #define DEBUG_PRINT @@ -59,6 +68,9 @@ typedef struct PathContext { float matrix[3][3]; float axis_sep; + /* only to access BMO flags */ + BMesh *bm_bmoflag; + BMVert *v_a, *v_b; BLI_mempool *link_pool; @@ -134,7 +146,7 @@ static void state_calc_co_pair(const PathContext *pc, static bool state_link_find(PathLinkState *state, BMElem *ele) { PathLink *link = state->link_last; - BLI_assert(ELEM3(ele->head.htype, BM_VERT, BM_EDGE, BM_FACE)); + BLI_assert(ELEM(ele->head.htype, BM_VERT, BM_EDGE, BM_FACE)); if (link) { do { if (link->ele == ele) { @@ -204,8 +216,9 @@ static void state_link_add(PathContext *pc, PathLinkState *state, state->link_last = step_new; } -static PathLinkState *state_dupe_add(PathContext *pc, - PathLinkState *state, const PathLinkState *state_orig) +static PathLinkState *state_dupe_add( + PathContext *pc, + PathLinkState *state, const PathLinkState *state_orig) { state = MEM_mallocN(sizeof(*state), __func__); *state = *state_orig; @@ -214,16 +227,19 @@ static PathLinkState *state_dupe_add(PathContext *pc, } /* walk around the face edges */ -static PathLinkState *state_step__face_edges(PathContext *pc, - PathLinkState *state, const PathLinkState *state_orig, - BMLoop *l_iter, BMLoop *l_last) +static PathLinkState *state_step__face_edges( + PathContext *pc, + PathLinkState *state, const PathLinkState *state_orig, + BMLoop *l_iter, BMLoop *l_last) { do { if (state_isect_co_pair(pc, l_iter->v->co, l_iter->next->v->co)) { BMElem *ele_next = (BMElem *)l_iter->e; BMElem *ele_next_from = (BMElem *)l_iter->f; - if (state_link_find(state, ele_next) == false) { + if (FACE_WALK_TEST((BMFace *)ele_next_from) && + (state_link_find(state, ele_next) == false)) + { if (state_orig->link_last != state->link_last) { state = state_dupe_add(pc, state, state_orig); } @@ -235,16 +251,19 @@ static PathLinkState *state_step__face_edges(PathContext *pc, } /* walk around the face verts */ -static PathLinkState *state_step__face_verts(PathContext *pc, - PathLinkState *state, const PathLinkState *state_orig, - BMLoop *l_iter, BMLoop *l_last) +static PathLinkState *state_step__face_verts( + PathContext *pc, + PathLinkState *state, const PathLinkState *state_orig, + BMLoop *l_iter, BMLoop *l_last) { do { if (state_isect_co_exact(pc, l_iter->v->co)) { BMElem *ele_next = (BMElem *)l_iter->v; BMElem *ele_next_from = (BMElem *)l_iter->f; - if (state_link_find(state, ele_next) == false) { + if (FACE_WALK_TEST((BMFace *)ele_next_from) && + state_link_find(state, ele_next) == false) + { if (state_orig->link_last != state->link_last) { state = state_dupe_add(pc, state, state_orig); } @@ -268,7 +287,9 @@ static bool state_step(PathContext *pc, PathLinkState *state) BMLoop *l_start; BM_ITER_ELEM (l_start, &liter, e, BM_LOOPS_OF_EDGE) { - if (l_start->f != ele_from) { + if ((l_start->f != ele_from) && + FACE_WALK_TEST(l_start->f)) + { /* very similar to block below */ if (BM_vert_in_face(l_start->f, pc->v_b)) { if (state_orig.link_last != state->link_last) { @@ -295,7 +316,9 @@ static bool state_step(PathContext *pc, PathLinkState *state) BMLoop *l_start; BM_ITER_ELEM (l_start, &liter, v, BM_LOOPS_OF_VERT) { - if (l_start->f != ele_from) { + if ((l_start->f != ele_from) && + FACE_WALK_TEST(l_start->f)) + { /* very similar to block above */ if (BM_vert_in_face(l_start->f, pc->v_b)) { BMElem *ele_next = (BMElem *)pc->v_b; @@ -324,8 +347,10 @@ static bool state_step(PathContext *pc, PathLinkState *state) BMIter eiter; BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if ((BMElem *)e != ele_from) { - BMVert *v_other = BM_edge_other_vert(e, v); + BMVert *v_other = BM_edge_other_vert(e, v); + if (((BMElem *)e != ele_from) && + VERT_WALK_TEST(v_other)) + { if (v_other == pc->v_b) { BMElem *ele_next = (BMElem *)pc->v_b; BMElem *ele_next_from = (BMElem *)e; @@ -371,6 +396,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) return; } + pc.bm_bmoflag = bm; pc.v_a = ((BMVert **)op_verts_slot->data.p)[0]; pc.v_b = ((BMVert **)op_verts_slot->data.p)[1]; @@ -384,6 +410,10 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) printf("%s: v_b: %d\n", __func__, BM_elem_index_get(pc.v_b)); #endif + /* tag so we won't touch ever (typically hidden faces) */ + BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces_exclude", BM_FACE, FACE_EXCLUDE); + BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts_exclude", BM_VERT, VERT_EXCLUDE); + /* setup context */ { BLI_listbase_clear(&pc.state_lb); @@ -468,9 +498,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) BLI_remlink(&pc.state_lb, state); MEM_freeN(state); } - else { - found_all = false; - } + found_all = false; } else { /* didn't reach the end, remove it, @@ -481,6 +509,11 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) } if (found_all) { +#ifdef DEBUG + for (state = pc.state_lb.first; state; state = state->next) { + BLI_assert(state->link_last->ele == (BMElem *)pc.v_b); + } +#endif break; } } @@ -533,7 +566,8 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) * always connect even when resulting faces are degenerate [#39418] */ BMOperator op_sub; BMO_op_initf(bm, &op_sub, 0, - "connect_verts verts=%fv", VERT_OUT); + "connect_verts verts=%fv faces_exclude=%s", + VERT_OUT, op, "faces_exclude"); BMO_op_exec(bm, &op_sub); BMO_slot_copy(&op_sub, slots_out, "edges.out", op, slots_out, "edges.out"); diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index 209ca30ddc3..8cd9ee14bcb 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -29,6 +29,7 @@ #include "MEM_guardedalloc.h" #include "BLI_array.h" +#include "BLI_stack.h" #include "BLI_math.h" #include "bmesh.h" @@ -51,6 +52,7 @@ #define VERT_MARK_PAIR 4 #define VERT_TAG 2 #define VERT_ISGC 8 +#define VERT_MARK_TEAR 16 @@ -85,15 +87,20 @@ static bool UNUSED_FUNCTION(check_hole_in_region) (BMesh *bm, BMFace *f) return true; } -static void bm_face_split(BMesh *bm, const short oflag) +static void bm_face_split(BMesh *bm, const short oflag, bool use_edge_delete) { + BLI_Stack *edge_delete_verts; BMIter iter; BMVert *v; - BMIter liter; + if (use_edge_delete) { + edge_delete_verts = BLI_stack_new(sizeof(BMVert *), __func__); + } + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BMO_elem_flag_test(bm, v, oflag)) { if (BM_vert_is_edge_pair(v) == false) { + BMIter liter; BMLoop *l; BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { if (l->f->len > 3) { @@ -104,8 +111,23 @@ static void bm_face_split(BMesh *bm, const short oflag) } } } + + if (use_edge_delete) { + BLI_stack_push(edge_delete_verts, &v); + } + } + } + } + + if (use_edge_delete) { + while (!BLI_stack_is_empty(edge_delete_verts)) { + /* remove surrounding edges & faces */ + BLI_stack_pop(edge_delete_verts, &v); + while (v->e) { + BM_edge_kill(bm, v->e); } } + BLI_stack_free(edge_delete_verts); } } @@ -268,7 +290,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) } } - bm_face_split(bm, VERT_TAG); + bm_face_split(bm, VERT_TAG, false); } if (use_verts) { @@ -345,13 +367,29 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) BMFace *act_face = bm->act_face; const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split"); + const bool use_boundary_tear = BMO_slot_bool_get(op->slots_in, "use_boundary_tear"); BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { BMO_elem_flag_enable(bm, v, VERT_MARK | VERT_ISGC); } if (use_face_split) { - bm_face_split(bm, VERT_MARK); + bm_face_split(bm, VERT_MARK, false); + } + + if (use_boundary_tear) { + BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { + if (!BM_vert_is_edge_pair(v)) { + BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { + if (BM_edge_is_boundary(e)) { + BMO_elem_flag_enable(bm, v, VERT_MARK_TEAR); + break; + } + } + } + } + + bm_face_split(bm, VERT_MARK_TEAR, true); } BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c index 794c688b26b..cd5592f08c9 100644 --- a/source/blender/bmesh/operators/bmo_dupe.c +++ b/source/blender/bmesh/operators/bmo_dupe.c @@ -183,6 +183,7 @@ static BMFace *bmo_face_copy(BMOperator *op, */ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) { + const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history"); BMVert *v = NULL, *v2; BMEdge *e = NULL; @@ -285,6 +286,16 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) /* free pointer hashes */ BLI_ghash_free(vhash, NULL, NULL); BLI_ghash_free(ehash, NULL, NULL); + + if (use_select_history) { + BLI_assert(bm_src == bm_dst); + BMO_mesh_selected_remap( + bm_dst, + slot_vert_map_out, + slot_edge_map_out, + slot_face_map_out, + false); + } } /** diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c index 0c5de590ccf..4423123f65e 100644 --- a/source/blender/bmesh/operators/bmo_edgenet.c +++ b/source/blender/bmesh/operators/bmo_edgenet.c @@ -179,11 +179,11 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) if (!count) { edges1 = edges; - BLI_array_length_set(edges1, BLI_array_count(edges)); + BLI_array_count_set(edges1, BLI_array_count(edges)); } else { edges2 = edges; - BLI_array_length_set(edges2, BLI_array_count(edges)); + BLI_array_count_set(edges2, BLI_array_count(edges)); } BLI_array_empty(edges); diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c index 510c3ae0078..88b53b63abb 100644 --- a/source/blender/bmesh/operators/bmo_extrude.c +++ b/source/blender/bmesh/operators/bmo_extrude.c @@ -53,9 +53,16 @@ enum { void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) { + const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history"); + GHash *select_history_map = NULL; + BMOIter siter; BMFace *f_org; + if (use_select_history) { + select_history_map = BM_select_history_map_create(bm); + } + BMO_ITER (f_org, &siter, op->slots_in, "faces", BM_FACE) { BMFace *f_new; BMLoop *l_org, *l_org_first; @@ -66,6 +73,14 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) f_new = BM_face_copy(bm, bm, f_org, true, true); BMO_elem_flag_enable(bm, f_new, EXT_KEEP); + if (select_history_map) { + BMEditSelection *ese; + ese = BLI_ghash_lookup(select_history_map, f_org); + if (ese) { + ese->ele = (BMElem *)f_new; + } + } + l_org = l_org_first = BM_FACE_FIRST_LOOP(f_org); l_new = BM_FACE_FIRST_LOOP(f_new); @@ -85,10 +100,28 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) BM_elem_attrs_copy(bm, bm, l_org->next, l_side_iter); l_side_iter = l_side_iter->next; BM_elem_attrs_copy(bm, bm, l_org, l_side_iter); l_side_iter = l_side_iter->next; BM_elem_attrs_copy(bm, bm, l_org, l_side_iter); + + if (select_history_map) { + BMEditSelection *ese; + + ese = BLI_ghash_lookup(select_history_map, l_org->v); + if (ese) { + ese->ele = (BMElem *)l_new->v; + } + ese = BLI_ghash_lookup(select_history_map, l_org->e); + if (ese) { + ese->ele = (BMElem *)l_new->e; + } + } + } while (((l_new = l_new->next), (l_org = l_org->next)) != l_org_first); } + if (select_history_map) { + BLI_ghash_free(select_history_map, NULL, NULL); + } + BMO_op_callf(bm, op->flag, "delete geom=%ff context=%i", EXT_DEL, DEL_ONLYFACES); @@ -157,7 +190,11 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op) BMO_elem_flag_enable(bm, e->v2, EXT_INPUT); } - BMO_op_initf(bm, &dupeop, op->flag, "duplicate geom=%fve", EXT_INPUT); + BMO_op_initf( + bm, &dupeop, op->flag, + "duplicate geom=%fve use_select_history=%b", + EXT_INPUT, BMO_slot_bool_get(op->slots_in, "use_select_history")); + BMO_op_exec(bm, &dupeop); /* disable root flag on all new skin nodes */ @@ -205,10 +242,16 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op) void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) { + const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history"); BMOIter siter; BMVert *v, *dupev; BMEdge *e; const bool has_vskin = CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN); + GHash *select_history_map = NULL; + + if (use_select_history) { + select_history_map = BM_select_history_map_create(bm); + } 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, BM_CREATE_NOP); @@ -217,6 +260,14 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) if (has_vskin) bm_extrude_disable_skin_root(bm, v); + if (select_history_map) { + BMEditSelection *ese; + ese = BLI_ghash_lookup(select_history_map, v); + if (ese) { + ese->ele = (BMElem *)dupev; + } + } + /* not essential, but ensures face normals from extruded edges are contiguous */ if (BM_vert_is_wire_endpoint(v)) { if (v->e->v1 == v) { @@ -228,6 +279,10 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) BMO_elem_flag_enable(bm, e, EXT_KEEP); } + if (select_history_map) { + BLI_ghash_free(select_history_map, NULL, NULL); + } + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, EXT_KEEP); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EXT_KEEP); } @@ -245,8 +300,11 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) BMOpSlot *slot_edges_exclude; /* initialize our sub-operators */ - BMO_op_init(bm, &dupeop, op->flag, "duplicate"); - + BMO_op_initf( + bm, &dupeop, op->flag, + "duplicate use_select_history=%b", + BMO_slot_bool_get(op->slots_in, "use_select_history")); + BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_EDGE | BM_FACE, EXT_INPUT); /* if one flagged face is bordered by an un-flagged face, then we delete diff --git a/source/blender/bmesh/operators/bmo_fill_attribute.c b/source/blender/bmesh/operators/bmo_fill_attribute.c index fa77e6b509c..d9f50ac891c 100644 --- a/source/blender/bmesh/operators/bmo_fill_attribute.c +++ b/source/blender/bmesh/operators/bmo_fill_attribute.c @@ -154,7 +154,7 @@ static unsigned int bmesh_face_attribute_fill(BMesh *bm, return face_tot; } -void bmo_face_attribute_fill_exec(BMesh *bm, BMOperator *op) +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"); diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c index 6a0fca425f8..40f6937245b 100644 --- a/source/blender/bmesh/operators/bmo_fill_grid.c +++ b/source/blender/bmesh/operators/bmo_fill_grid.c @@ -313,12 +313,12 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const unsigned int xt if (use_interp_simple == false) { float co_a[3], co_b[3]; - barycentric_transform( + transform_point_by_tri_v3( co_a, v_grid[x]->co, tri_t[0], tri_t[1], tri_t[2], tri_a[0], tri_a[1], tri_a[2]); - barycentric_transform( + transform_point_by_tri_v3( co_b, v_grid[(xtot * ytot) + (x - xtot)]->co, tri_t[0], tri_t[1], tri_t[2], diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c index 0ca4ddf8d55..f2e5ebad9c8 100644 --- a/source/blender/bmesh/operators/bmo_inset.c +++ b/source/blender/bmesh/operators/bmo_inset.c @@ -389,7 +389,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) const bool use_outset = BMO_slot_bool_get(op->slots_in, "use_outset"); const bool use_boundary = BMO_slot_bool_get(op->slots_in, "use_boundary") && (use_outset == false); const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset"); - const bool use_even_boundry = use_even_offset; /* could make own option */ + const bool use_even_boundary = use_even_offset; /* could make own option */ const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); const bool use_edge_rail = BMO_slot_bool_get(op->slots_in, "use_edge_rail"); const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate"); @@ -716,7 +716,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) else if (vert_edge_tag_tot == 1) { /* 1 edge user - boundary vert, not so common */ const float *e_no_a = edge_info[vecpair[0]].no; - if (use_even_boundry) { + if (use_even_boundary) { /* This case where only one edge attached to v_split * is used - ei - the face to inset is on a boundary. @@ -984,7 +984,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) if (BM_elem_flag_test(v, BM_ELEM_TAG)) { const float fac = (depth * (use_relative_offset ? bm_edge_info_average_length(v, edge_info) : 1.0f) * - (use_even_boundry ? BM_vert_calc_shell_factor(v) : 1.0f)); + (use_even_boundary ? 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_poke.c b/source/blender/bmesh/operators/bmo_poke.c index 26f20656478..363e395e082 100644 --- a/source/blender/bmesh/operators/bmo_poke.c +++ b/source/blender/bmesh/operators/bmo_poke.c @@ -101,7 +101,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op) do { BMLoop *l_new; - f_new = BM_face_create_quad_tri(bm, l_iter->v, l_iter->next->v, v_center, NULL, f, false); + f_new = BM_face_create_quad_tri(bm, l_iter->v, l_iter->next->v, v_center, NULL, f, BM_CREATE_NOP); l_new = BM_FACE_FIRST_LOOP(f_new); if (i == 0) { diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index f0e31b78ca0..e69dcca6342 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -405,7 +405,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) v2 = eva[icoface[a][1]]; v3 = eva[icoface[a][2]]; - eftemp = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, false); + eftemp = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, BM_CREATE_NOP); BM_ITER_ELEM (l, &liter, eftemp, BM_LOOPS_OF_FACE) { BMO_elem_flag_enable(bm, l->e, EDGE_MARK); @@ -476,14 +476,14 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) tv[monkeyf[i][1] + i - monkeyo], tv[monkeyf[i][2] + i - monkeyo], (monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeyf[i][3] + i - monkeyo] : NULL, - NULL, false); + NULL, BM_CREATE_NOP); BM_face_create_quad_tri(bm, tv[monkeynv + monkeyf[i][2] + i - monkeyo], tv[monkeynv + monkeyf[i][1] + i - monkeyo], tv[monkeynv + monkeyf[i][0] + i - monkeyo], (monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeynv + monkeyf[i][3] + i - monkeyo] : NULL, - NULL, false); + NULL, BM_CREATE_NOP); } MEM_freeN(tv); @@ -535,7 +535,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) if (a && cap_ends) { BMFace *f; - f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, false); + f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, f, FACE_NEW); } @@ -553,7 +553,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) if (cap_ends) { BMFace *f; - f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, false); + f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, f, FACE_NEW); } @@ -622,12 +622,12 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) if (cap_ends) { BMFace *f; - f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, false); + f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, f, FACE_NEW); - f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, false); + f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, f, FACE_NEW); } - BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, false); + BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP); } else { firstv1 = v1; @@ -644,9 +644,9 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) if (cap_ends) { BMFace *f; - f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, false); + f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, f, FACE_NEW); - f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, false); + f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, f, FACE_NEW); } @@ -654,7 +654,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); } - BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, false); + BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP); BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.000001); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); @@ -726,14 +726,14 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op) BMO_elem_flag_enable(bm, v8, VERT_MARK); /* the four sides */ - BM_face_create_quad_tri(bm, v5, v6, v2, v1, NULL, false); - BM_face_create_quad_tri(bm, v6, v7, v3, v2, NULL, false); - BM_face_create_quad_tri(bm, v7, v8, v4, v3, NULL, false); - BM_face_create_quad_tri(bm, v8, v5, v1, v4, NULL, false); + BM_face_create_quad_tri(bm, v5, v6, v2, v1, NULL, BM_CREATE_NOP); + BM_face_create_quad_tri(bm, v6, v7, v3, v2, NULL, BM_CREATE_NOP); + BM_face_create_quad_tri(bm, v7, v8, v4, v3, NULL, BM_CREATE_NOP); + BM_face_create_quad_tri(bm, v8, v5, v1, v4, NULL, BM_CREATE_NOP); /* top/bottom */ - BM_face_create_quad_tri(bm, v1, v2, v3, v4, NULL, false); - BM_face_create_quad_tri(bm, v8, v7, v6, v5, NULL, false); + BM_face_create_quad_tri(bm, v1, v2, v3, v4, NULL, BM_CREATE_NOP); + BM_face_create_quad_tri(bm, v8, v7, v6, v5, NULL, BM_CREATE_NOP); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index 814649c7dbf..75f9feef413 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -528,7 +528,8 @@ static void bmesh_find_doubles_common(BMesh *bm, BMOperator *op, int i, j, keepvert = 0; const float dist = BMO_slot_float_get(op->slots_in, "dist"); - const float dist3 = dist * 3.0f; + const float dist_sq = dist * dist; + const float dist3 = (M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */ /* Test whether keep_verts arg exists and is non-empty */ if (BMO_slot_exists(op->slots_in, "keep_verts")) { @@ -576,7 +577,7 @@ static void bmesh_find_doubles_common(BMesh *bm, BMOperator *op, continue; } - if (compare_len_v3v3(v_check->co, v_other->co, dist)) { + if (compare_len_squared_v3v3(v_check->co, v_other->co, dist_sq)) { /* If one vert is marked as keep, make sure it will be the target */ if (BMO_elem_flag_test(bm, v_other, VERT_KEEP)) { diff --git a/source/blender/bmesh/operators/bmo_smooth_laplacian.c b/source/blender/bmesh/operators/bmo_smooth_laplacian.c index af5f35f2a75..a250c716c16 100644 --- a/source/blender/bmesh/operators/bmo_smooth_laplacian.c +++ b/source/blender/bmesh/operators/bmo_smooth_laplacian.c @@ -156,7 +156,7 @@ static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numFaces, in return sys; } -/* Compute weigth between vertice v_i and all your neighbors +/* Compute weight between vertice v_i and all your neighbors * weight between v_i and v_neighbor * Wij = cot(alpha) + cot(beta) / (4.0 * total area of all faces * sum all weight) * v_i * diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c index e13a9df4474..c01ad10d716 100644 --- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c +++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c @@ -727,8 +727,8 @@ static void bm_edgering_pair_interpolate(BMesh *bm, LoopPairStore *lpair, tri_tmp = tri_array[i]; - barycentric_transform(co_a, v_a->co, UNPACK3(tri_tmp), UNPACK3(tri_sta)); - barycentric_transform(co_b, v_b->co, UNPACK3(tri_tmp), UNPACK3(tri_end)); + transform_point_by_tri_v3(co_a, v_a->co, UNPACK3(tri_tmp), UNPACK3(tri_sta)); + transform_point_by_tri_v3(co_b, v_b->co, UNPACK3(tri_tmp), UNPACK3(tri_end)); interp_v3_v3v3(((BMVert *)v_iter->data)->co, co_a, co_b, (float)i / (float)(resolu - 1)); } @@ -920,13 +920,13 @@ static void bm_edgering_pair_order(BMesh *bm, } BLI_assert(node != NULL); - BLI_rotatelist_first(lb_b, node); + BLI_listbase_rotate_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_first(lb_b, node); + BLI_listbase_rotate_first(lb_b, node); } /* sanity checks that we are aligned & winding now */ diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c index 8e254b2e499..986583cc21b 100644 --- a/source/blender/bmesh/operators/bmo_triangulate.c +++ b/source/blender/bmesh/operators/bmo_triangulate.c @@ -26,10 +26,12 @@ * Triangulate faces, also defines triangle fill. */ +#include "MEM_guardedalloc.h" + #include "DNA_listBase.h" #include "BLI_math.h" -#include "BLI_smallhash.h" +#include "BLI_sort_utils.h" #include "BLI_scanfill.h" #include "bmesh.h" @@ -56,6 +58,10 @@ void bmo_triangulate_exec(BMesh *bm, BMOperator *op) BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); } +struct SortNormal { + float value; /* keep first */ + float no[3]; +}; void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) { @@ -65,54 +71,153 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) BMEdge *e; ScanFillContext sf_ctx; /* ScanFillEdge *sf_edge; */ /* UNUSED */ - ScanFillVert *sf_vert_1, *sf_vert_2; ScanFillFace *sf_tri; - SmallHash hash; - float normal[3], *normal_pt; + GHash *sf_vert_map; + float normal[3]; const int scanfill_flag = BLI_SCANFILL_CALC_HOLES | BLI_SCANFILL_CALC_POLYS | BLI_SCANFILL_CALC_LOOSE; + bool calc_winding = false; - BLI_smallhash_init_ex(&hash, BMO_slot_buffer_count(op->slots_in, "edges")); + sf_vert_map = BLI_ghash_ptr_new_ex(__func__, BMO_slot_buffer_count(op->slots_in, "edges")); BMO_slot_vec_get(op->slots_in, "normal", normal); BLI_scanfill_begin(&sf_ctx); BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + ScanFillVert *sf_verts[2]; + BMVert **e_verts = &e->v1; + unsigned int i; + BMO_elem_flag_enable(bm, e, EDGE_MARK); - - if ((sf_vert_1 = BLI_smallhash_lookup(&hash, (uintptr_t)e->v1)) == NULL) { - sf_vert_1 = BLI_scanfill_vert_add(&sf_ctx, e->v1->co); - sf_vert_1->tmp.p = e->v1; - BLI_smallhash_insert(&hash, (uintptr_t)e->v1, sf_vert_1); - } - - if ((sf_vert_2 = BLI_smallhash_lookup(&hash, (uintptr_t)e->v2)) == NULL) { - sf_vert_2 = BLI_scanfill_vert_add(&sf_ctx, e->v2->co); - sf_vert_2->tmp.p = e->v2; - BLI_smallhash_insert(&hash, (uintptr_t)e->v2, sf_vert_2); + + calc_winding = (calc_winding || BM_edge_is_boundary(e)); + + for (i = 0; i < 2; i++) { + if ((sf_verts[i] = BLI_ghash_lookup(sf_vert_map, e_verts[i])) == NULL) { + sf_verts[i] = BLI_scanfill_vert_add(&sf_ctx, e_verts[i]->co); + sf_verts[i]->tmp.p = e_verts[i]; + BLI_ghash_insert(sf_vert_map, e_verts[i], sf_verts[i]); + } } - - /* sf_edge = */ BLI_scanfill_edge_add(&sf_ctx, sf_vert_1, sf_vert_2); + /* sf_edge = */ BLI_scanfill_edge_add(&sf_ctx, UNPACK2(sf_verts)); /* sf_edge->tmp.p = e; */ /* UNUSED */ } + BLI_ghash_free(sf_vert_map, NULL, NULL); + if (is_zero_v3(normal)) { - normal_pt = NULL; + /* calculate the normal from the cross product of vert-edge pairs. + * Since we don't know winding, just accumulate */ + ScanFillVert *sf_vert; + struct SortNormal *nors; + const unsigned int nors_tot = BLI_ghash_size(sf_vert_map); + unsigned int i; + bool is_degenerate = true; + + nors = MEM_mallocN(sizeof(*nors) * nors_tot, __func__); + + for (sf_vert = sf_ctx.fillvertbase.first, i = 0; sf_vert; sf_vert = sf_vert->next, i++) { + BMVert *v = sf_vert->tmp.p; + BMIter eiter; + BMEdge *e, *e_pair[2]; + unsigned int e_index = 0; + + nors[i].value = -1.0f; + + /* only use if 'is_degenerate' stays true */ + add_v3_v3(normal, v->no); + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (e_index == 2) { + e_index = 0; + break; + } + e_pair[e_index++] = e; + } + } + + if (e_index == 2) { + float dir_a[3], dir_b[3]; + + is_degenerate = false; + + sub_v3_v3v3(dir_a, v->co, BM_edge_other_vert(e_pair[0], v)->co); + sub_v3_v3v3(dir_b, v->co, BM_edge_other_vert(e_pair[1], v)->co); + + cross_v3_v3v3(nors[i].no, dir_a, dir_b); + nors[i].value = len_squared_v3(nors[i].no); + + /* only to get deterministic behavior (for initial normal) */ + if (len_squared_v3(dir_a) > len_squared_v3(dir_b)) { + negate_v3(nors[i].no); + } + } + } + + if (UNLIKELY(is_degenerate)) { + /* no vertices have 2 edges? + * in this case fall back to the average vertex normals */ + } + else { + qsort(nors, nors_tot, sizeof(*nors), BLI_sortutil_cmp_float_reverse); + + copy_v3_v3(normal, nors[0].no); + for (i = 0; i < nors_tot; i++) { + if (UNLIKELY(nors[i].value == -1.0f)) { + break; + } + if (dot_v3v3(normal, nors[i].no) < 0.0f) { + negate_v3(nors[i].no); + } + add_v3_v3(normal, nors[i].no); + } + normalize_v3(normal); + } + + MEM_freeN(nors); } else { - normalize_v3(normal); - normal_pt = normal; + calc_winding = false; } - BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal_pt); - + normalize_v3(normal); + + BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal); + + + /* if we have existing faces, base winding on those */ + if (calc_winding) { + int winding_votes = 0; + for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { + BMVert *v_tri[3] = {sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p}; + unsigned int i, i_prev; + + for (i = 0, i_prev = 2; i < 3; i_prev = i++) { + e = BM_edge_exists(v_tri[i], v_tri[i_prev]); + if (e && BM_edge_is_boundary(e) && BMO_elem_flag_test(bm, e, EDGE_MARK)) { + winding_votes += (e->l->v == v_tri[i]) ? 1 : -1; + } + } + } + + if (winding_votes < 0) { + for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { + SWAP(struct ScanFillVert *, sf_tri->v2, sf_tri->v3); + } + } + } + + for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { - BMFace *f = BM_face_create_quad_tri(bm, - sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p, NULL, - NULL, true); + BMFace *f; BMLoop *l; BMIter liter; + + f = BM_face_create_quad_tri(bm, + sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p, NULL, + NULL, BM_CREATE_NO_DOUBLE); BMO_elem_flag_enable(bm, f, ELE_NEW); BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { @@ -123,7 +228,6 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) } BLI_scanfill_end(&sf_ctx); - BLI_smallhash_release(&hash); if (use_beauty) { BMOperator bmop; diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index 600386893dd..d2d1c0854de 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -63,7 +63,7 @@ void bmo_transform_exec(BMesh *UNUSED(bm), BMOperator *op) if (!is_zero_m4(mat_space)) { invert_m4_m4(imat_space, mat_space); - mul_serie_m4(mat, imat_space, mat, mat_space, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(mat, imat_space, mat, mat_space); } BMO_ITER (v, &iter, op->slots_in, "verts", BM_VERT) { diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c index 90d26a775d3..6639e767e77 100644 --- a/source/blender/bmesh/tools/bmesh_beautify.c +++ b/source/blender/bmesh/tools/bmesh_beautify.c @@ -67,6 +67,7 @@ static unsigned int erot_gsetutil_hash(const void *ptr) return BLI_ghashutil_inthash_v4(&e_state->v1); } #endif +#if 0 static int erot_gsetutil_cmp(const void *a, const void *b) { const EdRotState *e_state_a = (const EdRotState *)a; @@ -81,10 +82,10 @@ static int erot_gsetutil_cmp(const void *a, const void *b) else if (e_state_a->f2 > e_state_b->f2) return 1; else return 0; } - +#endif static GSet *erot_gset_new(void) { - return BLI_gset_new(BLI_ghashutil_inthash_v4_p, erot_gsetutil_cmp, __func__); + return BLI_gset_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__); } /* ensure v0 is smaller */ @@ -142,10 +143,10 @@ static float bm_edge_calc_rotate_beauty__area( float axis_mat[3][3]; // 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) && - (ELEM3(v3, v1, v2, v4) == false) && - (ELEM3(v4, v1, v2, v3) == false)); + BLI_assert((ELEM(v1, v2, v3, v4) == false) && + (ELEM(v2, v1, v3, v4) == false) && + (ELEM(v3, v1, v2, v4) == false) && + (ELEM(v4, v1, v2, v3) == false)); is_zero_a = (normal_tri_v3(no_a, v2, v3, v4) <= FLT_EPSILON); is_zero_b = (normal_tri_v3(no_b, v2, v4, v1) <= FLT_EPSILON); diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index c583464ab6d..4a9fb677257 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -187,6 +187,7 @@ typedef struct BevelParams { bool limit_offset; /* should offsets be limited by collisions? */ const struct MDeformVert *dvert; /* vertex group array, maybe set if vertex_only */ int vertex_group; /* vertex group index, maybe set if vertex_only */ + int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */ } BevelParams; // #pragma GCC diagnostic ignored "-Wpadded" @@ -356,11 +357,12 @@ static BMFace *boundvert_rep_face(BoundVert *v) * Make ngon from verts alone. * Make sure to properly copy face attributes and do custom data interpolation from * corresponding elements of face_arr, if that is non-NULL, else from facerep. + * If mat_nr >= 0 then the material of the face is set to that. * * \note ALL face creation goes through this function, this is important to keep! */ static BMFace *bev_create_ngon(BMesh *bm, BMVert **vert_arr, const int totv, - BMFace **face_arr, BMFace *facerep, bool do_interp) + BMFace **face_arr, BMFace *facerep, int mat_nr, bool do_interp) { BMIter iter; BMLoop *l; @@ -395,22 +397,24 @@ static BMFace *bev_create_ngon(BMesh *bm, BMVert **vert_arr, const int totv, BM_elem_flag_enable(f, BM_ELEM_TAG); } + if (mat_nr >= 0) + f->mat_nr = mat_nr; return f; } static BMFace *bev_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, - BMFace *facerep, bool do_interp) + BMFace *facerep, int mat_nr, bool do_interp) { BMVert *varr[4] = {v1, v2, v3, v4}; - return bev_create_ngon(bm, varr, v4 ? 4 : 3, NULL, facerep, do_interp); + return bev_create_ngon(bm, varr, v4 ? 4 : 3, NULL, facerep, mat_nr, do_interp); } static BMFace *bev_create_quad_tri_ex(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, - BMFace *f1, BMFace *f2, BMFace *f3, BMFace *f4) + BMFace *f1, BMFace *f2, BMFace *f3, BMFace *f4, int mat_nr) { BMVert *varr[4] = {v1, v2, v3, v4}; BMFace *farr[4] = {f1, f2, f3, f4}; - return bev_create_ngon(bm, varr, v4 ? 4 : 3, farr, f1, true); + return bev_create_ngon(bm, varr, v4 ? 4 : 3, farr, f1, mat_nr, true); } @@ -490,13 +494,13 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f * one side (f1, arbitrarily), and interpolate them all on that side. * For face data, use f1 (arbitrarily) as face representative. */ static BMFace *bev_create_quad_straddle(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, - BMFace *f1, BMFace *f2, bool is_seam) + BMFace *f1, BMFace *f2, int mat_nr, bool is_seam) { BMFace *f, *facerep; BMLoop *l; BMIter iter; - f = bev_create_quad_tri(bm, v1, v2, v3, v4, f1, false); + f = bev_create_quad_tri(bm, v1, v2, v3, v4, f1, mat_nr, false); if (!f) return NULL; @@ -1627,7 +1631,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) * corresponding ones that changed on the other end. * The graph is dynamic in the sense that having an offset that * doesn't meet the user spec can be added as the search proceeds. - * We want this search to be deterministic (not dependendent + * We want this search to be deterministic (not dependent * on order of processing through hash table), so as to avoid * flicker to to different decisions made if search is different * while dragging the offset number in the UI. So look for the @@ -1719,7 +1723,7 @@ static BoundVert *pipe_test(BevVert *bv) sub_v3_v3v3(dir3, BM_edge_other_vert(v3->ebev->e, bv->v)->co, bv->v->co); normalize_v3(dir1); normalize_v3(dir3); - if (angle_v3v3(dir1, dir3) < BEVEL_EPSILON_BIG) { + if (angle_normalized_v3v3(dir1, dir3) < BEVEL_EPSILON_BIG) { epipe = v1->ebev; break; } @@ -1865,7 +1869,7 @@ static float sabin_gamma(int n) k2 = k * k; k4 = k2 * k2; k6 = k4 * k2; - y = pow(1.73205080756888 * sqrt(64.0 * k6 - 144.0 * k4 + 135.0 * k2 - 27.0) + 9.0 * k, + y = pow(M_SQRT3 * sqrt(64.0 * k6 - 144.0 * k4 + 135.0 * k2 - 27.0) + 9.0 * k, 1.0 / 3.0); x = 0.480749856769136 * y - (0.231120424783545 * (12.0 * k2 - 9.0)) / y; ans = (k * x + 2.0 * k2 - 1.0) / (x * x * (k * x + 1.0)); @@ -2258,7 +2262,7 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) bndv = bndv->next; } /* center vertex */ - w = 0.57735027f; /* 1/sqrt(3) */ + w = (float)(1.0 / M_SQRT3); co[0] = w; co[1] = w; co[2] = w; @@ -2500,6 +2504,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv) BMVert *bmv1, *bmv2, *bmv3, *bmv4; BMFace *f, *f2, *f23; BoundVert *vpipe; + int mat_nr = bp->mat_nr; n = bv->vmesh->count; ns = bv->vmesh->seg; @@ -2552,7 +2557,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv) if (odd && k == ns2 && f2 && !v->any_seam) f23 = f2; bev_create_quad_tri_ex(bm, bmv1, bmv2, bmv3, bmv4, - f, f23, f23, f); + f, f23, f23, f, mat_nr); } } } while ((v = v->next) != vm->boundstart); @@ -2589,13 +2594,13 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv) BLI_array_append(vf, v->any_seam ? f : boundvert_rep_face(v)); } while ((v = v->next) != vm->boundstart); f = boundvert_rep_face(vm->boundstart); - bev_create_ngon(bm, vv, BLI_array_count(vv), vf, f, true); + bev_create_ngon(bm, vv, BLI_array_count(vv), vf, f, mat_nr, true); BLI_array_free(vv); } } -static BMFace *bevel_build_poly(BMesh *bm, BevVert *bv) +static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv) { BMFace *f; int n, k; @@ -2625,7 +2630,7 @@ static BMFace *bevel_build_poly(BMesh *bm, BevVert *bv) } } while ((v = v->next) != vm->boundstart); if (n > 2) { - f = bev_create_ngon(bm, vv, n, vf, boundvert_rep_face(v), true); + f = bev_create_ngon(bm, vv, n, vf, boundvert_rep_face(v), bp->mat_nr, true); } else { f = NULL; @@ -2634,12 +2639,12 @@ static BMFace *bevel_build_poly(BMesh *bm, BevVert *bv) return f; } -static void bevel_build_trifan(BMesh *bm, BevVert *bv) +static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv) { BMFace *f; BLI_assert(next_bev(bv, NULL)->seg == 1 || bv->selcount == 1); - f = bevel_build_poly(bm, bv); + f = bevel_build_poly(bp, bm, bv); if (f) { /* we have a polygon which we know starts at the previous vertex, make it into a fan */ @@ -2669,12 +2674,12 @@ static void bevel_build_trifan(BMesh *bm, BevVert *bv) } } -static void bevel_build_quadstrip(BMesh *bm, BevVert *bv) +static void bevel_build_quadstrip(BevelParams *bp, BMesh *bm, BevVert *bv) { BMFace *f; BLI_assert(bv->selcount == 2); - f = bevel_build_poly(bm, bv); + f = bevel_build_poly(bp, bm, bv); if (f) { /* we have a polygon which we know starts at this vertex, make it into strips */ @@ -2813,16 +2818,16 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) bevel_build_one_wire(bm, bv); break; case M_POLY: - bevel_build_poly(bm, bv); + bevel_build_poly(bp, bm, bv); break; case M_ADJ: bevel_build_rings(bp, bm, bv); break; case M_TRI_FAN: - bevel_build_trifan(bm, bv); + bevel_build_trifan(bp, bm, bv); break; case M_QUAD_STRIP: - bevel_build_quadstrip(bm, bv); + bevel_build_quadstrip(bp, bm, bv); break; } } @@ -3173,7 +3178,7 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) } if (do_rebuild) { n = BLI_array_count(vv); - f_new = bev_create_ngon(bm, vv, n, NULL, f, true); + f_new = bev_create_ngon(bm, vv, n, NULL, f, -1, true); for (k = 0; k < BLI_array_count(vv_fix); k++) { bev_merge_uvs(bm, vv_fix[k]); @@ -3384,6 +3389,7 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) BMEdge *bme1, *bme2; BMFace *f1, *f2, *f; int k, nseg, i1, i2, odd, mid; + int mat_nr = bp->mat_nr; if (!BM_edge_is_manifold(bme)) return; @@ -3422,7 +3428,7 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) vm2 = bv2->vmesh; if (nseg == 1) { - bev_create_quad_straddle(bm, bmv1, bmv2, bmv3, bmv4, f1, f2, e1->is_seam); + bev_create_quad_straddle(bm, bmv1, bmv2, bmv3, bmv4, f1, f2, mat_nr, e1->is_seam); } else { bmv1i = bmv1; @@ -3433,11 +3439,11 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) bmv4i = mesh_vert(vm1, i1, 0, k)->v; bmv3i = mesh_vert(vm2, i2, 0, nseg - k)->v; if (odd && k == mid + 1) { - bev_create_quad_straddle(bm, bmv1i, bmv2i, bmv3i, bmv4i, f1, f2, e1->is_seam); + bev_create_quad_straddle(bm, bmv1i, bmv2i, bmv3i, bmv4i, f1, f2, mat_nr, e1->is_seam); } else { f = (k <= mid) ? f1 : f2; - bev_create_quad_tri(bm, bmv1i, bmv2i, bmv3i, bmv4i, f, true); + bev_create_quad_tri(bm, bmv1i, bmv2i, bmv3i, bmv4i, f, mat_nr, true); } bmv1i = bmv4i; bmv2i = bmv3i; @@ -3676,7 +3682,7 @@ static float bevel_limit_offset(BMesh *bm, BevelParams *bp) void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type, const float segments, const float profile, const bool vertex_only, const bool use_weights, const bool limit_offset, - const struct MDeformVert *dvert, const int vertex_group) + const struct MDeformVert *dvert, const int vertex_group, const int mat) { BMIter iter; BMVert *v, *v_next; @@ -3694,6 +3700,7 @@ void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type, bp.limit_offset = limit_offset; bp.dvert = dvert; bp.vertex_group = vertex_group; + bp.mat_nr = mat; if (bp.pro_super_r < 0.60f) bp.pro_super_r = 0.60f; /* TODO: implement 0 case properly */ diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h index 0c088ce0238..52d8faa5401 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.h +++ b/source/blender/bmesh/tools/bmesh_bevel.h @@ -31,6 +31,7 @@ struct MDeformVert; void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type, const float segments, const float profile, const bool vertex_only, const bool use_weights, - const bool limit_offset, const struct MDeformVert *dvert, const int vertex_group); + const bool limit_offset, const struct MDeformVert *dvert, const int vertex_group, + const int mat); #endif /* __BMESH_BEVEL_H__ */ diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c index 0ecb8066ac1..ae9b882cea0 100644 --- a/source/blender/bmesh/tools/bmesh_bisect_plane.c +++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c @@ -124,7 +124,7 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con /* 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. */ + * ... that the face doesn't only have boundary verts on the plane for eg. */ l_iter = l_first; do { if (vert_is_center_test(l_iter->v)) { diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c index 4b6209fc4eb..ef1783cc693 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c +++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c @@ -414,10 +414,10 @@ static void bm_decim_triangulate_end(BMesh *bm) BM_vert_in_edge(e, l_b->next->v) ? l_b->prev->v : l_b->next->v, }; - BLI_assert(ELEM3(vquad[0], vquad[1], vquad[2], vquad[3]) == false); - BLI_assert(ELEM3(vquad[1], vquad[0], vquad[2], vquad[3]) == false); - BLI_assert(ELEM3(vquad[2], vquad[1], vquad[0], vquad[3]) == false); - BLI_assert(ELEM3(vquad[3], vquad[1], vquad[2], vquad[0]) == false); + BLI_assert(ELEM(vquad[0], vquad[1], vquad[2], vquad[3]) == false); + BLI_assert(ELEM(vquad[1], vquad[0], vquad[2], vquad[3]) == false); + BLI_assert(ELEM(vquad[2], vquad[1], vquad[0], vquad[3]) == false); + BLI_assert(ELEM(vquad[3], vquad[1], vquad[2], vquad[0]) == false); if (is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) { /* highly unlikely to fail, but prevents possible double-ups */ diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c index a08aa6184b5..1328b81b746 100644 --- a/source/blender/bmesh/tools/bmesh_edgenet.c +++ b/source/blender/bmesh/tools/bmesh_edgenet.c @@ -393,8 +393,8 @@ static LinkNode *bm_edgenet_path_calc_best( if (path == NULL) { return NULL; } - else if (path_cost <= 1) { - /* any face that takes 1-2 iterations to find we consider valid */ + else if (path_cost < 1) { + /* any face that takes 1 iteration to find we consider valid */ return path; } else { @@ -465,7 +465,6 @@ void BM_mesh_edgenet(BMesh *bm, 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)); } } diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c new file mode 100644 index 00000000000..4d87c3e3551 --- /dev/null +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -0,0 +1,1302 @@ +/* + * ***** 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/bmesh/tools/bmesh_intersect.c + * \ingroup bmesh + * + * Cut meshes along intersections. + * + * Boolean-like modeling operation (without calculating inside/outside). + * + * Supported: + * - Concave faces. + * - Non-planar faces. + * - Custom-data (UV's etc). + * + * Unsupported: + * - Intersecting between different meshes. + * - No support for holes (cutting a hole into a single face). + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" +#include "BLI_memarena.h" +#include "BLI_alloca.h" +#include "BLI_sort_utils.h" + +#include "BLI_linklist_stack.h" +#include "BLI_stackdefines.h" +#include "BLI_array.h" + +#include "BLI_kdopbvh.h" + +#include "bmesh.h" +#include "bmesh_intersect.h" /* own include */ + +#include "tools/bmesh_edgesplit.h" + +#include "BLI_strict_flags.h" + +/* + * Some of these depend on each other: + */ + +/* splice verts into existing edges */ +#define USE_SPLICE +/* split faces by intersecting edges */ +#define USE_NET +/* split resulting edges */ +#define USE_SEPARATE +/* remove verts created by intersecting triangles */ +#define USE_DISSOLVE + +/* strict asserts that may fail in practice (handy for debugging cases which should succeed) */ +// #define USE_PARANOID +/* use accelerated overlap check */ +#define USE_BVH + + +static void tri_v3_scale( + float v1[3], float v2[3], float v3[3], + const float t) +{ + float p[3]; + + mid_v3_v3v3v3(p, v1, v2, v3); + + interp_v3_v3v3(v1, p, v1, t); + interp_v3_v3v3(v2, p, v2, t); + interp_v3_v3v3(v3, p, v3, t); +} + +#ifdef USE_DISSOLVE +/* other edge when a vert only has 2 edges */ +static BMEdge *bm_vert_other_edge(BMVert *v, BMEdge *e) +{ + BLI_assert(BM_vert_is_edge_pair(v)); + BLI_assert(BM_vert_in_edge(e, v)); + + if (v->e != e) { + return v->e; + } + else { + return BM_DISK_EDGE_NEXT(v->e, v); + } +} +#endif + +enum ISectType { + IX_NONE = -1, + IX_EDGE_TRI_EDGE0, + IX_EDGE_TRI_EDGE1, + IX_EDGE_TRI_EDGE2, + IX_EDGE_TRI, + IX_TOT, +}; + +struct ISectEpsilon { + float eps, eps_sq; + float eps2x, eps2x_sq; + float eps_margin, eps_margin_sq; +}; + +struct ISectState { + BMesh *bm; + GHash *edgetri_cache; /* int[4]: BMVert */ + GHash *edge_verts; /* BMEdge: LinkList(of verts), new and original edges */ + GHash *face_edges; /* BMFace-index: LinkList(of edges), only original faces */ + GSet *wire_edges; /* BMEdge (could use tags instead) */ + LinkNode *vert_dissolve; /* BMVert's */ + + MemArena *mem_arena; + + struct ISectEpsilon epsilon; +}; + +/** + * Store as value in GHash so we can get list-length without counting every time. + * Also means we don't need to update the GHash value each time. + */ +struct LinkBase { + LinkNode *list; + unsigned int list_len; +}; + +static bool ghash_insert_link( + GHash *gh, void *key, void *val, bool use_test, + MemArena *mem_arena) +{ + struct LinkBase *ls_base; + LinkNode *ls; + + ls_base = BLI_ghash_lookup(gh, key); + + if (ls_base) { + if (use_test && (BLI_linklist_index(ls_base->list, key) != -1)) { + return false; + } + } + else { + ls_base = BLI_memarena_alloc(mem_arena, sizeof(*ls_base)); + ls_base->list = NULL; + ls_base->list_len = 0; + BLI_ghash_insert(gh, key, ls_base); + } + + ls = BLI_memarena_alloc(mem_arena, sizeof(*ls)); + ls->next = ls_base->list; + ls->link = val; + ls_base->list = ls; + ls_base->list_len += 1; + + return true; +} + +struct vert_sort_t { + float val; + BMVert *v; +}; + +#ifdef USE_SPLICE +static void edge_verts_sort(const float co[3], struct LinkBase *v_ls_base) +{ + /* not optimal but list will be typically < 5 */ + unsigned int i; + struct vert_sort_t *vert_sort = BLI_array_alloca(vert_sort, v_ls_base->list_len); + LinkNode *node; + + BLI_assert(v_ls_base->list_len > 1); + + for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) { + BMVert *v = node->link; + BLI_assert(v->head.htype == BM_VERT); + vert_sort[i].val = len_squared_v3v3(co, v->co); + vert_sort[i].v = v; + } + + qsort(vert_sort, v_ls_base->list_len, sizeof(*vert_sort), BLI_sortutil_cmp_float); + + for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) { + node->link = vert_sort[i].v; + } +} +#endif + +static void edge_verts_add( + struct ISectState *s, + BMEdge *e, + BMVert *v, + const bool use_test + ) +{ + BLI_assert(e->head.htype == BM_EDGE); + BLI_assert(v->head.htype == BM_VERT); + ghash_insert_link(s->edge_verts, (void *)e, v, use_test, s->mem_arena); +} + +static void face_edges_add( + struct ISectState *s, + const int f_index, + BMEdge *e, + const bool use_test) +{ + void *f_index_key = SET_INT_IN_POINTER(f_index); + BLI_assert(e->head.htype == BM_EDGE); + BLI_assert(BM_edge_in_face(e, s->bm->ftable[f_index]) == false); + BLI_assert(BM_elem_index_get(s->bm->ftable[f_index]) == f_index); + + ghash_insert_link(s->face_edges, f_index_key, e, use_test, s->mem_arena); +} + +#ifdef USE_NET +static void face_edges_split( + BMesh *bm, + BMFace *f, + struct LinkBase *e_ls_base) +{ + unsigned int i; + BMEdge **edge_arr = BLI_array_alloca(edge_arr, e_ls_base->list_len); + LinkNode *node; + BLI_assert(f->head.htype == BM_FACE); + + for (i = 0, node = e_ls_base->list; i < e_ls_base->list_len; i++, node = node->next) { + edge_arr[i] = node->link; + } + BLI_assert(node == NULL); + +#ifdef USE_DUMP + printf("# %s: %d %u\n", __func__, BM_elem_index_get(f), e_ls_base->list_len); +#endif + + BM_face_split_edgenet(bm, f, edge_arr, (int)e_ls_base->list_len, NULL, NULL); +} +#endif + +#ifdef USE_DISSOLVE +static void vert_dissolve_add( + struct ISectState *s, + BMVert *v) +{ + BLI_assert(v->head.htype == BM_VERT); + BLI_assert(!BM_elem_flag_test(v, BM_ELEM_TAG)); + BLI_assert(BLI_linklist_index(s->vert_dissolve, v) == -1); + + BM_elem_flag_enable(v, BM_ELEM_TAG); + BLI_linklist_prepend_arena(&s->vert_dissolve, v, s->mem_arena); +} +#endif + +static enum ISectType intersect_line_tri( + const float p0[3], const float p1[3], + const float *t_cos[3], const float t_nor[3], + float r_ix[3], + const struct ISectEpsilon *e) +{ + float p_dir[3]; + unsigned int i_t0; + float fac; + + sub_v3_v3v3(p_dir, p0, p1); + normalize_v3(p_dir); + + for (i_t0 = 0; i_t0 < 3; i_t0++) { + const unsigned int i_t1 = (i_t0 + 1) % 3; + float te_dir[3]; + + sub_v3_v3v3(te_dir, t_cos[i_t0], t_cos[i_t1]); + normalize_v3(te_dir); + if (fabsf(dot_v3v3(p_dir, te_dir)) >= 1.0f - e->eps) { + /* co-linear */ + } + else { + float ix_pair[2][3]; + int ix_pair_type; + + ix_pair_type = isect_line_line_epsilon_v3(p0, p1, t_cos[i_t0], t_cos[i_t1], ix_pair[0], ix_pair[1], 0.0f); + + if (ix_pair_type != 0) { + if (ix_pair_type == 1) { + copy_v3_v3(ix_pair[1], ix_pair[0]); + } + + if ((ix_pair_type == 1) || + (len_squared_v3v3(ix_pair[0], ix_pair[1]) <= e->eps_margin_sq)) + { + fac = line_point_factor_v3(ix_pair[1], t_cos[i_t0], t_cos[i_t1]); + if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) { + fac = line_point_factor_v3(ix_pair[0], p0, p1); + if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) { + copy_v3_v3(r_ix, ix_pair[0]); + return (IX_EDGE_TRI_EDGE0 + (enum ISectType)i_t0); + } + } + } + } + } + } + + /* check ray isn't planar with tri */ + if (fabsf(dot_v3v3(p_dir, t_nor)) >= e->eps) { + if (isect_line_tri_epsilon_v3(p0, p1, t_cos[0], t_cos[1], t_cos[2], &fac, NULL, 0.0f)) { + if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) { + interp_v3_v3v3(r_ix, p0, p1, fac); + if (min_fff(len_squared_v3v3(t_cos[0], r_ix), + len_squared_v3v3(t_cos[1], r_ix), + len_squared_v3v3(t_cos[2], r_ix)) >= e->eps_margin_sq) + { + return IX_EDGE_TRI; + } + } + } + } + + /* r_ix may be unset */ + return IX_NONE; +} + +static BMVert *bm_isect_edge_tri( + struct ISectState *s, + BMVert *e_v0, BMVert *e_v1, + BMVert *t[3], const int t_index, + const float *t_cos[3], const float t_nor[3], + enum ISectType *r_side) +{ + BMesh *bm = s->bm; + int k_arr[IX_TOT][4]; + unsigned int i; + const int ti[3] = {UNPACK3_EX(BM_elem_index_get, t, )}; + float ix[3]; + + if (BM_elem_index_get(e_v0) > BM_elem_index_get(e_v1)) { + SWAP(BMVert *, e_v0, e_v1); + } + +#ifdef USE_PARANOID + BLI_assert(len_squared_v3v3(e_v0->co, t[0]->co) >= s->epsilon.eps_sq); + BLI_assert(len_squared_v3v3(e_v0->co, t[1]->co) >= s->epsilon.eps_sq); + BLI_assert(len_squared_v3v3(e_v0->co, t[2]->co) >= s->epsilon.eps_sq); + BLI_assert(len_squared_v3v3(e_v1->co, t[0]->co) >= s->epsilon.eps_sq); + BLI_assert(len_squared_v3v3(e_v1->co, t[1]->co) >= s->epsilon.eps_sq); + BLI_assert(len_squared_v3v3(e_v1->co, t[2]->co) >= s->epsilon.eps_sq); +#endif + +#define KEY_SET(k, i0, i1, i2, i3) { \ + (k)[0] = i0; \ + (k)[1] = i1; \ + (k)[2] = i2; \ + (k)[3] = i3; \ +} (void)0 + + /* order tri, then order (1-2, 2-3)*/ +#define KEY_EDGE_TRI_ORDER(k) { \ + if (k[2] > k[3]) { \ + SWAP(int, k[2], k[3]); \ + } \ + if (k[0] > k[2]) { \ + SWAP(int, k[0], k[2]); \ + SWAP(int, k[1], k[3]); \ + } \ +} (void)0 + + KEY_SET(k_arr[IX_EDGE_TRI], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), t_index, -1); + /* need to order here */ + KEY_SET(k_arr[IX_EDGE_TRI_EDGE0], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[0], ti[1]); + KEY_SET(k_arr[IX_EDGE_TRI_EDGE1], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[1], ti[2]); + KEY_SET(k_arr[IX_EDGE_TRI_EDGE2], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[2], ti[0]); + + KEY_EDGE_TRI_ORDER(k_arr[IX_EDGE_TRI_EDGE0]); + KEY_EDGE_TRI_ORDER(k_arr[IX_EDGE_TRI_EDGE1]); + KEY_EDGE_TRI_ORDER(k_arr[IX_EDGE_TRI_EDGE2]); + +#undef KEY_SET +#undef KEY_EDGE_TRI_ORDER + + + + for (i = 0; i < ARRAY_SIZE(k_arr); i++) { + BMVert *iv; + + iv = BLI_ghash_lookup(s->edgetri_cache, k_arr[i]); + + if (iv) { +#ifdef USE_DUMP + printf("# cache hit (%d, %d, %d, %d)\n", UNPACK4(k_arr[i])); +#endif + *r_side = (enum ISectType)i; + return iv; + } + } + + *r_side = intersect_line_tri(e_v0->co, e_v1->co, t_cos, t_nor, ix, &s->epsilon); + if (*r_side != IX_NONE) { + BMVert *iv; + BMEdge *e; +#ifdef USE_DUMP + printf("# new vertex (%.6f, %.6f, %.6f) %d\n", UNPACK3(ix), *r_side); +#endif + +#ifdef USE_PARANOID + BLI_assert(len_squared_v3v3(ix, e_v0->co) > s->epsilon.eps_sq); + BLI_assert(len_squared_v3v3(ix, e_v1->co) > s->epsilon.eps_sq); + BLI_assert(len_squared_v3v3(ix, t[0]->co) > s->epsilon.eps_sq); + BLI_assert(len_squared_v3v3(ix, t[1]->co) > s->epsilon.eps_sq); + BLI_assert(len_squared_v3v3(ix, t[2]->co) > s->epsilon.eps_sq); +#endif + iv = BM_vert_create(bm, ix, NULL, 0); + + e = BM_edge_exists(e_v0, e_v1); + if (e) { +#ifdef USE_DUMP + printf("# adding to edge %d\n", BM_elem_index_get(e)); +#endif + edge_verts_add(s, e, iv, false); + } + else { +#ifdef USE_DISSOLVE + vert_dissolve_add(s, iv); +#endif + } + + if ((*r_side >= IX_EDGE_TRI_EDGE0) && (*r_side <= IX_EDGE_TRI_EDGE2)) { + i = (unsigned int)(*r_side - IX_EDGE_TRI_EDGE0); + e = BM_edge_exists(t[i], t[(i + 1) % 3]); + if (e) { + edge_verts_add(s, e, iv, false); + } + } + + { + int *k = BLI_memarena_alloc(s->mem_arena, sizeof(int[4])); + memcpy(k, k_arr[*r_side], sizeof(int[4])); + BLI_ghash_insert(s->edgetri_cache, k, iv); + } + + return iv; + + } + + *r_side = IX_NONE; + + return NULL; +} + +/** + * Return true if we have any intersections. + */ +static void bm_isect_tri_tri( + struct ISectState *s, + int a_index, int b_index, + BMLoop **a, BMLoop **b) +{ + BMFace *f_a = (*a)->f; + BMFace *f_b = (*b)->f; + BMVert *fv_a[3] = {UNPACK3_EX(, a, ->v)}; + BMVert *fv_b[3] = {UNPACK3_EX(, b, ->v)}; + const float *f_a_cos[3] = {UNPACK3_EX(, fv_a, ->co)}; + const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)}; + float f_a_nor[3]; + float f_b_nor[3]; + int a_mask = 0; + int b_mask = 0; + unsigned int i; + + + /* should be enough but may need to bump */ + BMVert *iv_ls_a[8]; + BMVert *iv_ls_b[8]; + STACK_DECLARE(iv_ls_a); + STACK_DECLARE(iv_ls_b); + + if (UNLIKELY(ELEM(fv_a[0], UNPACK3(fv_b)) || + ELEM(fv_a[1], UNPACK3(fv_b)) || + ELEM(fv_a[2], UNPACK3(fv_b)))) + { + return; + } + + STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a)); + STACK_INIT(iv_ls_b, ARRAY_SIZE(iv_ls_b)); + + /* vert-vert + * --------- */ + { + /* first check in any verts are touching + * (any case where we wont create new verts) + */ + unsigned int i_a; + for (i_a = 0; i_a < 3; i_a++) { + unsigned int i_b; + for (i_b = 0; i_b < 3; i_b++) { + if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { + if (!((1 << i_a) & a_mask)) { + STACK_PUSH(iv_ls_a, fv_a[i_a]); + a_mask |= (1 << i_a); +#ifdef USE_DUMP + printf(" ('VERT-VERT-A') %d, %d),\n", + i_a, BM_elem_index_get(fv_a[i_a])); +#endif + } + if (!((1 << i_b) & b_mask)) { + STACK_PUSH(iv_ls_b, fv_b[i_b]); + b_mask |= (1 << i_b); +#ifdef USE_DUMP + printf(" ('VERT-VERT-B') %d, %d),\n", + i_b, BM_elem_index_get(fv_b[i_b])); +#endif + } + } + } + } + } + + /* vert-edge + * --------- */ + { + unsigned int i_a; + for (i_a = 0; i_a < 3; i_a++) { + if (!((1 << i_a) & a_mask)) { + unsigned int i_b_e0; + for (i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) { + unsigned int i_b_e1 = (i_b_e0 + 1) % 3; + float fac; + if (((1 << i_b_e0) | (1 << i_b_e1)) & b_mask) + continue; + fac = line_point_factor_v3(fv_a[i_a]->co, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co); + if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0 + s->epsilon.eps)) { + float ix[3]; + interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac); + if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) { + BMEdge *e; + STACK_PUSH(iv_ls_b, fv_a[i_a]); + // STACK_PUSH(iv_ls_a, fv_a[i_a]); + a_mask |= (1 << i_a); + e = BM_edge_exists(fv_b[i_b_e0], fv_b[i_b_e1]); +#ifdef USE_DUMP + printf(" ('VERT-EDGE-A', %d, %d),\n", + BM_elem_index_get(fv_b[i_b_e0]), BM_elem_index_get(fv_b[i_b_e1])); +#endif + if (e) { +#ifdef USE_DUMP + printf("# adding to edge %d\n", BM_elem_index_get(e)); +#endif + edge_verts_add(s, e, fv_a[i_a], true); + } + break; + } + } + } + } + } + } + + { + unsigned int i_b; + for (i_b = 0; i_b < 3; i_b++) { + if (!((1 << i_b) & b_mask)) { + unsigned int i_a_e0; + for (i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) { + unsigned int i_a_e1 = (i_a_e0 + 1) % 3; + float fac; + if (((1 << i_a_e0) | (1 << i_a_e1)) & a_mask) + continue; + fac = line_point_factor_v3(fv_b[i_b]->co, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co); + if ((fac > 0.0 - s->epsilon.eps) && (fac < 1.0 + s->epsilon.eps)) { + float ix[3]; + interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac); + if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { + BMEdge *e; + STACK_PUSH(iv_ls_a, fv_b[i_b]); + // STACK_PUSH(iv_ls_b, fv_b[i_b]); + b_mask |= (1 << i_b); + e = BM_edge_exists(fv_a[i_a_e0], fv_a[i_a_e1]); +#ifdef USE_DUMP + printf(" ('VERT-EDGE-B', %d, %d),\n", + BM_elem_index_get(fv_a[i_a_e0]), BM_elem_index_get(fv_a[i_a_e1])); +#endif + if (e) { +#ifdef USE_DUMP + printf(" adding to edge %d\n", BM_elem_index_get(e)); +#endif + edge_verts_add(s, e, fv_b[i_b], true); + } + break; + } + } + } + } + } + } + + /* vert-tri + * -------- */ + { + + float t_scale[3][3]; + unsigned int i_a; + + copy_v3_v3(t_scale[0], fv_b[0]->co); + copy_v3_v3(t_scale[1], fv_b[1]->co); + copy_v3_v3(t_scale[2], fv_b[2]->co); + tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x); + + // second check for verts intersecting the triangle + for (i_a = 0; i_a < 3; i_a++) { + float ix[3]; + if ((1 << i_a) & a_mask) + continue; + if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) { + if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) { + BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), fv_a[i_a]) == -1); + BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), fv_a[i_a]) == -1); + + STACK_PUSH(iv_ls_a, fv_a[i_a]); + STACK_PUSH(iv_ls_b, fv_a[i_a]); + a_mask |= (1 << i_a); +#ifdef USE_DUMP + printf(" 'VERT TRI-A',\n"); +#endif + } + } + } + } + + { + float t_scale[3][3]; + unsigned int i_b; + + copy_v3_v3(t_scale[0], fv_a[0]->co); + copy_v3_v3(t_scale[1], fv_a[1]->co); + copy_v3_v3(t_scale[2], fv_a[2]->co); + tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x); + + for (i_b = 0; i_b < 3; i_b++) { + float ix[3]; + if ((1 << i_b) & b_mask) + continue; + + if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) { + if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { + BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), fv_b[i_b]) == -1); + BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), fv_b[i_b]) == -1); + + STACK_PUSH(iv_ls_a, fv_b[i_b]); + STACK_PUSH(iv_ls_b, fv_b[i_b]); + b_mask |= (1 << i_b); +#ifdef USE_DUMP + printf(" 'VERT TRI-B',\n"); +#endif + } + } + } + } + + if ((STACK_SIZE(iv_ls_a) >= 3) && + (STACK_SIZE(iv_ls_b) >= 3)) + { +#ifdef USE_DUMP + printf("# OVERLAP\n"); +#endif + return; + } + + normal_tri_v3(f_a_nor, UNPACK3(f_a_cos)); + normal_tri_v3(f_b_nor, UNPACK3(f_b_cos)); + + /* edge-tri & edge-edge + * -------------------- */ + { + unsigned int i_e0; + for (i_e0 = 0; i_e0 < 3; i_e0++) { + unsigned int i_e1 = (i_e0 + 1) % 3; + enum ISectType side; + BMVert *iv; + if (((1 << i_e0) | (1 << i_e1)) & a_mask) + continue; + iv = bm_isect_edge_tri(s, fv_a[i_e0], fv_a[i_e1], fv_b, b_index, f_b_cos, f_b_nor, &side); + if (iv) { + BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1); + BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1); + STACK_PUSH(iv_ls_a, iv); + STACK_PUSH(iv_ls_b, iv); +#ifdef USE_DUMP + printf(" ('EDGE-TRI-A', %d),\n", side); +#endif + } + } + + for (i_e0 = 0; i_e0 < 3; i_e0++) { + unsigned int i_e1 = (i_e0 + 1) % 3; + enum ISectType side; + BMVert *iv; + if (((1 << i_e0) | (1 << i_e1)) & b_mask) + continue; + iv = bm_isect_edge_tri(s, fv_b[i_e0], fv_b[i_e1], fv_a, a_index, f_a_cos, f_a_nor, &side); + if (iv) { + /* check this wasn't handled above */ + if (!(side >= IX_EDGE_TRI_EDGE0 && side <= IX_EDGE_TRI_EDGE2)) { + BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1); + BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1); + STACK_PUSH(iv_ls_a, iv); + STACK_PUSH(iv_ls_b, iv); +#ifdef USE_DUMP + printf(" ('EDGE-RAY-B', %d),\n", side); +#endif + } + } + } + } + + { + for (i = 0; i < 2; i++) { + BMVert **ie_vs; + BMFace *f; + bool ie_exists; + BMEdge *ie; + + if (i == 0) { + if (STACK_SIZE(iv_ls_a) != 2) + continue; + ie_vs = iv_ls_a; + f = f_a; + } + else { + if (STACK_SIZE(iv_ls_b) != 2) + continue; + ie_vs = iv_ls_b; + f = f_b; + } + + /* possible but unlikely we get this - for edge-edge intersection */ + ie = BM_edge_exists(UNPACK2(ie_vs)); + if (ie == NULL) { + ie_exists = false; + /* one of the verts must be new if we are making an edge + * ...no, we need this in case 2x quads intersect at either ends. + * if not (ie_vs[0].index == -1 or ie_vs[1].index == -1): + * continue */ + ie = BM_edge_create(s->bm, UNPACK2(ie_vs), NULL, 0); + BLI_gset_insert(s->wire_edges, ie); + } + else { + ie_exists = true; + /* may already exist */ + BLI_gset_add(s->wire_edges, ie); + + if (BM_edge_in_face(ie, f)) { + continue; + } + } + + face_edges_add(s, BM_elem_index_get(f), ie, ie_exists); + // BLI_assert(len(ie_vs) <= 2) + } + } +} + +/** + * Intersect tessellated faces + * leaving the resulting edges tagged. + * + * \param test_fn Return value: -1: skip, 0: tree_a, 1: tree_b (use_self == false) + */ +bool BM_mesh_intersect( + BMesh *bm, + struct BMLoop *(*looptris)[3], const int looptris_tot, + int (*test_fn)(BMFace *f, void *user_data), void *user_data, + const bool use_self, const bool use_separate, + const float eps) +{ + struct ISectState s; + bool has_isect; + const int totface_orig = bm->totface; + +#ifdef USE_BVH + BVHTree *tree_a, *tree_b; + unsigned int tree_overlap_tot; + BVHTreeOverlap *overlap; +#else + int i_a, i_b; +#endif + + s.bm = bm; + + s.edgetri_cache = BLI_ghash_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__); + + s.edge_verts = BLI_ghash_ptr_new(__func__); + s.face_edges = BLI_ghash_ptr_new(__func__); + s.wire_edges = BLI_gset_ptr_new(__func__); + s.vert_dissolve = NULL; + + s.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + + /* setup epsilon from base */ + s.epsilon.eps = eps; + s.epsilon.eps2x = eps * 2.0f; + s.epsilon.eps_margin = s.epsilon.eps2x * 10.0f; + + s.epsilon.eps_sq = s.epsilon.eps * s.epsilon.eps; + s.epsilon.eps2x_sq = s.epsilon.eps2x * s.epsilon.eps2x; + s.epsilon.eps_margin_sq = s.epsilon.eps_margin * s.epsilon.eps_margin; + + BM_mesh_elem_index_ensure( + bm, + BM_VERT | + BM_EDGE | +#ifdef USE_NET + BM_FACE | +#endif + 0); + + + BM_mesh_elem_table_ensure( + bm, +#ifdef USE_SPLICE + BM_EDGE | +#endif +#ifdef USE_NET + BM_FACE | +#endif + 0); + +#ifdef USE_DISSOLVE + BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_VERT, BM_ELEM_TAG, false); +#endif + +#ifdef USE_DUMP + printf("data = [\n"); +#endif + +#ifdef USE_BVH + { + int i; + tree_a = BLI_bvhtree_new(looptris_tot, s.epsilon.eps_margin, 8, 8); + for (i = 0; i < looptris_tot; i++) { + if (test_fn(looptris[i][0]->f, user_data) == 0) { + const float t_cos[3][3] = { + {UNPACK3(looptris[i][0]->v->co)}, + {UNPACK3(looptris[i][1]->v->co)}, + {UNPACK3(looptris[i][2]->v->co)}, + }; + + BLI_bvhtree_insert(tree_a, i, (float *)t_cos, 3); + } + } + BLI_bvhtree_balance(tree_a); + } + + if (use_self == false) { + int i; + tree_b = BLI_bvhtree_new(looptris_tot, s.epsilon.eps_margin, 8, 8); + for (i = 0; i < looptris_tot; i++) { + if (test_fn(looptris[i][0]->f, user_data) == 1) { + const float t_cos[3][3] = { + {UNPACK3(looptris[i][0]->v->co)}, + {UNPACK3(looptris[i][1]->v->co)}, + {UNPACK3(looptris[i][2]->v->co)}, + }; + + BLI_bvhtree_insert(tree_b, i, (float *)t_cos, 3); + } + } + BLI_bvhtree_balance(tree_b); + } + else { + tree_b = tree_a; + } + + overlap = BLI_bvhtree_overlap(tree_b, tree_a, &tree_overlap_tot); + + if (overlap) { + unsigned int i; + + for (i = 0; i < tree_overlap_tot; i++) { +#ifdef USE_DUMP + printf(" ((%d, %d), (\n", + overlap[i].indexA, + overlap[i].indexB); +#endif + bm_isect_tri_tri( + &s, + overlap[i].indexA, + overlap[i].indexB, + looptris[overlap[i].indexA], + looptris[overlap[i].indexB]); +#ifdef USE_DUMP + printf(")),\n"); +#endif + } + MEM_freeN(overlap); + } + BLI_bvhtree_free(tree_a); + if (tree_a != tree_b) { + BLI_bvhtree_free(tree_b); + } + +#else + { + for (i_a = 0; i_a < looptris_tot; i_a++) { + const int t_a = test_fn(looptris[i_a][0]->f, user_data); + for (i_b = i_a + 1; i_b < looptris_tot; i_b++) { + const int t_b = test_fn(looptris[i_b][0]->f, user_data); + + if (use_self) { + if ((t_a != 0) || (t_b != 0)) { + continue; + } + } + else { + if ((t_a != t_b) && !ELEM(-1, t_a, t_b)) { + continue; + } + } + +#ifdef USE_DUMP + printf(" ((%d, %d), (", + i_a, i_b); +#endif + bm_isect_tri_tri( + &s, + i_a, + i_b, + looptris[i_a], + looptris[i_b]); +#ifdef USE_DUMP + printf(")),\n"); +#endif + } + } + } +#endif /* USE_BVH */ + +#ifdef USE_DUMP + printf("]\n"); +#endif + + /* --------- */ + +#ifdef USE_SPLICE + { + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, s.edge_verts) { + BMEdge *e = BLI_ghashIterator_getKey(&gh_iter); + struct LinkBase *v_ls_base = BLI_ghashIterator_getValue(&gh_iter); + + BMVert *v_start; + BMVert *v_end; + BMVert *v_prev; + bool is_wire; + + LinkNode *node; + + /* direction is arbitrary, could be swapped */ + v_start = e->v1; + v_end = e->v2; + + if (v_ls_base->list_len > 1) { + edge_verts_sort(v_start->co, v_ls_base); + } + +#ifdef USE_DUMP + printf("# SPLITTING EDGE: %d, %d\n", e_index, v_ls_base->list_len); +#endif + /* intersect */ + is_wire = BLI_gset_haskey(s.wire_edges, e); + +#ifdef USE_PARANOID + for (node = v_ls_base->list; node; node = node->next) { + BMVert *_v = node->link; + BLI_assert(len_squared_v3v3(_v->co, e->v1->co) > s.epsilon.eps_sq); + BLI_assert(len_squared_v3v3(_v->co, e->v2->co) > s.epsilon.eps_sq); + } +#endif + + v_prev = v_start; + + for (node = v_ls_base->list; node; node = node->next) { + BMVert *vi = node->link; + const float fac = line_point_factor_v3(vi->co, e->v1->co, e->v2->co); + + if (BM_vert_in_edge(e, v_prev)) { + v_prev = BM_edge_split(bm, e, v_prev, NULL, CLAMPIS(fac, 0.0f, 1.0f)); + BLI_assert( BM_vert_in_edge(e, v_end)); + + if (!BM_edge_exists(v_prev, vi) && + !BM_vert_splice_check_double(v_prev, vi) && + !BM_vert_pair_share_face_check(v_prev, vi)) + { + BM_vert_splice(bm, v_prev, vi); + } + else { + copy_v3_v3(v_prev->co, vi->co); + } + v_prev = vi; + if (is_wire) { + BLI_gset_insert(s.wire_edges, e); + } + } + } + } + } +#endif + + + /* important to handle before edgenet */ +#ifdef USE_DISSOLVE + { + /* first pass */ + BMVert *(*splice_ls)[2]; + STACK_DECLARE(splice_ls); + LinkNode *node; + + + for (node = s.vert_dissolve; node; node = node->next) { + BMVert *v = node->link; + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + if (!BM_vert_is_edge_pair(v)) { + BM_elem_flag_disable(v, BM_ELEM_TAG); + } + } + } + + splice_ls = MEM_mallocN((unsigned int)BLI_gset_size(s.wire_edges) * sizeof(*splice_ls), __func__); + STACK_INIT(splice_ls, (unsigned int)BLI_gset_size(s.wire_edges)); + + for (node = s.vert_dissolve; node; node = node->next) { + BMEdge *e_pair[2]; + BMVert *v = node->link; + BMVert *v_a, *v_b; + + if (!BM_elem_flag_test(v, BM_ELEM_TAG)) { + continue; + } + + /* get chain */ + e_pair[0] = v->e; + e_pair[1] = BM_DISK_EDGE_NEXT(v->e, v); + + if (BM_elem_flag_test(e_pair[0], BM_ELEM_TAG) || + BM_elem_flag_test(e_pair[1], BM_ELEM_TAG)) + { + continue; + } + + v_a = BM_edge_other_vert(e_pair[0], v); + v_b = BM_edge_other_vert(e_pair[1], v); + + /* simple case */ + if (BM_elem_flag_test(v_a, BM_ELEM_TAG) && + BM_elem_flag_test(v_b, BM_ELEM_TAG)) + { + /* only start on an edge-case */ + /* pass */ + } + else if ((!BM_elem_flag_test(v_a, BM_ELEM_TAG)) && + (!BM_elem_flag_test(v_b, BM_ELEM_TAG))) + { + /* simple case, single edge spans face */ + BMVert **splice_pair; + BM_elem_flag_enable(e_pair[1], BM_ELEM_TAG); + splice_pair = STACK_PUSH_RET(splice_ls); + splice_pair[0] = v; + splice_pair[1] = v_b; +#ifdef USE_DUMP + printf("# Simple Case!\n"); +#endif + } + else { +#ifdef USE_PARANOID + BMEdge *e_keep; +#endif + BMEdge *e; + BMEdge *e_step; + BMVert *v_step; + + /* walk the chain! */ + if (BM_elem_flag_test(v_a, BM_ELEM_TAG)) { + e = e_pair[0]; +#ifdef USE_PARANOID + e_keep = e_pair[1]; +#endif + } + else { + SWAP(BMVert *, v_a, v_b); + e = e_pair[1]; +#ifdef USE_PARANOID + e_keep = e_pair[0]; +#endif + } + + /* WALK */ + v_step = v; + e_step = e; + + while (true) { + BMEdge *e_next; + BMVert *v_next; + + v_next = BM_edge_other_vert(e_step, v_step); + BM_elem_flag_enable(e_step, BM_ELEM_TAG); + if (!BM_elem_flag_test(v_next, BM_ELEM_TAG)) { + BMVert **splice_pair; +#ifdef USE_PARANOID + BLI_assert(e_step != e_keep); +#endif + splice_pair = STACK_PUSH_RET(splice_ls); + splice_pair[0] = v; + splice_pair[1] = v_next; + break; + } + else { + e_next = bm_vert_other_edge(v_next, e_step); + } + + e_step = e_next; + v_step = v_next; + BM_elem_flag_enable(e_step, BM_ELEM_TAG); +#ifdef USE_PARANOID + BLI_assert(e_step != e_keep); +#endif +#ifdef USE_DUMP + printf("# walk step %p %p\n", e_next, v_next); +#endif + } +#ifdef USE_PARANOID + BLI_assert(BM_elem_flag_test(e_keep, BM_ELEM_TAG) == 0); +#endif + } + } + + /* Remove edges! */ + { + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, s.face_edges) { + struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); + LinkNode **node_prev_p; + unsigned int i; + + node_prev_p = &e_ls_base->list; + for (i = 0, node = e_ls_base->list; node; i++, node = node->next) { + BMEdge *e = node->link; + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + /* allocated by arena, don't free */ + *node_prev_p = node->next; + e_ls_base->list_len--; + } + else { + node_prev_p = &node->next; + } + } + } + } + + { + BMIter eiter; + BMEdge *e, *e_next; + + BM_ITER_MESH_MUTABLE (e, e_next, &eiter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + + /* in rare and annoying cases, + * there can be faces from 's.face_edges' removed by the edges. + * These are degenerate cases, so just make sure we don't reference the faces again. */ + if (e->l) { + BMLoop *l_iter = e->l; + BMFace **faces; + + faces = bm->ftable; + + do { + const int f_index = BM_elem_index_get(l_iter->f); + if (f_index >= 0) { + BLI_assert(f_index < totface_orig); + /* we could check if these are in: 's.face_edges', but easier just to remove */ + faces[f_index] = NULL; + } + } while ((l_iter = l_iter->radial_next) != e->l); + } + + BLI_gset_remove(s.wire_edges, e, NULL); + BM_edge_kill(bm, e); + } + } + } + + /* Remove verts! */ + { + GSet *verts_invalid = BLI_gset_ptr_new(__func__); + + for (node = s.vert_dissolve; node; node = node->next) { + /* arena allocated, don't free */ + BMVert *v = node->link; + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + if (!v->e) { + BLI_gset_add(verts_invalid, v); + BM_vert_kill(bm, v); + } + } + } + + { + unsigned int i; + for (i = 0; i < STACK_SIZE(splice_ls); i++) { + if (!BLI_gset_haskey(verts_invalid, splice_ls[i][0]) && + !BLI_gset_haskey(verts_invalid, splice_ls[i][1])) + { + if (!BM_edge_exists(UNPACK2(splice_ls[i])) && + !BM_vert_splice_check_double(UNPACK2(splice_ls[i]))) + { + BM_vert_splice(bm, UNPACK2(splice_ls[i])); + } + } + } + } + + BLI_gset_free(verts_invalid, NULL); + } + + MEM_freeN(splice_ls); + } +#endif /* USE_DISSOLVE */ + + + /* now split faces */ +#ifdef USE_NET + { + GHashIterator gh_iter; + BMFace **faces; + + faces = bm->ftable; + + GHASH_ITER (gh_iter, s.face_edges) { + const int f_index = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter)); + BMFace *f; + struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter); + + BLI_assert(f_index >= 0 && f_index < totface_orig); + + f = faces[f_index]; + if (UNLIKELY(f == NULL)) { + continue; + } + + BLI_assert(BM_elem_index_get(f) == f_index); + + face_edges_split(bm, f, e_ls_base); + } + } +#else + (void)totface_orig; +#endif /* USE_NET */ + + +#ifdef USE_SEPARATE + if (use_separate) { + GSetIterator gs_iter; + + BM_mesh_elem_hflag_disable_all(bm, BM_EDGE, BM_ELEM_TAG, false); + + GSET_ITER (gs_iter, s.wire_edges) { + BMEdge *e = BLI_gsetIterator_getKey(&gs_iter); + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + + BM_mesh_edgesplit(bm, false, true, false); + } +#else + (void)use_separate; +#endif /* USE_SEPARATE */ + + has_isect = (BLI_ghash_size(s.face_edges) != 0); + + /* cleanup */ + BLI_ghash_free(s.edgetri_cache, NULL, NULL); + + BLI_ghash_free(s.edge_verts, NULL, NULL); + BLI_ghash_free(s.face_edges, NULL, NULL); + BLI_gset_free(s.wire_edges, NULL); + + BLI_memarena_free(s.mem_arena); + + return has_isect; +} diff --git a/source/blender/bmesh/tools/bmesh_intersect.h b/source/blender/bmesh/tools/bmesh_intersect.h new file mode 100644 index 00000000000..af6e510a8f6 --- /dev/null +++ b/source/blender/bmesh/tools/bmesh_intersect.h @@ -0,0 +1,35 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BMESH_INTERSECT_H__ +#define __BMESH_INTERSECT_H__ + +/** \file blender/bmesh/tools/bmesh_intersect.h + * \ingroup bmesh + */ + +bool BM_mesh_intersect( + BMesh *bm, + struct BMLoop *(*looptris)[3], const int looptris_tot, + int (*test_fn)(BMFace *f, void *user_data), void *user_data, + const bool use_self, const bool use_separate, + const float eps); + +#endif /* __BMESH_INTERSECT_H__ */ diff --git a/source/blender/bmesh/tools/bmesh_wireframe.c b/source/blender/bmesh/tools/bmesh_wireframe.c index e2ce31d15b9..79fea3e5da1 100644 --- a/source/blender/bmesh/tools/bmesh_wireframe.c +++ b/source/blender/bmesh/tools/bmesh_wireframe.c @@ -441,7 +441,7 @@ void BM_mesh_wireframe( BMVert *v_pos1 = verts_pos[i_1]; BMVert *v_pos2 = verts_pos[i_2]; - f_new = BM_face_create_quad_tri(bm, v_l1, v_l2, v_neg2, v_neg1, f_src, false); + f_new = BM_face_create_quad_tri(bm, v_l1, v_l2, v_neg2, v_neg1, f_src, BM_CREATE_NOP); if (mat_offset) f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max); BM_elem_flag_enable(f_new, BM_ELEM_TAG); l_new = BM_FACE_FIRST_LOOP(f_new); @@ -451,7 +451,7 @@ void BM_mesh_wireframe( BM_elem_attrs_copy(bm, bm, l_next, l_new->next); BM_elem_attrs_copy(bm, bm, l_next, l_new->next->next); - f_new = BM_face_create_quad_tri(bm, v_l2, v_l1, v_pos1, v_pos2, f_src, false); + f_new = BM_face_create_quad_tri(bm, v_l2, v_l1, v_pos1, v_pos2, f_src, BM_CREATE_NOP); if (mat_offset) f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max); BM_elem_flag_enable(f_new, BM_ELEM_TAG); @@ -469,7 +469,7 @@ void BM_mesh_wireframe( BMVert *v_b1 = verts_boundary[i_1]; BMVert *v_b2 = verts_boundary[i_2]; - f_new = BM_face_create_quad_tri(bm, v_b2, v_b1, v_neg1, v_neg2, f_src, false); + f_new = BM_face_create_quad_tri(bm, v_b2, v_b1, v_neg1, v_neg2, f_src, BM_CREATE_NOP); if (mat_offset) f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max); BM_elem_flag_enable(f_new, BM_ELEM_TAG); l_new = BM_FACE_FIRST_LOOP(f_new); @@ -479,7 +479,7 @@ void BM_mesh_wireframe( BM_elem_attrs_copy(bm, bm, l, l_new->next); BM_elem_attrs_copy(bm, bm, l, l_new->next->next); - f_new = BM_face_create_quad_tri(bm, v_b1, v_b2, v_pos2, v_pos1, f_src, false); + f_new = BM_face_create_quad_tri(bm, v_b1, v_b2, v_pos2, v_pos1, f_src, BM_CREATE_NOP); if (mat_offset) f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max); BM_elem_flag_enable(f_new, BM_ELEM_TAG); l_new = BM_FACE_FIRST_LOOP(f_new); diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index d27795b0ab2..6e2d337a32e 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -804,7 +804,7 @@ void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& a // evaluate_joint_world_transform_at_frame(temp, NULL, node, fra); // calc special matrix - mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL); + mul_m4_series(mat, irest, temp, irest_dae, rest); } else { copy_m4_m4(mat, matfra); @@ -1210,7 +1210,7 @@ void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vector<FCurv // evaluate_joint_world_transform_at_frame(temp, NULL, node, fra); // calc special matrix - mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL); + mul_m4_series(mat, irest, temp, irest_dae, rest); float rot[4], loc[3], scale[3]; @@ -1545,7 +1545,7 @@ Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node, // evaluate_joint_world_transform_at_frame(temp, NULL, node, fra); // calc special matrix - mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL); + mul_m4_series(mat, irest, temp, irest_dae, rest); } else { copy_m4_m4(mat, matfra); diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp index e34161f4aaa..bc1c4172f46 100644 --- a/source/blender/collada/ControllerExporter.cpp +++ b/source/blender/collada/ControllerExporter.cpp @@ -284,7 +284,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm) } if (oob_counter > 0) { - fprintf(stderr, "Ignored %d Vertex weigths which use index to non existing VGroup %ld.\n", oob_counter, joint_index_by_def_index.size()); + fprintf(stderr, "Ignored %d Vertex weights which use index to non existing VGroup %ld.\n", oob_counter, joint_index_by_def_index.size()); } } diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index bbbbbf211c6..8101e579098 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -483,6 +483,17 @@ void DocumentImporter::create_constraints(ExtraTags *et, Object *ob) } } +void DocumentImporter::report_unknown_reference(const COLLADAFW::Node &node, const std::string object_type) +{ + std::string id = node.getOriginalId(); + std::string name = node.getName(); + fprintf(stderr, + "error: node id=\"%s\", name=\"%s\" refers to an undefined %s.\n", + id.c_str(), + name.c_str(), + object_type.c_str()); +} + std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLADAFW::Node *parent_node, Scene *sce, Object *par, bool is_library_node) { Object *ob = NULL; @@ -538,10 +549,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA ob = mesh_importer.create_mesh_object(node, geom[geom_done], false, uid_material_map, material_texture_mapping_map); if (ob == NULL) { - fprintf(stderr, - "<node id=\"%s\", name=\"%s\" >...contains a reference to an unknown instance_mesh.\n", - id.c_str(), - name.c_str()); + report_unknown_reference(*node, "instance_mesh"); } else { objects_done->push_back(ob); @@ -554,9 +562,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA while (camera_done < camera.getCount()) { ob = create_camera_object(camera[camera_done], sce); if (ob == NULL) { - std::string id = node->getOriginalId(); - std::string name = node->getName(); - fprintf(stderr, "<node id=\"%s\", name=\"%s\" >...contains a reference to an unknown instance_camera.\n", id.c_str(), name.c_str()); + report_unknown_reference(*node, "instance_camera"); } else { objects_done->push_back(ob); @@ -568,18 +574,28 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA } while (lamp_done < lamp.getCount()) { ob = create_lamp_object(lamp[lamp_done], sce); - objects_done->push_back(ob); - if (parent_node == NULL) { - root_objects->push_back(ob); + if (ob == NULL) { + report_unknown_reference(*node, "instance_lamp"); + } + else { + objects_done->push_back(ob); + if (parent_node == NULL) { + root_objects->push_back(ob); + } } ++lamp_done; } while (controller_done < controller.getCount()) { COLLADAFW::InstanceGeometry *geom = (COLLADAFW::InstanceGeometry *)controller[controller_done]; ob = mesh_importer.create_mesh_object(node, geom, true, uid_material_map, material_texture_mapping_map); - objects_done->push_back(ob); - if (parent_node == NULL) { - root_objects->push_back(ob); + if (ob == NULL) { + report_unknown_reference(*node, "instance_controller"); + } + else { + objects_done->push_back(ob); + if (parent_node == NULL) { + root_objects->push_back(ob); + } } ++controller_done; } @@ -805,10 +821,14 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia // DIFFUSE // color if (ef->getDiffuse().isColor()) { + /* too high intensity can create artefacts (fireflies) + So here we take care that intensity is set to 0.8 wherever possible + */ col = ef->getDiffuse().getColor(); - ma->r = col.getRed(); - ma->g = col.getGreen(); - ma->b = col.getBlue(); + ma->ref = max_ffff(col.getRed(), col.getGreen(), col.getBlue(), 0.8); + ma->r = col.getRed() / ma->ref; + ma->g = col.getGreen() / ma->ref; + ma->b = col.getBlue() / ma->ref; } // texture else if (ef->getDiffuse().isTexture()) { diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h index 96aa7eb4578..5a7df9a41cf 100644 --- a/source/blender/collada/DocumentImporter.h +++ b/source/blender/collada/DocumentImporter.h @@ -171,6 +171,8 @@ private: std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map; std::string import_from_version; + + void report_unknown_reference(const COLLADAFW::Node &node, const std::string object_type); }; #endif diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index 211c34ed325..a4bf1d28366 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -84,7 +84,7 @@ static const char *bc_primTypeToStr(COLLADAFW::MeshPrimitive::PrimitiveType type case COLLADAFW::MeshPrimitive::TRIANGLE_FANS: return "TRIANGLE_FANS"; case COLLADAFW::MeshPrimitive::TRIANGLE_STRIPS: - return "TRIANGLE_FANS"; + return "TRIANGLE_STRIPS"; case COLLADAFW::MeshPrimitive::POINTS: return "POINTS"; case COLLADAFW::MeshPrimitive::UNDEFINED_PRIMITIVE_TYPE: diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp index 7ae1750d2ca..75928f9d189 100644 --- a/source/blender/collada/SkinInfo.cpp +++ b/source/blender/collada/SkinInfo.cpp @@ -34,6 +34,10 @@ /* COLLADABU_ASSERT, may be able to remove later */ #include "COLLADABUPlatform.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_compiler_attrs.h" + #include "BKE_object.h" #include "DNA_armature_types.h" #include "DNA_modifier_types.h" @@ -41,8 +45,6 @@ #include "ED_mesh.h" #include "ED_object.h" #include "BKE_action.h" -#include "BLI_listbase.h" -#include "BLI_math.h" #include "SkinInfo.h" #include "collada_utils.h" diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp index c3665a33ca4..595787b44ac 100644 --- a/source/blender/collada/TransformWriter.cpp +++ b/source/blender/collada/TransformWriter.cpp @@ -77,7 +77,7 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B BKE_object_to_mat4(ob, C); copy_v3_v3(ob->size, scale); - mul_serie_m4(tmat, ob->parent->obmat, ob->parentinv, C, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(tmat, ob->parent->obmat, ob->parentinv, C); // calculate local mat diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index a19433436f1..4bcdd4d9e34 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -39,7 +39,7 @@ set(INC ../nodes/intern ../render/extern/include ../render/intern/include - ../../../intern/opencl + ../../../extern/clew/include ../../../intern/guardedalloc ) @@ -175,6 +175,11 @@ set(SRC nodes/COM_GlareNode.cpp nodes/COM_GlareNode.h + nodes/COM_SunBeamsNode.cpp + nodes/COM_SunBeamsNode.h + operations/COM_SunBeamsOperation.cpp + operations/COM_SunBeamsOperation.h + nodes/COM_CornerPinNode.cpp nodes/COM_CornerPinNode.h nodes/COM_PlaneTrackDeformNode.cpp @@ -535,4 +540,6 @@ list(APPEND INC data_to_c(${CMAKE_CURRENT_SOURCE_DIR}/operations/COM_OpenCLKernels.cl ${CMAKE_CURRENT_BINARY_DIR}/operations/COM_OpenCLKernels.cl.h SRC) +add_definitions(-DCL_USE_DEPRECATED_OPENCL_1_1_APIS) + blender_add_lib(bf_compositor "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h index 2cf2c690d3e..9b22444cf7f 100644 --- a/source/blender/compositor/COM_compositor.h +++ b/source/blender/compositor/COM_compositor.h @@ -208,7 +208,7 @@ extern "C" { * * @see ExecutionGroup.execute Execute a complete ExecutionGroup. Halts until finished or breaked by user * @see ExecutionGroup.scheduleChunkWhenPossible Tries to schedule a single chunk, - * checks if all input data is available. Can trigger dependant chunks to be calculated + * checks if all input data is available. Can trigger dependent chunks to be calculated * @see ExecutionGroup.scheduleAreaWhenPossible Tries to schedule an area. This can be multiple chunks * (is called from [@ref ExecutionGroup.scheduleChunkWhenPossible]) * @see ExecutionGroup.scheduleChunk Schedule a chunk on the WorkScheduler diff --git a/source/blender/compositor/SConscript b/source/blender/compositor/SConscript index 073b100e156..eab40873f64 100644 --- a/source/blender/compositor/SConscript +++ b/source/blender/compositor/SConscript @@ -26,7 +26,7 @@ # ***** END GPL LICENSE BLOCK ***** Import ('env') -defs = ['GLEW_STATIC'] +defs = ['GLEW_STATIC', 'CL_USE_DEPRECATED_OPENCL_1_1_APIS'] sources_intern = env.Glob('intern/*.cpp') sources_nodes = env.Glob('nodes/*.cpp') @@ -37,7 +37,7 @@ incs = [ 'intern', 'nodes', 'operations', - '#/intern/opencl', + '#/extern/clew/include', '../blenkernel', '../blenlib', '../imbuf', diff --git a/source/blender/compositor/intern/COM_ChunkOrder.cpp b/source/blender/compositor/intern/COM_ChunkOrder.cpp index 1b7c435ecea..3b094609a26 100644 --- a/source/blender/compositor/intern/COM_ChunkOrder.cpp +++ b/source/blender/compositor/intern/COM_ChunkOrder.cpp @@ -34,7 +34,7 @@ ChunkOrder::ChunkOrder() void ChunkOrder::determineDistance(ChunkOrderHotspot **hotspots, unsigned int numberOfHotspots) { unsigned int index; - double distance = MAXFLOAT; + double distance = FLT_MAX; for (index = 0; index < numberOfHotspots; index++) { ChunkOrderHotspot *hotspot = hotspots[index]; double ndistance = hotspot->determineDistance(this->m_x, this->m_y); diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp index 9251e161839..99f66bcb5b4 100644 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ b/source/blender/compositor/intern/COM_Converter.cpp @@ -99,6 +99,7 @@ extern "C" { #include "COM_SetValueOperation.h" #include "COM_SplitViewerNode.h" #include "COM_Stabilize2dNode.h" +#include "COM_SunBeamsNode.h" #include "COM_SwitchNode.h" #include "COM_TextureNode.h" #include "COM_TimeNode.h" @@ -394,6 +395,9 @@ Node *Converter::convert(bNode *b_node) case CMP_NODE_CORNERPIN: node = new CornerPinNode(b_node); break; + case CMP_NODE_SUNBEAMS: + node = new SunBeamsNode(b_node); + break; } return node; } diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cpp b/source/blender/compositor/intern/COM_MemoryBuffer.cpp index c1916f4a68f..c59ecced93c 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.cpp +++ b/source/blender/compositor/intern/COM_MemoryBuffer.cpp @@ -178,162 +178,58 @@ void MemoryBuffer::addPixel(int x, int y, const float color[4]) } } - -// table of (exp(ar) - exp(a)) / (1 - exp(a)) for r in range [0, 1] and a = -2 -// used instead of actual gaussian, otherwise at high texture magnifications circular artifacts are visible -#define EWA_MAXIDX 255 -static const float EWA_WTS[EWA_MAXIDX + 1] = { - 1.f, 0.990965f, 0.982f, 0.973105f, 0.96428f, 0.955524f, 0.946836f, 0.938216f, 0.929664f, - 0.921178f, 0.912759f, 0.904405f, 0.896117f, 0.887893f, 0.879734f, 0.871638f, 0.863605f, - 0.855636f, 0.847728f, 0.839883f, 0.832098f, 0.824375f, 0.816712f, 0.809108f, 0.801564f, - 0.794079f, 0.786653f, 0.779284f, 0.771974f, 0.76472f, 0.757523f, 0.750382f, 0.743297f, - 0.736267f, 0.729292f, 0.722372f, 0.715505f, 0.708693f, 0.701933f, 0.695227f, 0.688572f, - 0.68197f, 0.67542f, 0.66892f, 0.662471f, 0.656073f, 0.649725f, 0.643426f, 0.637176f, - 0.630976f, 0.624824f, 0.618719f, 0.612663f, 0.606654f, 0.600691f, 0.594776f, 0.588906f, - 0.583083f, 0.577305f, 0.571572f, 0.565883f, 0.56024f, 0.55464f, 0.549084f, 0.543572f, - 0.538102f, 0.532676f, 0.527291f, 0.521949f, 0.516649f, 0.511389f, 0.506171f, 0.500994f, - 0.495857f, 0.490761f, 0.485704f, 0.480687f, 0.475709f, 0.470769f, 0.465869f, 0.461006f, - 0.456182f, 0.451395f, 0.446646f, 0.441934f, 0.437258f, 0.432619f, 0.428017f, 0.42345f, - 0.418919f, 0.414424f, 0.409963f, 0.405538f, 0.401147f, 0.39679f, 0.392467f, 0.388178f, - 0.383923f, 0.379701f, 0.375511f, 0.371355f, 0.367231f, 0.363139f, 0.359079f, 0.355051f, - 0.351055f, 0.347089f, 0.343155f, 0.339251f, 0.335378f, 0.331535f, 0.327722f, 0.323939f, - 0.320186f, 0.316461f, 0.312766f, 0.3091f, 0.305462f, 0.301853f, 0.298272f, 0.294719f, - 0.291194f, 0.287696f, 0.284226f, 0.280782f, 0.277366f, 0.273976f, 0.270613f, 0.267276f, - 0.263965f, 0.26068f, 0.257421f, 0.254187f, 0.250979f, 0.247795f, 0.244636f, 0.241502f, - 0.238393f, 0.235308f, 0.232246f, 0.229209f, 0.226196f, 0.223206f, 0.220239f, 0.217296f, - 0.214375f, 0.211478f, 0.208603f, 0.20575f, 0.20292f, 0.200112f, 0.197326f, 0.194562f, - 0.191819f, 0.189097f, 0.186397f, 0.183718f, 0.18106f, 0.178423f, 0.175806f, 0.17321f, - 0.170634f, 0.168078f, 0.165542f, 0.163026f, 0.16053f, 0.158053f, 0.155595f, 0.153157f, - 0.150738f, 0.148337f, 0.145955f, 0.143592f, 0.141248f, 0.138921f, 0.136613f, 0.134323f, - 0.132051f, 0.129797f, 0.12756f, 0.125341f, 0.123139f, 0.120954f, 0.118786f, 0.116635f, - 0.114501f, 0.112384f, 0.110283f, 0.108199f, 0.106131f, 0.104079f, 0.102043f, 0.100023f, - 0.0980186f, 0.09603f, 0.094057f, 0.0920994f, 0.0901571f, 0.08823f, 0.0863179f, 0.0844208f, - 0.0825384f, 0.0806708f, 0.0788178f, 0.0769792f, 0.0751551f, 0.0733451f, 0.0715493f, 0.0697676f, - 0.0679997f, 0.0662457f, 0.0645054f, 0.0627786f, 0.0610654f, 0.0593655f, 0.0576789f, 0.0560055f, - 0.0543452f, 0.0526979f, 0.0510634f, 0.0494416f, 0.0478326f, 0.0462361f, 0.0446521f, 0.0430805f, - 0.0415211f, 0.039974f, 0.0384389f, 0.0369158f, 0.0354046f, 0.0339052f, 0.0324175f, 0.0309415f, - 0.029477f, 0.0280239f, 0.0265822f, 0.0251517f, 0.0237324f, 0.0223242f, 0.020927f, 0.0195408f, - 0.0181653f, 0.0168006f, 0.0154466f, 0.0141031f, 0.0127701f, 0.0114476f, 0.0101354f, 0.00883339f, - 0.00754159f, 0.00625989f, 0.00498819f, 0.00372644f, 0.00247454f, 0.00123242f, 0.f -}; - -static void ellipse_bounds(float A, float B, float C, float F, float &xmax, float &ymax) -{ - float denom = 4.0f * A * C - B * B; - if (denom > 0.0f && A != 0.0f && C != 0.0f) { - xmax = sqrtf(F) / (2.0f * A) * (sqrtf(F * (4.0f * A - B * B / C)) + B * B * sqrtf(F / (C * denom))); - ymax = sqrtf(F) / (2.0f * C) * (sqrtf(F * (4.0f * C - B * B / A)) + B * B * sqrtf(F / (A * denom))); +typedef struct ReadEWAData { + MemoryBuffer *buffer; + PixelSampler sampler; + float ufac, vfac; +} ReadEWAData; + +static void read_ewa_pixel_sampled(void *userdata, int x, int y, float result[4]) +{ + ReadEWAData *data = (ReadEWAData *) userdata; + switch (data->sampler) { + case COM_PS_NEAREST: + data->buffer->read(result, x, y); + break; + case COM_PS_BILINEAR: + data->buffer->readBilinear(result, + (float)x + data->ufac, + (float)y + data->vfac); + break; + case COM_PS_BICUBIC: + /* TOOD(sergey): no readBicubic method yet */ + data->buffer->readBilinear(result, + (float)x + data->ufac, + (float)y + data->vfac); + break; + default: + zero_v4(result); + break; } - else { - xmax = 0.0f; - ymax = 0.0f; - } -} - -static void ellipse_params(float Ux, float Uy, float Vx, float Vy, - float &A, float &B, float &C, float &F, float &umax, float &vmax) -{ - A = Vx * Vx + Vy * Vy; - B = -2.0f * (Ux * Vx + Uy * Vy); - C = Ux * Ux + Uy * Uy; - F = A * C - B * B * 0.25f; - - float factor = (F != 0.0f ? (float)(EWA_MAXIDX + 1) / F : 0.0f); - A *= factor; - B *= factor; - C *= factor; - F = (float)(EWA_MAXIDX + 1); - - ellipse_bounds(A, B, C, sqrtf(F), umax, vmax); } -/** - * Filtering method based on - * "Creating raster omnimax images from multiple perspective views using the elliptical weighted average filter" - * by Ned Greene and Paul S. Heckbert (1986) - */ void MemoryBuffer::readEWA(float result[4], const float uv[2], const float derivatives[2][2], PixelSampler sampler) { - zero_v4(result); - int width = this->getWidth(), height = this->getHeight(); - if (width == 0 || height == 0) - return; - - float u = uv[0], v = uv[1]; - float Ux = derivatives[0][0], Vx = derivatives[1][0], Uy = derivatives[0][1], Vy = derivatives[1][1]; - float A, B, C, F, ue, ve; - ellipse_params(Ux, Uy, Vx, Vy, A, B, C, F, ue, ve); + ReadEWAData data; + data.buffer = this; + data.sampler = sampler; + data.ufac = uv[0] - floorf(uv[0]); + data.vfac = uv[1] - floorf(uv[1]); - /* Note: highly eccentric ellipses can lead to large texture space areas to filter! - * This is limited somewhat by the EWA_WTS size in the loop, but a nicer approach - * could be the one found in - * "High Quality Elliptical Texture Filtering on GPU" - * by Pavlos Mavridis and Georgios Papaioannou - * in which the eccentricity of the ellipse is clamped. - */ - - int U0 = (int)u; - int V0 = (int)v; - /* pixel offset for interpolation */ - float ufac = u - floorf(u), vfac = v - floorf(v); - /* filter size */ - int u1 = (int)(u - ue); - int u2 = (int)(u + ue); - int v1 = (int)(v - ve); - int v2 = (int)(v + ve); - - /* sane clamping to avoid unnecessarily huge loops */ - /* note: if eccentricity gets clamped (see above), - * the ue/ve limits can also be lowered accordingly + int width = this->getWidth(), height = this->getHeight(); + /* TODO(sergey): Render pipeline uses normalized coordinates and derivatives, + * but compositor uses pixel space. For now let's just divide the values and + * switch compositor to normalized space for EWA later. */ - if (U0 - u1 > EWA_MAXIDX) u1 = U0 - EWA_MAXIDX; - if (u2 - U0 > EWA_MAXIDX) u2 = U0 + EWA_MAXIDX; - if (V0 - v1 > EWA_MAXIDX) v1 = V0 - EWA_MAXIDX; - if (v2 - V0 > EWA_MAXIDX) v2 = V0 + EWA_MAXIDX; - - /* Early output check for cases the whole region is outside of the buffer. */ - if ((u2 < m_rect.xmin || u1 >= m_rect.xmax) || - (v2 < m_rect.ymin || v1 >= m_rect.ymax)) - { - zero_v4(result); - return; - } - - /* Clamp sampling rectagle to the buffer dimensions. */ - u1 = max_ii(u1, m_rect.xmin); - u2 = min_ii(u2, m_rect.xmax); - v1 = max_ii(v1, m_rect.ymin); - v2 = min_ii(v2, m_rect.ymax); - - float DDQ = 2.0f * A; - float U = u1 - U0; - float ac1 = A * (2.0f * U + 1.0f); - float ac2 = A * U * U; - float BU = B * U; - - float sum = 0.0f; - for (int v = v1; v <= v2; ++v) { - float V = v - V0; - - float DQ = ac1 + B * V; - float Q = (C * V + BU) * V + ac2; - for (int u = u1; u <= u2; ++u) { - if (Q < F) { - float tc[4]; - const float wt = EWA_WTS[CLAMPIS((int)Q, 0, EWA_MAXIDX)]; - switch (sampler) { - case COM_PS_NEAREST: read(tc, u, v); break; - case COM_PS_BILINEAR: readBilinear(tc, (float)u + ufac, (float)v + vfac); break; - case COM_PS_BICUBIC: readBilinear(tc, (float)u + ufac, (float)v + vfac); break; /* XXX no readBicubic method yet */ - default: zero_v4(tc); break; - } - madd_v4_v4fl(result, tc, wt); - sum += wt; - } - Q += DQ; - DQ += DDQ; - } - } - - mul_v4_fl(result, (sum != 0.0f ? 1.0f / sum : 0.0f)); + float uv_normal[2] = {uv[0] / width, uv[1] / height}; + float du_normal[2] = {derivatives[0][0] / width, derivatives[0][1] / height}; + float dv_normal[2] = {derivatives[1][0] / width, derivatives[1][1] / height}; + + BLI_ewa_filter(this->getWidth(), this->getHeight(), + false, + true, + uv_normal, du_normal, dv_normal, + read_ewa_pixel_sampled, + &data, + result); } diff --git a/source/blender/compositor/intern/COM_NodeConverter.cpp b/source/blender/compositor/intern/COM_NodeConverter.cpp index 81a10a58cc5..208a3db812f 100644 --- a/source/blender/compositor/intern/COM_NodeConverter.cpp +++ b/source/blender/compositor/intern/COM_NodeConverter.cpp @@ -83,9 +83,9 @@ NodeOperation *NodeConverter::setInvalidOutput(NodeOutput *output) return operation; } -NodeOperationOutput *NodeConverter::addInputProxy(NodeInput *input) +NodeOperationOutput *NodeConverter::addInputProxy(NodeInput *input, bool use_conversion) { - SocketProxyOperation *proxy = new SocketProxyOperation(input->getDataType()); + SocketProxyOperation *proxy = new SocketProxyOperation(input->getDataType(), use_conversion); m_builder->addOperation(proxy); m_builder->mapInputSocket(input, proxy->getInputSocket(0)); @@ -93,9 +93,9 @@ NodeOperationOutput *NodeConverter::addInputProxy(NodeInput *input) return proxy->getOutputSocket(); } -NodeOperationInput *NodeConverter::addOutputProxy(NodeOutput *output) +NodeOperationInput *NodeConverter::addOutputProxy(NodeOutput *output, bool use_conversion) { - SocketProxyOperation *proxy = new SocketProxyOperation(output->getDataType()); + SocketProxyOperation *proxy = new SocketProxyOperation(output->getDataType(), use_conversion); m_builder->addOperation(proxy); m_builder->mapOutputSocket(output, proxy->getOutputSocket()); diff --git a/source/blender/compositor/intern/COM_NodeConverter.h b/source/blender/compositor/intern/COM_NodeConverter.h index e5e7629f39a..414b4f1ee95 100644 --- a/source/blender/compositor/intern/COM_NodeConverter.h +++ b/source/blender/compositor/intern/COM_NodeConverter.h @@ -70,12 +70,12 @@ public: * This operation will be removed later and replaced * by direct links between the connected operations. */ - NodeOperationOutput *addInputProxy(NodeInput *input); + NodeOperationOutput *addInputProxy(NodeInput *input, bool use_conversion); /** Create a proxy operation for a node output. * This operation will be removed later and replaced * by direct links between the connected operations. */ - NodeOperationInput *addOutputProxy(NodeOutput *output); + NodeOperationInput *addOutputProxy(NodeOutput *output, bool use_conversion); /** Define a constant input value. */ void addInputValue(NodeOperationInput *input, float value); diff --git a/source/blender/compositor/intern/COM_NodeGraph.cpp b/source/blender/compositor/intern/COM_NodeGraph.cpp index cbe47238249..2dcf419d81b 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.cpp +++ b/source/blender/compositor/intern/COM_NodeGraph.cpp @@ -202,7 +202,7 @@ void NodeGraph::add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink void NodeGraph::add_proxies_mute(bNodeTree *b_ntree, bNode *b_node, bNodeInstanceKey key, bool is_active_group) { for (bNodeLink *b_link = (bNodeLink *)b_node->internal_links.first; b_link; b_link = b_link->next) { - SocketProxyNode *proxy = new SocketProxyNode(b_node, b_link->fromsock, b_link->tosock); + SocketProxyNode *proxy = new SocketProxyNode(b_node, b_link->fromsock, b_link->tosock, false); add_node(proxy, b_ntree, key, is_active_group); } } @@ -219,7 +219,7 @@ void NodeGraph::add_proxies_skip(bNodeTree *b_ntree, bNode *b_node, bNodeInstanc } if (input) { - SocketProxyNode *proxy = new SocketProxyNode(b_node, input, output); + SocketProxyNode *proxy = new SocketProxyNode(b_node, input, output, true); add_node(proxy, b_ntree, key, is_active_group); } } @@ -237,7 +237,7 @@ void NodeGraph::add_proxies_group_inputs(bNode *b_node, bNode *b_node_io) for (bNodeSocket *b_sock_io = (bNodeSocket *)b_node_io->outputs.first; b_sock_io; b_sock_io = b_sock_io->next) { bNodeSocket *b_sock_group = find_b_node_input(b_node, b_sock_io->identifier); if (b_sock_group) { - SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_group, b_sock_io); + SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_group, b_sock_io, true); add_node(proxy, b_group_tree, key, is_active_group); } } @@ -260,7 +260,7 @@ void NodeGraph::add_proxies_group_outputs(bNode *b_node, bNode *b_node_io, bool add_node(buffer, b_group_tree, key, is_active_group); } else { - SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_io, b_sock_group); + SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_io, b_sock_group, true); add_node(proxy, b_group_tree, key, is_active_group); } } @@ -294,6 +294,6 @@ void NodeGraph::add_proxies_group(const CompositorContext &context, bNode *b_nod void NodeGraph::add_proxies_reroute(bNodeTree *b_ntree, bNode *b_node, bNodeInstanceKey key, bool is_active_group) { - SocketProxyNode *proxy = new SocketProxyNode(b_node, (bNodeSocket *)b_node->inputs.first, (bNodeSocket *)b_node->outputs.first); + SocketProxyNode *proxy = new SocketProxyNode(b_node, (bNodeSocket *)b_node->inputs.first, (bNodeSocket *)b_node->outputs.first, false); add_node(proxy, b_ntree, key, is_active_group); } diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h index 3f636dff63c..d9c16615fb6 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.h +++ b/source/blender/compositor/intern/COM_NodeOperation.h @@ -38,7 +38,7 @@ extern "C" { #include "COM_MemoryProxy.h" #include "COM_SocketReader.h" -#include "OCL_opencl.h" +#include "clew.h" using std::list; using std::min; @@ -288,6 +288,8 @@ public: virtual bool isFileOutputOperation() const { return false; } virtual bool isProxyOperation() const { return false; } + virtual bool useDatatypeConversion() const { return true; } + inline bool isBreaked() const { return this->m_btree->test_break(this->m_btree->tbh); } diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp index 6554926991c..fb5bc8fcd9b 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp @@ -269,6 +269,13 @@ void NodeOperationBuilder::add_datatype_conversions() Links convert_links; for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) { const Link &link = *it; + + /* proxy operations can skip data type conversion */ + NodeOperation *from_op = &link.from()->getOperation(); + NodeOperation *to_op = &link.to()->getOperation(); + if (!(from_op->useDatatypeConversion() || to_op->useDatatypeConversion())) + continue; + if (link.from()->getDataType() != link.to()->getDataType()) convert_links.push_back(link); } diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cpp index 2cfc10cff29..c5b663d2aef 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp +++ b/source/blender/compositor/intern/COM_OpenCLDevice.cpp @@ -103,7 +103,7 @@ void OpenCLDevice::COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel ker if (offsetIndex != -1) { cl_int error; rcti *rect = memoryBuffer->getRect(); - cl_int2 offset = {rect->xmin, rect->ymin}; + cl_int2 offset = {{rect->xmin, rect->ymin}}; error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset); if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); } @@ -114,7 +114,7 @@ void OpenCLDevice::COM_clAttachSizeToKernelParameter(cl_kernel kernel, int offse { if (offsetIndex != -1) { cl_int error; - cl_int2 offset = {(cl_int)operation->getWidth(), (cl_int)operation->getHeight()}; + cl_int2 offset = {{(cl_int)operation->getWidth(), (cl_int)operation->getHeight()}}; error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset); if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); } @@ -154,7 +154,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, MemoryBuffer *outputMemo bool breaked = false; for (offsety = 0; offsety < height && (!breaked); offsety += localSize) { - offset[1] = offsety; + offset.y = offsety; if (offsety + localSize < height) { size[1] = localSize; } @@ -169,7 +169,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, MemoryBuffer *outputMemo else { size[0] = width - offsetx; } - offset[0] = offsetx; + offset.x = offsetx; error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset); if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); } diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h index 50cc6f25f70..94df2f2b44c 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.h +++ b/source/blender/compositor/intern/COM_OpenCLDevice.h @@ -26,7 +26,7 @@ class OpenCLDevice; #define _COM_OpenCLDevice_h #include "COM_Device.h" -#include "OCL_opencl.h" +#include "clew.h" #include "COM_WorkScheduler.h" #include "COM_ReadBufferOperation.h" diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp index d60f9cb7f10..e1016731c7f 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.cpp +++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp @@ -28,7 +28,7 @@ #include "COM_CPUDevice.h" #include "COM_OpenCLDevice.h" #include "COM_OpenCLKernels.cl.h" -#include "OCL_opencl.h" +#include "clew.h" #include "COM_WriteBufferOperation.h" #include "MEM_guardedalloc.h" @@ -274,7 +274,7 @@ bool WorkScheduler::hasGPUDevices() #endif } -static void clContextError(const char *errinfo, const void *private_info, size_t cb, void *user_data) +static void CL_CALLBACK clContextError(const char *errinfo, const void *private_info, size_t cb, void *user_data) { printf("OPENCL error: %s\n", errinfo); } @@ -326,7 +326,7 @@ void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads) g_context = NULL; g_program = NULL; - if (!OCL_init()) /* this will check for errors and skip if already initialized */ + if (clewInit() != CLEW_SUCCESS) /* this will check for errors and skip if already initialized */ return; if (clCreateContextFromType) { diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp index 99655c67a3f..ec9ef6c7e68 100644 --- a/source/blender/compositor/intern/COM_compositor.cpp +++ b/source/blender/compositor/intern/COM_compositor.cpp @@ -32,7 +32,7 @@ extern "C" { #include "COM_compositor.h" #include "COM_ExecutionSystem.h" #include "COM_WorkScheduler.h" -#include "OCL_opencl.h" +#include "clew.h" #include "COM_MovieDistortionOperation.h" static ThreadMutex s_compositorMutex; diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp b/source/blender/compositor/nodes/COM_SocketProxyNode.cpp index f750a44a788..48c8acfc6a1 100644 --- a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp +++ b/source/blender/compositor/nodes/COM_SocketProxyNode.cpp @@ -29,7 +29,9 @@ #include "COM_WriteBufferOperation.h" #include "COM_ReadBufferOperation.h" -SocketProxyNode::SocketProxyNode(bNode *editorNode, bNodeSocket *editorInput, bNodeSocket *editorOutput) : Node(editorNode, false) +SocketProxyNode::SocketProxyNode(bNode *editorNode, bNodeSocket *editorInput, bNodeSocket *editorOutput, bool use_conversion) : + Node(editorNode, false), + m_use_conversion(use_conversion) { DataType dt; @@ -46,7 +48,7 @@ SocketProxyNode::SocketProxyNode(bNode *editorNode, bNodeSocket *editorInput, bN void SocketProxyNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const { - NodeOperationOutput *proxy_output = converter.addInputProxy(getInputSocket(0)); + NodeOperationOutput *proxy_output = converter.addInputProxy(getInputSocket(0), m_use_conversion); converter.mapOutputSocket(getOutputSocket(), proxy_output); } diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.h b/source/blender/compositor/nodes/COM_SocketProxyNode.h index 2fbaa71421c..5dbf39382cc 100644 --- a/source/blender/compositor/nodes/COM_SocketProxyNode.h +++ b/source/blender/compositor/nodes/COM_SocketProxyNode.h @@ -31,8 +31,15 @@ */ class SocketProxyNode : public Node { public: - SocketProxyNode(bNode *editorNode, bNodeSocket *editorInput, bNodeSocket *editorOutput); + SocketProxyNode(bNode *editorNode, bNodeSocket *editorInput, bNodeSocket *editorOutput, bool use_conversion); void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + + bool getUseConversion() const { return m_use_conversion; } + void setUseConversion(bool use_conversion) { m_use_conversion = use_conversion; } + +private: + /** If true, the proxy will convert input and output data to/from the proxy socket types. */ + bool m_use_conversion; }; diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp b/source/blender/compositor/nodes/COM_SunBeamsNode.cpp new file mode 100644 index 00000000000..ed14acabf36 --- /dev/null +++ b/source/blender/compositor/nodes/COM_SunBeamsNode.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2014, 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_SunBeamsNode.h" +#include "COM_SunBeamsOperation.h" + +SunBeamsNode::SunBeamsNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void SunBeamsNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const +{ + NodeInput *inputSocket = this->getInputSocket(0); + NodeOutput *outputSocket = this->getOutputSocket(0); + NodeSunBeams *data = (NodeSunBeams *)getbNode()->storage; + + SunBeamsOperation *operation = new SunBeamsOperation(); + operation->setData(*data); + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.h b/source/blender/compositor/nodes/COM_SunBeamsNode.h new file mode 100644 index 00000000000..4024eb276bc --- /dev/null +++ b/source/blender/compositor/nodes/COM_SunBeamsNode.h @@ -0,0 +1,37 @@ +/* + * Copyright 2014, 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_SunBeamsNode_h_ +#define _COM_SunBeamsNode_h_ + +#include "COM_Node.h" + +/** + * @brief SunBeamsNode + * @ingroup Node + */ +class SunBeamsNode : public Node { +public: + SunBeamsNode(bNode *editorNode); + void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; +}; + +#endif diff --git a/source/blender/compositor/nodes/COM_SwitchNode.cpp b/source/blender/compositor/nodes/COM_SwitchNode.cpp index 692b8d743f6..10f0ee3821d 100644 --- a/source/blender/compositor/nodes/COM_SwitchNode.cpp +++ b/source/blender/compositor/nodes/COM_SwitchNode.cpp @@ -33,9 +33,9 @@ void SwitchNode::convertToOperations(NodeConverter &converter, const CompositorC NodeOperationOutput *result; if (!condition) - result = converter.addInputProxy(getInputSocket(0)); + result = converter.addInputProxy(getInputSocket(0), false); else - result = converter.addInputProxy(getInputSocket(1)); + result = converter.addInputProxy(getInputSocket(1), false); converter.mapOutputSocket(getOutputSocket(0), result); } diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.h b/source/blender/compositor/operations/COM_BokehImageOperation.h index f1f0f1ed11c..3cf9afda32a 100644 --- a/source/blender/compositor/operations/COM_BokehImageOperation.h +++ b/source/blender/compositor/operations/COM_BokehImageOperation.h @@ -88,7 +88,7 @@ private: bool m_deleteData; /** - * @brief detemine the coordinate of a flap cornder + * @brief determine the coordinate of a flap cornder * * @param r result in bokehimage space are stored [x,y] * @param flapNumber the flap number to calculate diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp index b54e47c136d..cbf4ce693d9 100644 --- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp +++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp @@ -371,7 +371,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect) float *rectf = result->buffer; // temp holds maxima for every step in the algorithm, buf holds a - // single row or column of input values, padded with MAXFLOATs to + // single row or column of input values, padded with FLT_MAX's to // simplify the logic. float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp"); float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window), "dilate erode buf"); @@ -380,7 +380,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect) // first pass, horizontal dilate/erode for (y = ymin; y < ymax; y++) { for (x = 0; x < bwidth + 5 * half_window; x++) { - buf[x] = -MAXFLOAT; + buf[x] = -FLT_MAX; } for (x = xmin; x < xmax; ++x) { buf[x - rect->xmin + window - 1] = buffer[4 * (y * width + x)]; @@ -405,7 +405,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect) // second pass, vertical dilate/erode for (x = 0; x < bwidth; x++) { for (y = 0; y < bheight + 5 * half_window; y++) { - buf[y] = -MAXFLOAT; + buf[y] = -FLT_MAX; } for (y = ymin; y < ymax; y++) { buf[y - rect->ymin + window - 1] = rectf[(y - ymin) * bwidth + x]; @@ -498,7 +498,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) float *rectf = result->buffer; // temp holds maxima for every step in the algorithm, buf holds a - // single row or column of input values, padded with MAXFLOATs to + // single row or column of input values, padded with FLT_MAX's to // simplify the logic. float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp"); float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window), "dilate erode buf"); @@ -507,7 +507,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) // first pass, horizontal dilate/erode for (y = ymin; y < ymax; y++) { for (x = 0; x < bwidth + 5 * half_window; x++) { - buf[x] = MAXFLOAT; + buf[x] = FLT_MAX; } for (x = xmin; x < xmax; ++x) { buf[x - rect->xmin + window - 1] = buffer[4 * (y * width + x)]; @@ -532,7 +532,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) // second pass, vertical dilate/erode for (x = 0; x < bwidth; x++) { for (y = 0; y < bheight + 5 * half_window; y++) { - buf[y] = MAXFLOAT; + buf[y] = FLT_MAX; } for (y = ymin; y < ymax; y++) { buf[y - rect->ymin + window - 1] = rectf[(y - ymin) * bwidth + x]; diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp index 0cea2a7183f..67f52934b13 100644 --- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp @@ -109,8 +109,8 @@ void DirectionalBlurOperation::executeOpenCL(OpenCLDevice *device, cl_kernel directionalBlurKernel = device->COM_clCreateKernel("directionalBlurKernel", NULL); cl_int iterations = pow(2.0f, this->m_data->iter); - cl_float2 ltxy = {this->m_tx, this->m_ty}; - cl_float2 centerpix = {this->m_center_x_pix, this->m_center_y_pix}; + cl_float2 ltxy = {{this->m_tx, this->m_ty}}; + cl_float2 centerpix = {{this->m_center_x_pix, this->m_center_y_pix}}; cl_float lsc = this->m_sc; cl_float lrot = this->m_rot; diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cpp index cbc60b5091d..32a1e77b9a7 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp +++ b/source/blender/compositor/operations/COM_MathBaseOperation.cpp @@ -335,12 +335,11 @@ void MathModuloOperation::executePixelSampled(float output[4], float x, float y, void MathAbsoluteOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) { - float inputValue1[4]; + float inputValue1[4]; - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - output[0] = fabs(inputValue1[0]); + output[0] = fabs(inputValue1[0]); - clampIfNeeded(output); + clampIfNeeded(output); } - diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.h b/source/blender/compositor/operations/COM_MathBaseOperation.h index 05d2bb054d3..32cd19f1fb9 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.h +++ b/source/blender/compositor/operations/COM_MathBaseOperation.h @@ -165,8 +165,8 @@ public: class MathAbsoluteOperation : public MathBaseOperation { public: - MathAbsoluteOperation() : MathBaseOperation() {} - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + MathAbsoluteOperation() : MathBaseOperation() {} + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); }; #endif diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp b/source/blender/compositor/operations/COM_SocketProxyOperation.cpp index da345b282fd..21d2f28332e 100644 --- a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp +++ b/source/blender/compositor/operations/COM_SocketProxyOperation.cpp @@ -22,7 +22,9 @@ #include "COM_SocketProxyOperation.h" -SocketProxyOperation::SocketProxyOperation(DataType type) : NodeOperation() +SocketProxyOperation::SocketProxyOperation(DataType type, bool use_conversion) : + NodeOperation(), + m_use_conversion(use_conversion) { this->addInputSocket(type); this->addOutputSocket(type); diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.h b/source/blender/compositor/operations/COM_SocketProxyOperation.h index 9733a1fbeec..c9d6cb6ef9e 100644 --- a/source/blender/compositor/operations/COM_SocketProxyOperation.h +++ b/source/blender/compositor/operations/COM_SocketProxyOperation.h @@ -27,9 +27,16 @@ class SocketProxyOperation : public NodeOperation { public: - SocketProxyOperation(DataType type); + SocketProxyOperation(DataType type, bool use_conversion); bool isProxyOperation() const { return true; } + bool useDatatypeConversion() const { return m_use_conversion; } + + bool getUseConversion() const { return m_use_conversion; } + void setUseConversion(bool use_conversion) { m_use_conversion = use_conversion; } + +private: + bool m_use_conversion; }; #endif diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp new file mode 100644 index 00000000000..9a34dccacb1 --- /dev/null +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp @@ -0,0 +1,308 @@ +/* + * Copyright 2014, 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 "MEM_guardedalloc.h" + +#include "COM_SunBeamsOperation.h" + +SunBeamsOperation::SunBeamsOperation() : NodeOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + + this->setComplex(true); +} + +void SunBeamsOperation::initExecution() +{ + /* convert to pixels */ + this->m_source_px[0] = this->m_data.source[0] * this->getWidth(); + this->m_source_px[1] = this->m_data.source[1] * this->getHeight(); + this->m_ray_length_px = this->m_data.ray_length * max(this->getWidth(), this->getHeight()); +} + +/** + * Defines a line accumulator for a specific sector, + * given by the four matrix entries that rotate from buffer space into the sector + * + * (x,y) is used to designate buffer space coordinates + * (u,v) is used to designate sector space coordinates + * + * For a target point (x,y) the sector should be chosen such that + * ``u >= v >= 0`` + * This removes the need to handle all sorts of special cases. + */ +template <int fxx, int fxy, int fyx, int fyy> +struct BufferLineAccumulator { + + /* utility functions implementing the matrix transform to/from sector space */ + + static inline void buffer_to_sector(int x, int y, int &u, int &v) + { + u = x * fxx + y * fyx; + v = x * fxy + y * fyy; + } + + static inline void buffer_to_sector(float x, float y, float &u, float &v) + { + u = x * fxx + y * fyx; + v = x * fxy + y * fyy; + } + + static inline void sector_to_buffer(int u, int v, int &x, int &y) + { + x = u * fxx + v * fxy; + y = u * fyx + v * fyy; + } + + static inline void sector_to_buffer(float u, float v, float &x, float &y) + { + x = u * fxx + v * fxy; + y = u * fyx + v * fyy; + } + + /** + * Set up the initial buffer pointer and calculate necessary variables for looping. + * + * Note that sector space is centered around the "source" point while the loop starts + * at dist_min from the target pt. This way the loop can be canceled as soon as it runs + * out of the buffer rect, because no pixels further along the line can contribute. + * + * \param x, y Start location in the buffer + * \param num Total steps in the loop + * \param v, dv Vertical offset in sector space, for line offset perpendicular to the loop axis + */ + static float *init_buffer_iterator(MemoryBuffer *input, const float source[2], const float pt_ofs[2], + float dist_min, float dist_max, + int &x, int &y, int &num, float &v, float &dv, float &falloff_factor) + { + float pu, pv; + buffer_to_sector(pt_ofs[0], pt_ofs[1], pu, pv); + + /* line angle */ + float tan_phi = pv / pu; + float dr = sqrtf(tan_phi * tan_phi + 1.0f); + float cos_phi = 1.0f / dr; + + /* clamp u range to avoid influence of pixels "behind" the source */ + float umin = max_ff(pu - cos_phi * dist_min, 0.0f); + float umax = max_ff(pu - cos_phi * dist_max, 0.0f); + v = umin * tan_phi; + dv = tan_phi; + + int start = (int)floorf(umax); + int end = (int)ceilf(umin); + num = end - start; + + sector_to_buffer(end, (int)ceilf(v), x, y); + x += (int)source[0]; + y += (int)source[1]; + + falloff_factor = dist_max > dist_min ? dr / (float)(dist_max - dist_min) : 0.0f; + + float *iter = input->getBuffer() + COM_NUMBER_OF_CHANNELS * (x + input->getWidth() * y); + return iter; + } + + /** + * Perform the actual accumulation along a ray segment from source to pt. + * Only pixels withing dist_min..dist_max contribute. + * + * The loop runs backwards(!) over the primary sector space axis u, i.e. increasing distance to pt. + * After each step it decrements v by dv < 1, adding a buffer shift when necessary. + */ + static void eval(MemoryBuffer *input, float output[4], const float pt_ofs[2], const float source[2], + float dist_min, float dist_max) + { + rcti rect = *input->getRect(); + int buffer_width = input->getWidth(); + int x, y, num; + float v, dv; + float falloff_factor; + + /* initialise the iteration variables */ + float *buffer = init_buffer_iterator(input, source, pt_ofs, dist_min, dist_max, x, y, num, v, dv, falloff_factor); + + int tot = 0; + + /* v_local keeps track of when to decrement v (see below) */ + float v_local = v - floorf(v); + + for (int i = 0; i < num; i++) { + /* range check, abort when running beyond the image border */ + if (x < rect.xmin || x >= rect.xmax || y < rect.ymin || y >= rect.ymax) + break; + + float f = 1.0f - (float)i * falloff_factor; + madd_v4_v4fl(output, buffer, buffer[3] * f * f); + /* TODO implement proper filtering here, see + * http://en.wikipedia.org/wiki/Lanczos_resampling + * http://en.wikipedia.org/wiki/Sinc_function + * + * using lanczos with x = distance from the line segment, + * normalized to a == 0.5f, could give a good result + * + * for now just count samples and divide equally at the end ... + */ + tot++; + + /* decrement u */ + x -= fxx; + y -= fyx; + buffer -= (fxx + fyx * buffer_width) * COM_NUMBER_OF_CHANNELS; + + /* decrement v (in steps of dv < 1) */ + v_local -= dv; + if (v_local < 0.0f) { + v_local += 1.0f; + + x -= fxy; + y -= fyy; + buffer -= (fxy + fyy * buffer_width) * COM_NUMBER_OF_CHANNELS; + } + } + + /* normalize */ + if (num > 0) { + mul_v4_fl(output, 1.0f / (float)num); + } + } +}; + +/** + * Dispatch function which selects an appropriate accumulator based on the sector of the target point, + * relative to the source. + * + * The BufferLineAccumulator defines the actual loop over the buffer, with an efficient inner loop + * due to using compile time constants instead of a local matrix variable defining the sector space. + */ +static void accumulate_line(MemoryBuffer *input, float output[4], const float co[2], const float source[2], + float dist_min, float dist_max) +{ + /* coordinates relative to source */ + float pt_ofs[2] = {co[0] - source[0], co[1] - source[1]}; + + /* The source sectors are defined like so: + * + * \ 3 | 2 / + * \ | / + * 4 \ | / 1 + * \|/ + * ----------- + * /|\ + * 5 / | \ 8 + * / | \ + * / 6 | 7 \ + * + * The template arguments encode the transformation into "sector space", + * by means of rotation/mirroring matrix elements. + */ + + if (fabsf(pt_ofs[1]) > fabsf(pt_ofs[0])) { + if (pt_ofs[0] > 0.0f) { + if (pt_ofs[1] > 0.0f) { + /* 2 */ + BufferLineAccumulator<0, 1, 1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + else { + /* 7 */ + BufferLineAccumulator<0, 1, -1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + } + else { + if (pt_ofs[1] > 0.0f) { + /* 3 */ + BufferLineAccumulator<0, -1, 1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + else { + /* 6 */ + BufferLineAccumulator<0, -1, -1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + } + } + else { + if (pt_ofs[0] > 0.0f) { + if (pt_ofs[1] > 0.0f) { + /* 1 */ + BufferLineAccumulator< 1, 0, 0, 1>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + else { + /* 8 */ + BufferLineAccumulator< 1, 0, 0, -1>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + } + else { + if (pt_ofs[1] > 0.0f) { + /* 4 */ + BufferLineAccumulator<-1, 0, 0, 1>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + else { + /* 5 */ + BufferLineAccumulator<-1, 0, 0, -1>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + } + } +} + +void *SunBeamsOperation::initializeTileData(rcti *rect) +{ + void *buffer = getInputOperation(0)->initializeTileData(NULL); + return buffer; +} + +void SunBeamsOperation::executePixel(float output[4], int x, int y, void *data) +{ + const float co[2] = {(float)x, (float)y}; + + accumulate_line((MemoryBuffer *)data, output, co, this->m_source_px, 0.0f, this->m_ray_length_px); +} + +static void calc_ray_shift(rcti *rect, float x, float y, const float source[2], float ray_length) +{ + float co[2] = {(float)x, (float)y}; + float dir[2], dist; + + /* move (x,y) vector toward the source by ray_length distance */ + sub_v2_v2v2(dir, co, source); + dist = normalize_v2(dir); + mul_v2_fl(dir, min_ff(dist, ray_length)); + sub_v2_v2(co, dir); + + int ico[2] = {(int)co[0], (int)co[1]}; + BLI_rcti_do_minmax_v(rect, ico); +} + +bool SunBeamsOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + /* Enlarges the rect by moving each corner toward the source. + * This is the maximum distance that pixels can influence each other + * and gives a rect that contains all possible accumulated pixels. + */ + rcti rect = *input; + calc_ray_shift(&rect, input->xmin, input->ymin, this->m_source_px, this->m_ray_length_px); + calc_ray_shift(&rect, input->xmin, input->ymax, this->m_source_px, this->m_ray_length_px); + calc_ray_shift(&rect, input->xmax, input->ymin, this->m_source_px, this->m_ray_length_px); + calc_ray_shift(&rect, input->xmax, input->ymax, this->m_source_px, this->m_ray_length_px); + + return NodeOperation::determineDependingAreaOfInterest(&rect, readOperation, output); +} + diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.h b/source/blender/compositor/operations/COM_SunBeamsOperation.h new file mode 100644 index 00000000000..ef80a31fe40 --- /dev/null +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.h @@ -0,0 +1,48 @@ +/* + * Copyright 2014, 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_SunBeamsOperation_h +#define _COM_SunBeamsOperation_h + +#include "COM_NodeOperation.h" + +class SunBeamsOperation : public NodeOperation { +public: + SunBeamsOperation(); + + void executePixel(float output[4], int x, int y, void *data); + + void initExecution(); + + void *initializeTileData(rcti *rect); + + bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output); + + void setData(const NodeSunBeams &data) { m_data = data; } + +private: + NodeSunBeams m_data; + + float m_source_px[2]; + float m_ray_length_px; +}; + +#endif diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index b47e096dbff..c00fe6f103e 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -3845,7 +3845,7 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale short offset; /* sanity checks - don't draw anything */ - if (ELEM3(NULL, acf, ale, block)) + if (ELEM(NULL, acf, ale, block)) return; /* get initial offset */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 9997cc07c19..b6ab0407711 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -605,7 +605,7 @@ static int animedit_poll_channels_active(bContext *C) if (ELEM(NULL, sa, CTX_wm_region(C))) return 0; /* animation editor test */ - if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0) + if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0) return 0; return 1; @@ -622,7 +622,7 @@ static int animedit_poll_channels_nla_tweakmode_off(bContext *C) if (ELEM(NULL, sa, CTX_wm_region(C))) return 0; /* animation editor test */ - if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0) + if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0) return 0; /* NLA TweakMode test */ @@ -901,10 +901,10 @@ static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, b { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale, *ale_next; - int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); /* get all visible channels */ - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* now, only keep the ones that are of the types we are interested in */ for (ale = anim_data.first; ale; ale = ale_next) { @@ -2257,7 +2257,7 @@ static int animchannels_find_poll(bContext *C) return 0; /* animation editor with dopesheet */ - return ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA); + return ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA); } /* find_invoke() - Get initial channels */ @@ -2802,7 +2802,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, /* deselect all other channels */ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); - if (pchan) ED_pose_deselectall(ob, 0); + if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false); /* only select channels in group and group itself */ for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) @@ -2812,7 +2812,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, else { /* select group by itself */ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); - if (pchan) ED_pose_deselectall(ob, 0); + if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false); agrp->flag |= AGRP_SELECTED; } diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index 640349199be..f3b47b168e9 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -193,7 +193,7 @@ static void animchan_sync_fcurve(bAnimContext *ac, bAnimListElem *ale, FCurve ** /* major priority is selection status, so refer to the checks done in anim_filter.c * skip_fcurve_selected_data() for reference about what's going on here... */ - if (ELEM3(NULL, fcu, fcu->rna_path, owner_id)) + if (ELEM(NULL, fcu, fcu->rna_path, owner_id)) return; if (GS(owner_id->name) == ID_OB) { diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index d3e6d8f474f..57df6d32f03 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -63,7 +63,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) /* sanity checks */ if (name == NULL) return icon; - else if (ELEM3(NULL, id, fcu, fcu->rna_path)) { + else if (ELEM(NULL, id, fcu, fcu->rna_path)) { if (fcu == NULL) strcpy(name, IFACE_("<invalid>")); else if (fcu->rna_path == NULL) diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index da3d17b3190..0789aa6c148 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -204,7 +204,7 @@ void ED_markers_get_minmax(ListBase *markers, short sel, float *first, float *la /* sanity check */ //printf("markers = %p - %p, %p\n", markers, markers->first, markers->last); - if (ELEM3(NULL, markers, markers->first, markers->last)) { + if (ELEM(NULL, markers, markers->first, markers->last)) { *first = 0.0f; *last = 0.0f; return; @@ -603,24 +603,88 @@ typedef struct MarkerMove { NumInput num; } MarkerMove; +static bool ed_marker_move_use_time(MarkerMove *mm) +{ + if (((mm->slink->spacetype == SPACE_TIME) && !(((SpaceTime *)mm->slink)->flag & TIME_DRAWFRAMES)) || + ((mm->slink->spacetype == SPACE_SEQ) && !(((SpaceSeq *)mm->slink)->flag & SEQ_DRAWFRAMES)) || + ((mm->slink->spacetype == SPACE_ACTION) && (((SpaceAction *)mm->slink)->flag & SACTION_DRAWTIME)) || + ((mm->slink->spacetype == SPACE_IPO) && !(((SpaceIpo *)mm->slink)->flag & SIPO_DRAWTIME)) || + ((mm->slink->spacetype == SPACE_NLA) && !(((SpaceNla *)mm->slink)->flag & SNLA_DRAWTIME))) + { + return true; + } + + return false; +} + +static void ed_marker_move_update_header(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + MarkerMove *mm = op->customdata; + TimeMarker *marker, *selmarker = NULL; + const int offs = RNA_int_get(op->ptr, "frames"); + char str[256]; + char str_offs[NUM_STR_REP_LEN]; + int totmark; + const bool use_time = ed_marker_move_use_time(mm); + + for (totmark = 0, marker = mm->markers->first; marker; marker = marker->next) { + if (marker->flag & SELECT) { + selmarker = marker; + totmark++; + } + } + + if (hasNumInput(&mm->num)) { + outputNumInput(&mm->num, str_offs, &scene->unit); + } + else if (use_time) { + BLI_snprintf(str_offs, sizeof(str_offs), "%.2f", FRA2TIME(offs)); + } + else { + BLI_snprintf(str_offs, sizeof(str_offs), "%d", offs); + } + + if (totmark == 1 && selmarker) { + /* we print current marker value */ + if (use_time) { + BLI_snprintf(str, sizeof(str), "Marker %.2f offset %s", FRA2TIME(selmarker->frame), str_offs); + } + else { + BLI_snprintf(str, sizeof(str), "Marker %d offset %s", selmarker->frame, str_offs); + } + } + else { + BLI_snprintf(str, sizeof(str), "Marker offset %s", str_offs); + } + + ED_area_headerprint(CTX_wm_area(C), str); +} + /* copy selection to temp buffer */ /* return 0 if not OK */ -static int ed_marker_move_init(bContext *C, wmOperator *op) +static bool ed_marker_move_init(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ListBase *markers = ED_context_get_markers(C); MarkerMove *mm; TimeMarker *marker; - int totmark = 0; - int a; + int a, totmark; + + if (markers == NULL) { + return false; + } + + for (totmark = 0, marker = markers->first; marker; marker = marker->next) { + if (marker->flag & SELECT) { + totmark++; + } + } + + if (totmark == 0) { + return false; + } - if (markers == NULL) return 0; - - for (marker = markers->first; marker; marker = marker->next) - if (marker->flag & SELECT) totmark++; - - if (totmark == 0) return 0; - op->customdata = mm = MEM_callocN(sizeof(MarkerMove), "Markermove"); mm->slink = CTX_wm_space_data(C); mm->markers = markers; @@ -631,16 +695,16 @@ static int ed_marker_move_init(bContext *C, wmOperator *op) mm->num.val_flag[0] |= NUM_NO_FRACTION; mm->num.unit_sys = scene->unit.system; /* No time unit supporting frames currently... */ - mm->num.unit_type[0] = B_UNIT_NONE; - + mm->num.unit_type[0] = ed_marker_move_use_time(mm) ? B_UNIT_TIME : B_UNIT_NONE; + for (a = 0, marker = markers->first; marker; marker = marker->next) { if (marker->flag & SELECT) { mm->oldframe[a] = marker->frame; a++; } } - - return 1; + + return true; } /* free stuff */ @@ -671,7 +735,9 @@ static int ed_marker_move_invoke(bContext *C, wmOperator *op, const wmEvent *eve /* reset frs delta */ RNA_int_set(op->ptr, "frames", 0); - + + ed_marker_move_update_header(C, op); + return OPERATOR_RUNNING_MODAL; } @@ -725,138 +791,88 @@ static void ed_marker_move_cancel(bContext *C, wmOperator *op) ed_marker_move_exit(C, op); } - - static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = CTX_data_scene(C); MarkerMove *mm = op->customdata; View2D *v2d = UI_view2d_fromcontext(C); - TimeMarker *marker, *selmarker = NULL; - char str[256]; - - switch (event->type) { - case ESCKEY: - ed_marker_move_cancel(C, op); - return OPERATOR_CANCELLED; - case RIGHTMOUSE: - /* press = user manually demands transform to be canceled */ - if (event->val == KM_PRESS) { + const bool has_numinput = hasNumInput(&mm->num); + const bool use_time = ed_marker_move_use_time(mm); + + /* Modal numinput active, try to handle numeric inputs first... */ + if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &mm->num, event)) { + float value = (float)RNA_int_get(op->ptr, "frames"); + + applyNumInput(&mm->num, &value); + if (use_time) { + value = TIME2FRA(value); + } + + RNA_int_set(op->ptr, "frames", (int)value); + ed_marker_move_apply(C, op); + ed_marker_move_update_header(C, op); + } + else { + bool handled = false; + switch (event->type) { + case ESCKEY: ed_marker_move_cancel(C, op); return OPERATOR_CANCELLED; - } - /* else continue; <--- see if release event should be caught for tweak-end */ - - case RETKEY: - case PADENTER: - case LEFTMOUSE: - case MIDDLEMOUSE: - if (WM_modal_tweak_exit(event, mm->event_type)) { - ed_marker_move_exit(C, op); - WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL); - WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); - return OPERATOR_FINISHED; - } - break; - case MOUSEMOVE: - { - float dx, fac; - - if (hasNumInput(&mm->num)) - break; - - dx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); - - if (event->x != mm->evtx) { /* XXX maybe init for first time */ - int a, offs, totmark = 0; - - mm->evtx = event->x; - - fac = ((float)(event->x - mm->firstx) * dx); - - if (mm->slink->spacetype == SPACE_TIME) - apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0); - else - apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/); - - offs = (int)fac; - RNA_int_set(op->ptr, "frames", offs); - ed_marker_move_apply(C, op); - - /* cruft below is for header print */ - for (a = 0, marker = mm->markers->first; marker; marker = marker->next) { - if (marker->flag & SELECT) { - selmarker = marker; - a++; totmark++; - } + case RIGHTMOUSE: + /* press = user manually demands transform to be canceled */ + if (event->val == KM_PRESS) { + ed_marker_move_cancel(C, op); + return OPERATOR_CANCELLED; } - - if (totmark == 1) { - /* we print current marker value */ - if (mm->slink->spacetype == SPACE_TIME) { - SpaceTime *stime = (SpaceTime *)mm->slink; - if (stime->flag & TIME_DRAWFRAMES) - BLI_snprintf(str, sizeof(str), "Marker %d offset %d", selmarker->frame, offs); - else - BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs)); - } - else if (mm->slink->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)mm->slink; - if (saction->flag & SACTION_DRAWTIME) - BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs)); - else - BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs)); - } - else { - BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs)); - } + /* else continue; <--- see if release event should be caught for tweak-end */ + + case RETKEY: + case PADENTER: + case LEFTMOUSE: + case MIDDLEMOUSE: + if (WM_modal_tweak_exit(event, mm->event_type)) { + ed_marker_move_exit(C, op); + WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); + return OPERATOR_FINISHED; } - else { - /* we only print the offset */ - if (mm->slink->spacetype == SPACE_TIME) { - SpaceTime *stime = (SpaceTime *)mm->slink; - if (stime->flag & TIME_DRAWFRAMES) - BLI_snprintf(str, sizeof(str), "Marker offset %d ", offs); - else - BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs)); - } - else if (mm->slink->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)mm->slink; - if (saction->flag & SACTION_DRAWTIME) - BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs)); + break; + case MOUSEMOVE: + if (!has_numinput) { + float dx; + + dx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); + + if (event->x != mm->evtx) { /* XXX maybe init for first time */ + float fac; + + mm->evtx = event->x; + fac = ((float)(event->x - mm->firstx) * dx); + + if (mm->slink->spacetype == SPACE_TIME) + apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0); else - BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs)); - } - else { - BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs)); + apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/); + + RNA_int_set(op->ptr, "frames", (int)fac); + ed_marker_move_apply(C, op); + ed_marker_move_update_header(C, op); } } - - ED_area_headerprint(CTX_wm_area(C), str); - } - break; + break; } - } - if (event->val == KM_PRESS) { - if (handleNumInput(C, &mm->num, event)) { - char str_tx[NUM_STR_REP_LEN]; - float value = RNA_int_get(op->ptr, "frames"); - applyNumInput(&mm->num, &value); + if (!handled && event->val == KM_PRESS && handleNumInput(C, &mm->num, event)) { + float value = (float)RNA_int_get(op->ptr, "frames"); - if (hasNumInput(&mm->num)) { - outputNumInput(&mm->num, str_tx, scene->unit.scale_length); - } - else { - BLI_snprintf(str_tx, sizeof(str_tx), "%d", (int)value); + applyNumInput(&mm->num, &value); + if (use_time) { + value = TIME2FRA(value); } - RNA_int_set(op->ptr, "frames", value); + RNA_int_set(op->ptr, "frames", (int)value); ed_marker_move_apply(C, op); - // ed_marker_header_update(C, op, str, (int)value); - // strcat(str, str_tx); - BLI_snprintf(str, sizeof(str), "Marker offset %s", str_tx); - ED_area_headerprint(CTX_wm_area(C), str); + ed_marker_move_update_header(C, op); } } @@ -1011,14 +1027,14 @@ static void select_timeline_marker_frame(ListBase *markers, int frame, bool exte } } - LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) { + BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) { /* this way a not-extend select will allways give 1 selected marker */ if (marker->frame == frame) { marker->flag ^= SELECT; break; } } - LISTBASE_CIRCULAR_FORWARD_END (markers, marker, marker_first); + BLI_LISTBASE_CIRCULAR_FORWARD_END (markers, marker, marker_first); } static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool camera) diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 88429aa3867..0f202003dd8 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -72,7 +72,7 @@ static int change_frame_poll(bContext *C) * this shouldn't show up in 3D editor (or others without 2D timeline view) via search */ if (sa) { - if (ELEM5(sa->spacetype, SPACE_TIME, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) { + if (ELEM(sa->spacetype, SPACE_TIME, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) { return true; } else if (sa->spacetype == SPACE_IPO) { @@ -168,6 +168,7 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event) case LEFTMOUSE: case RIGHTMOUSE: + case MIDDLEMOUSE: /* we check for either mouse-button to end, as checking for ACTIONMOUSE (which is used to init * the modal op) doesn't work for some reason */ diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index ee5039488bd..83593faff22 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -670,8 +670,8 @@ static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *be if (bezt->f2 & SELECT) { bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1]; - if (ELEM3(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h1 = HD_ALIGN; - if (ELEM3(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h2 = HD_ALIGN; + if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h1 = HD_ALIGN; + if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h2 = HD_ALIGN; } return 0; } @@ -810,9 +810,9 @@ KeyframeEditFunc ANIM_editkeyframes_mirror(short type) */ #define ENSURE_HANDLES_MATCH(bezt) \ if (bezt->h1 != bezt->h2) { \ - if (ELEM3(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \ + if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \ bezt->h1 = HD_FREE; \ - if (ELEM3(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \ + if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \ bezt->h2 = HD_FREE; \ } (void)0 diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 640568a99e4..56165c36efa 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -408,8 +408,8 @@ void sample_fcurve(FCurve *fcu) * keyframes while sampling will affect the outcome... * - only start sampling+adding from index=1, so that we don't overwrite original keyframe */ - range = (int)(ceil(end->vec[1][0] - start->vec[1][0]) ); - sfra = (int)(floor(start->vec[1][0]) ); + range = (int)(ceil(end->vec[1][0] - start->vec[1][0])); + sfra = (int)(floor(start->vec[1][0])); if (range) { value_cache = MEM_callocN(sizeof(TempFrameValCache) * range, "IcuFrameValCache"); @@ -732,9 +732,9 @@ static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float bezt->vec[2][0] += offset; /* insert the keyframe - * NOTE: no special flags here for now + * NOTE: we do not want to inherit handles from existing keyframes in this case! */ - insert_bezt_fcurve(fcu, bezt, 0); + insert_bezt_fcurve(fcu, bezt, INSERTKEY_OVERWRITE_FULL); /* un-apply offset from src beztriple after copying */ bezt->vec[0][0] -= offset; diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 878c9193b23..4c2d90179a7 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -310,20 +310,25 @@ int insert_bezt_fcurve(FCurve *fcu, BezTriple *bezt, short flag) if (replace) { /* sanity check: 'i' may in rare cases exceed arraylen */ if ((i >= 0) && (i < fcu->totvert)) { - /* just change the values when replacing, so as to not overwrite handles */ - BezTriple *dst = (fcu->bezt + i); - float dy = bezt->vec[1][1] - dst->vec[1][1]; - - /* just apply delta value change to the handle values */ - dst->vec[0][1] += dy; - dst->vec[1][1] += dy; - dst->vec[2][1] += dy; - - dst->f1 = bezt->f1; - dst->f2 = bezt->f2; - dst->f3 = bezt->f3; - - /* TODO: perform some other operations? */ + if (flag & INSERTKEY_OVERWRITE_FULL) { + fcu->bezt[i] = *bezt; + } + else { + /* just change the values when replacing, so as to not overwrite handles */ + BezTriple *dst = (fcu->bezt + i); + float dy = bezt->vec[1][1] - dst->vec[1][1]; + + /* just apply delta value change to the handle values */ + dst->vec[0][1] += dy; + dst->vec[1][1] += dy; + dst->vec[2][1] += dy; + + dst->f1 = bezt->f1; + dst->f2 = bezt->f2; + dst->f3 = bezt->f3; + + /* TODO: perform some other operations? */ + } } } /* keyframing modes allow to not replace keyframe */ @@ -652,7 +657,7 @@ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) const char *identifier = NULL; /* validate data */ - if (ELEM3(NULL, ptr, ptr->data, prop)) + if (ELEM(NULL, ptr, ptr->data, prop)) return 0; /* get first constraint and determine type of keyframe constraints to check for @@ -1042,7 +1047,7 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou /* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor, * is determined by the array index for the F-Curve */ - if (ELEM5(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { + if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { fcu->color_mode = FCURVE_COLOR_AUTO_RGB; } } diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt index fc211f0e60b..d82da1c827f 100644 --- a/source/blender/editors/armature/CMakeLists.txt +++ b/source/blender/editors/armature/CMakeLists.txt @@ -23,10 +23,10 @@ set(INC ../../blenfont ../../blenkernel ../../blenlib - ../../gpu ../../makesdna ../../makesrna ../../windowmanager + ../../gpu ../../../../intern/guardedalloc ../../../../intern/glew-mx ) diff --git a/source/blender/editors/armature/SConscript b/source/blender/editors/armature/SConscript index b3c1ea2dbe9..c68045c9398 100644 --- a/source/blender/editors/armature/SConscript +++ b/source/blender/editors/armature/SConscript @@ -39,6 +39,7 @@ incs = [ '../../blenlib', '../../makesdna', '../../makesrna', + '../../gpu', '../../windowmanager', ] incs = ' '.join(incs) diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 16975eed75e..eba1bc4d78d 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -84,7 +84,7 @@ EditBone *ED_armature_edit_bone_add(bArmature *arm, const char *name) return bone; } -void add_primitive_bone(Object *obedit_arm, bool view_aligned) +EditBone *ED_armature_edit_bone_add_primitive(Object *obedit_arm, float length, bool view_aligned) { bArmature *arm = obedit_arm->data; EditBone *bone; @@ -99,10 +99,9 @@ void add_primitive_bone(Object *obedit_arm, bool view_aligned) zero_v3(bone->head); zero_v3(bone->tail); - if (view_aligned) - bone->tail[1] = 1.0f; - else - bone->tail[2] = 1.0f; + bone->tail[view_aligned ? 1 : 2] = length; + + return bone; } diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index f71cfd52175..1e4d9bac246 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -1343,7 +1343,9 @@ static int armature_reveal_exec(bContext *C, wmOperator *UNUSED(op)) for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (arm->layer & ebone->layer) { if (ebone->flag & BONE_HIDDEN_A) { - ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + if (!(ebone->flag & BONE_UNSELECTABLE)) { + ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + } ebone->flag &= ~BONE_HIDDEN_A; } } diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 9c3c93e4850..12d13b05ee1 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -160,7 +160,7 @@ void *get_nearest_bone(bContext *C, short findunsel, int x, int y) rect.ymin = rect.ymax = y; glInitNames(); - hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true); if (hits > 0) return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel); @@ -295,13 +295,13 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2], rect.ymin = mval[1] - 5; rect.ymax = mval[1] + 5; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true); if (hits == 0) { rect.xmin = mval[0] - 12; rect.xmax = mval[0] + 12; rect.ymin = mval[1] - 12; rect.ymax = mval[1] + 12; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true); } /* See if there are any selected bones in this group */ if (hits > 0) { diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index e898e600e9b..fbc18e977ce 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -180,15 +180,6 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap) return 0; } -static void add_vgroups__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) -{ - /* DerivedMesh mapFunc for getting final coords in weight paint mode */ - - float (*verts)[3] = userData; - copy_v3_v3(verts[index], co); -} - static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], const int *selected, float scale) @@ -200,10 +191,22 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i float distance; int i, iflip, j; bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0; + bool use_mask = false; + + if ((ob->mode & OB_MODE_WEIGHT_PAINT) && + (mesh->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL))) + { + use_mask = true; + } /* for each vertex in the mesh */ for (i = 0; i < mesh->totvert; i++) { - iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i, use_topology) : 0; + + if (use_mask && !(mesh->mvert[i].flag & SELECT)) { + continue; + } + + iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i, use_topology) : -1; /* for each skinnable bone */ for (j = 0; j < numbones; ++j) { @@ -224,7 +227,7 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i ED_vgroup_vert_remove(ob, dgroup, i); /* do same for mirror */ - if (dgroupflip && dgroupflip[j] && iflip >= 0) { + if (dgroupflip && dgroupflip[j] && iflip != -1) { if (distance != 0.0f) ED_vgroup_vert_add(ob, dgroupflip[j], iflip, distance, WEIGHT_REPLACE); @@ -362,7 +365,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); if (dm->foreachMappedVert) { - dm->foreachMappedVert(dm, add_vgroups__mapFunc, (void *)verts, DM_FOREACH_NOP); + mesh_get_mapped_verts_coords(dm, verts, mesh->totvert); vertsfilled = 1; } diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index ec139b9b2a1..85dcb2ed4da 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -53,6 +53,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "GPU_select.h" + typedef int (*GestureDetectFct)(bContext *, SK_Gesture *, SK_Sketch *); typedef void (*GestureApplyFct)(bContext *, SK_Gesture *, SK_Sketch *); @@ -493,7 +495,7 @@ static void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int gluQuadricNormals(quad, GLU_SMOOTH); if (id != -1) { - glLoadName(id); + GPU_select_load_id(id); for (i = 0; i < stk->nb_points; i++) { glPushMatrix(); @@ -1969,7 +1971,7 @@ static int sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], in rect.ymin = mval[1] - 5; rect.ymax = mval[1] + 5; - hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true); if (hits > 0) { int besthitresult = -1; @@ -2032,7 +2034,7 @@ static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch, sk_drawStroke(stk, id, NULL, -1, -1); } - glLoadName(-1); + GPU_select_load_id(-1); } else { float selected_rgb[3] = {1, 0, 0}; diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 56e7bde0081..49650fcadbf 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -635,8 +635,8 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; MVert *mvert = me->mvert; - bool use_vert_sel = false; - bool use_face_sel = false; + bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; *err_str = NULL; @@ -652,9 +652,8 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, return; /* count triangles and create mask */ - if (ob->mode == OB_MODE_WEIGHT_PAINT && - ((use_face_sel = ((me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0)) || - (use_vert_sel = ((me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0)))) + if (ob->mode & OB_MODE_WEIGHT_PAINT && + (use_face_sel || use_vert_sel)) { mask = MEM_callocN(sizeof(int) * me->totvert, "heat_bone_weighting mask"); diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 890bf6649b9..da68108285f 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -1074,7 +1074,9 @@ static int show_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr)) if (arm->layer & bone->layer) { if (bone->flag & BONE_HIDDEN_P) { bone->flag &= ~BONE_HIDDEN_P; - bone->flag |= BONE_SELECTED; + if (!(bone->flag & BONE_UNSELECTABLE)) { + bone->flag |= BONE_SELECTED; + } } } diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 0b115da5ff0..0609fcc29e8 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -307,7 +307,7 @@ static int poselib_sanitize_exec(bContext *C, wmOperator *op) /* check if any pose matches this */ /* TODO: don't go looking through the list like this every time... */ for (marker = act->markers.first; marker; marker = marker->next) { - if (IS_EQ(marker->frame, (double)ak->cfra)) { + if (IS_EQ((double)marker->frame, (double)ak->cfra)) { marker->flag = -1; break; } @@ -1417,7 +1417,7 @@ static void poselib_preview_init_data(bContext *C, wmOperator *op) pld->marker = (pld->act) ? BLI_findlink(&pld->act->markers, pose_index) : NULL; /* check if valid poselib */ - if (ELEM3(NULL, pld->ob, pld->pose, pld->arm)) { + if (ELEM(NULL, pld->ob, pld->pose, pld->arm)) { BKE_report(op->reports, RPT_ERROR, "Pose lib is only for armatures in pose mode"); pld->state = PL_PREVIEW_ERROR; return; @@ -1490,7 +1490,6 @@ static void poselib_preview_cleanup(bContext *C, wmOperator *op) DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */ else BKE_pose_where_is(scene, ob); - } else if (pld->state == PL_PREVIEW_CONFIRM) { /* tag poses as appropriate */ @@ -1511,6 +1510,9 @@ static void poselib_preview_cleanup(bContext *C, wmOperator *op) BKE_pose_where_is(scene, ob); } + /* Request final redraw of the view. */ + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pld->ob); + /* free memory used for backups and searching */ poselib_backup_free_data(pld); BLI_freelistN(&pld->searchp); diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index aa741ef9aaf..76284ba44de 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -69,6 +69,29 @@ /* ***************** Pose Select Utilities ********************* */ +/* Note: SEL_TOGGLE is assumed to have already been handled! */ +static void pose_do_bone_select(bPoseChannel *pchan, const int select_mode) +{ + /* select pchan only if selectable, but deselect works always */ + switch (select_mode) { + case SEL_SELECT: + if (!(pchan->bone->flag & BONE_UNSELECTABLE)) + pchan->bone->flag |= BONE_SELECTED; + break; + case SEL_DESELECT: + pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + break; + case SEL_INVERT: + if (pchan->bone->flag & BONE_SELECTED) { + pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + else if (!(pchan->bone->flag & BONE_UNSELECTABLE)) { + pchan->bone->flag |= BONE_SELECTED; + } + break; + } +} + /* Utility method for changing the selection status of a bone */ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select) { @@ -76,7 +99,7 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select) /* sanity checks */ // XXX: actually, we can probably still get away with no object - at most we have no updates - if (ELEM4(NULL, ob, ob->pose, pchan, pchan->bone)) + if (ELEM(NULL, ob, ob->pose, pchan, pchan->bone)) return; arm = ob->data; @@ -139,7 +162,7 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor } if (!extend && !deselect && !toggle) { - ED_pose_deselectall(ob, 0); + ED_pose_de_selectall(ob, SEL_DESELECT, true); nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); arm->act_bone = nearBone; } @@ -191,16 +214,12 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor return nearBone != NULL; } -/* test==0: deselect all - * test==1: swap select (apply to all the opposite of current situation) - * test==2: only clear active tag - * test==3: swap select (no test / inverse selection status of all independently) - */ -void ED_pose_deselectall(Object *ob, int test) +/* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT. + * When true, 'ignore_visibility' makes this func also affect invisible bones (hidden or on hidden layers). */ +void ED_pose_de_selectall(Object *ob, int select_mode, const bool ignore_visibility) { bArmature *arm = ob->data; bPoseChannel *pchan; - int selectmode = 0; /* we call this from outliner too */ if (ob->pose == NULL) { @@ -208,31 +227,23 @@ void ED_pose_deselectall(Object *ob, int test) } /* Determine if we're selecting or deselecting */ - if (test == 1) { + if (select_mode == SEL_TOGGLE) { + select_mode = SEL_SELECT; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (PBONE_VISIBLE(arm, pchan->bone)) { - if (pchan->bone->flag & BONE_SELECTED) + if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) { + if (pchan->bone->flag & BONE_SELECTED) { + select_mode = SEL_DESELECT; break; + } } } - - if (pchan == NULL) - selectmode = 1; } - else if (test == 2) - selectmode = 2; - /* Set the flags accordingly */ + /* Set the flags accordingly */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { /* ignore the pchan if it isn't visible or if its selection cannot be changed */ - if ((pchan->bone->layer & arm->layer) && !(pchan->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) { - if (test == 3) { - pchan->bone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else { - if (selectmode == 0) pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - else if (selectmode == 1) pchan->bone->flag |= BONE_SELECTED; - } + if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) { + pose_do_bone_select(pchan, select_mode); } } } @@ -353,24 +364,7 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op) /* Set the flags */ CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) { - /* select pchan only if selectable, but deselect works always */ - switch (action) { - case SEL_SELECT: - if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) - pchan->bone->flag |= BONE_SELECTED; - break; - case SEL_DESELECT: - pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - break; - case SEL_INVERT: - if (pchan->bone->flag & BONE_SELECTED) { - pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) { - pchan->bone->flag |= BONE_SELECTED; - } - break; - } + pose_do_bone_select(pchan, action); } CTX_DATA_END; @@ -644,7 +638,7 @@ static bool pose_select_same_group(bContext *C, Object *ob, bool extend) bool changed = false, tagged = false; /* sanity checks */ - if (ELEM3(NULL, ob, pose, arm)) + if (ELEM(NULL, ob, pose, arm)) return 0; /* count the number of groups */ @@ -701,7 +695,7 @@ static bool pose_select_same_layer(bContext *C, Object *ob, bool extend) bool changed = false; int layers = 0; - if (ELEM3(NULL, ob, pose, arm)) + if (ELEM(NULL, ob, pose, arm)) return 0; /* figure out what bones are selected */ @@ -761,7 +755,7 @@ static bool pose_select_same_keyingset(bContext *C, ReportList *reports, Object return false; } - if (ELEM3(NULL, ob, pose, arm)) + if (ELEM(NULL, ob, pose, arm)) return false; /* if not extending selection, deselect all selected first */ diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 375cbb0fe2b..5f9f24d23a4 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -134,7 +134,7 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode) pso->nextFrame = RNA_int_get(op->ptr, "next_frame"); /* check the settings from the context */ - if (ELEM4(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action)) + if (ELEM(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action)) return 0; else act = pso->ob->adt->action; diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 7b78b255a55..a52b2a619dc 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -1191,7 +1191,7 @@ static int *initialize_index_map(Object *obedit, int *r_old_totvert) for (nu = editnurb->nurbs.first, vertex_index = 0; nu != NULL; - nu = nu->next, vertex_index++) + nu = nu->next) { if (nu->bezt) { BezTriple *bezt = nu->bezt; @@ -1238,9 +1238,18 @@ static void remap_hooks_and_vertex_parents(Object *obedit) { Object *object; Curve *curve = (Curve *) obedit->data; + EditNurb *editnurb = curve->editnurb; int *old_to_new_map = NULL; int old_totvert; + if (editnurb->keyindex == NULL) { + /* TODO(sergey): Happens when separating curves, this would lead to + * the wrong indices in the hook modifier, address this together with + * other indices issues. + */ + return; + } + for (object = G.main->object.first; object; object = object->id.next) { ModifierData *md; int index; @@ -1467,37 +1476,6 @@ void ED_curve_select_swap(EditNurb *editnurb, bool hide_handles) } } -/******************** transform operator **********************/ - -void ED_curve_transform(Curve *cu, float mat[4][4]) -{ - Nurb *nu; - BPoint *bp; - BezTriple *bezt; - int a; - - float scale = mat4_to_scale(mat); - - for (nu = cu->nurb.first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - a = nu->pntsu; - for (bezt = nu->bezt; a--; bezt++) { - mul_m4_v3(mat, bezt->vec[0]); - mul_m4_v3(mat, bezt->vec[1]); - mul_m4_v3(mat, bezt->vec[2]); - bezt->radius *= scale; - } - BKE_nurb_handles_calc(nu); - } - else { - a = nu->pntsu * nu->pntsv; - for (bp = nu->bp; a--; bp++) - mul_m4_v3(mat, bp->vec); - } - } - DAG_id_tag_update(&cu->id, 0); -} - /******************** separate operator ***********************/ static int separate_exec(bContext *C, wmOperator *op) @@ -1975,17 +1953,15 @@ static void ed_curve_delete_selected(Object *obedit) next = nu->next; type = 0; if (nu->type == CU_BEZIER) { - int delta = 0; bezt = nu->bezt; for (a = 0; a < nu->pntsu; a++) { if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) { memmove(bezt, bezt + 1, (nu->pntsu - a - 1) * sizeof(BezTriple)); - keyIndex_delBezt(editnurb, bezt + delta); + keyIndex_delBezt(editnurb, bezt); keyIndex_updateBezt(editnurb, bezt + 1, bezt, nu->pntsu - a - 1); nu->pntsu--; a--; type = 1; - delta++; } else { bezt++; @@ -2001,18 +1977,16 @@ static void ed_curve_delete_selected(Object *obedit) } } else if (nu->pntsv == 1) { - int delta = 0; bp = nu->bp; for (a = 0; a < nu->pntsu; a++) { if (bp->f1 & SELECT) { memmove(bp, bp + 1, (nu->pntsu - a - 1) * sizeof(BPoint)); - keyIndex_delBP(editnurb, bp + delta); + keyIndex_delBP(editnurb, bp); keyIndex_updateBP(editnurb, bp + 1, bp, nu->pntsu - a - 1); nu->pntsu--; a--; type = 1; - delta++; } else { bp++; @@ -7023,7 +6997,7 @@ static int match_texture_space_poll(bContext *C) { Object *object = CTX_data_active_object(C); - return object && ELEM3(object->type, OB_CURVE, OB_SURF, OB_FONT); + return object && ELEM(object->type, OB_CURVE, OB_SURF, OB_FONT); } static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 3fc6e2e6f0d..2a84ca7f297 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -93,6 +93,8 @@ if(WITH_BLENDER) data_to_c_simple(../../../../release/datafiles/brushicons/soften.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/subtract.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/texdraw.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/texfill.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/texmask.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/thumb.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/twist.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/vertexdraw.png SRC) diff --git a/source/blender/editors/datafiles/SConscript b/source/blender/editors/datafiles/SConscript index 47819d0e33c..6bc8f21e384 100644 --- a/source/blender/editors/datafiles/SConscript +++ b/source/blender/editors/datafiles/SConscript @@ -77,6 +77,8 @@ sources.extend(( os.path.join(env['DATA_SOURCES'], "soften.png.c"), os.path.join(env['DATA_SOURCES'], "subtract.png.c"), os.path.join(env['DATA_SOURCES'], "texdraw.png.c"), + os.path.join(env['DATA_SOURCES'], "texfill.png.c"), + os.path.join(env['DATA_SOURCES'], "texmask.png.c"), os.path.join(env['DATA_SOURCES'], "thumb.png.c"), os.path.join(env['DATA_SOURCES'], "twist.png.c"), os.path.join(env['DATA_SOURCES'], "vertexdraw.png.c"), diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 6c73cc19d04..35982c63357 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -771,7 +771,7 @@ void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d) int offsx, offsy, winx, winy; /* check that we have grease-pencil stuff to draw */ - gpd = ED_gpencil_data_get_active_v3d(scene); // XXX + gpd = ED_gpencil_data_get_active_v3d(scene, v3d); if (gpd == NULL) return; /* when rendering to the offscreen buffer we don't want to diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index b725f5c773a..13334448941 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -62,6 +62,7 @@ #include "BKE_object.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "BKE_tracking.h" #include "UI_interface.h" @@ -186,15 +187,15 @@ bGPdata *ED_gpencil_data_get_active(const bContext *C) return (gpd_ptr) ? *(gpd_ptr) : NULL; } -/* needed for offscreen rendering */ -bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene) +bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d) { 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 ED_gpencil_data_get_active's behavior. */ - if (base && (scene->lay & base->lay) && (base->object->flag & SELECT)) { + + if (base && TESTBASE(v3d, base)) { gpd = base->object->gpd; } return gpd ? gpd : scene->gpd; @@ -1399,6 +1400,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd) { struct Main *bmain = CTX_data_main(C); + View3D *v3d = CTX_wm_view3d(C); /* may be NULL */ Scene *scene = CTX_data_scene(C); bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0); bGPDstroke *gps, *prev_gps = NULL; @@ -1412,7 +1414,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG rctf subrect, *subrect_ptr = NULL; /* error checking */ - if (ELEM3(NULL, gpd, gpl, gpf)) + if (ELEM(NULL, gpd, gpl, gpf)) return; /* only convert if there are any strokes on this layer's frame to convert */ @@ -1493,7 +1495,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG } /* set the layer and select */ - base_new->lay = ob->lay = base_orig ? base_orig->lay : scene->lay; + base_new->lay = ob->lay = base_orig ? base_orig->lay : BKE_screen_view3d_layer_active(v3d, scene); base_new->flag = ob->flag = base_new->flag | SELECT; } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 4910396ac6f..afecdd91599 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1861,7 +1861,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */ if (ISKEYBOARD(event->type)) { - if (ELEM4(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY)) { + if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY)) { /* allow some keys - for frame changing: [#33412] */ } else { @@ -1874,7 +1874,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* exit painting mode (and/or end current stroke) * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647] */ - if (ELEM4(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) { + if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) { /* exit() ends the current stroke before cleaning up */ /* printf("\t\tGP - end of paint op + end of stroke\n"); */ p->status = GP_STATUS_DONE; @@ -1949,7 +1949,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* eraser size */ else if ((p->paintmode == GP_PAINTMODE_ERASER) && - ELEM4(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS)) + ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS)) { /* just resize the brush (local version) * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys diff --git a/source/blender/editors/include/BIF_gl.h b/source/blender/editors/include/BIF_gl.h index 5f6c924f469..cd26bb22ada 100644 --- a/source/blender/editors/include/BIF_gl.h +++ b/source/blender/editors/include/BIF_gl.h @@ -58,8 +58,24 @@ * */ void cpack(unsigned int x); -#define glMultMatrixf(x) glMultMatrixf( (float *)(x)) -#define glLoadMatrixf(x) glLoadMatrixf( (float *)(x)) + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +# define glMultMatrixf(x) \ + glMultMatrixf(_Generic((x), \ + float *: (float *)(x), \ + float (*)[4]: (float *)(x), \ + const float *: (float *)(x), \ + const float (*)[4]: (float *)(x)) \ +) +# define glLoadMatrixf(x) \ + glLoadMatrixf(_Generic((x), \ + float *: (float *)(x), \ + float (*)[4]: (float *)(x)) \ +) +#else +# define glMultMatrixf(x) glMultMatrixf((float *)(x)) +# define glLoadMatrixf(x) glLoadMatrixf((float *)(x)) +#endif #define GLA_PIXEL_OFS 0.375f diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 7579f6cba65..6eac9f14bf6 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -133,8 +133,8 @@ EditBone *ED_armature_bone_get_mirrored(const struct ListBase *edbo, EditBone *e void ED_armature_sync_selection(struct ListBase *edbo); void ED_armature_validate_active(struct bArmature *arm); -void add_primitive_bone(struct Object *obedit_arm, bool view_aligned); -struct EditBone *ED_armature_edit_bone_add(struct bArmature *arm, const char *name); +EditBone *ED_armature_edit_bone_add_primitive(struct Object *obedit_arm, float length, bool view_aligned); +EditBone *ED_armature_edit_bone_add(struct bArmature *arm, const char *name); void ED_armature_edit_bone_remove(struct bArmature *arm, EditBone *exBone); bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child); @@ -174,7 +174,7 @@ 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); -void ED_pose_deselectall(struct Object *ob, int test); +void ED_pose_de_selectall(struct Object *ob, int select_mode, const bool ignore_visibility); void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select); 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_curve.h b/source/blender/editors/include/ED_curve.h index 330147db077..58e64f30b05 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -51,7 +51,6 @@ void ED_operatormacros_curve(void); void ED_keymap_curve(struct wmKeyConfig *keyconf); /* editcurve.c */ -void ED_curve_transform(struct Curve *cu, float mat[4][4]); void ED_curve_deselect_all(struct EditNurb *editnurb); void ED_curve_select_all(struct EditNurb *editnurb); void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles); diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h index 9022a1481aa..661ab58b98c 100644 --- a/source/blender/editors/include/ED_datafiles.h +++ b/source/blender/editors/include/ED_datafiles.h @@ -150,6 +150,12 @@ extern char datatoc_subtract_png[]; extern int datatoc_texdraw_png_size; extern char datatoc_texdraw_png[]; +extern int datatoc_texfill_png_size; +extern char datatoc_texfill_png[]; + +extern int datatoc_texmask_png_size; +extern char datatoc_texmask_png[]; + extern int datatoc_thumb_png_size; extern char datatoc_thumb_png[]; diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 63ffa1bef0c..05fb76b7aea 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -67,7 +67,7 @@ typedef struct tGPspoint { struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *ptr); struct bGPdata *ED_gpencil_data_get_active(const struct bContext *C); -struct bGPdata *ED_gpencil_data_get_active_v3d(struct Scene *scene); /* for offscreen rendering */ +struct bGPdata *ED_gpencil_data_get_active_v3d(struct Scene *scene, struct View3D *v3d); /* ----------- Grease Pencil Operators ----------------- */ diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index b15a83809f5..db13c628ade 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -69,8 +69,11 @@ void ED_image_point_pos__reverse(struct SpaceImage *sima, struct ARegion *ar, co bool ED_space_image_show_render(struct SpaceImage *sima); bool ED_space_image_show_paint(struct SpaceImage *sima); bool ED_space_image_show_uvedit(struct SpaceImage *sima, struct Object *obedit); +bool ED_space_image_show_texpaint(struct SpaceImage *sima, struct Object *ob); bool ED_space_image_show_uvshadow(struct SpaceImage *sima, struct Object *obedit); +bool ED_space_image_paint_curve(const struct bContext *C); + bool ED_space_image_check_show_maskedit(struct Scene *scene, struct SpaceImage *sima); int ED_space_image_maskedit_poll(struct bContext *C); int ED_space_image_maskedit_mask_poll(struct bContext *C); diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h index 4d19b6d5548..6636319dc9b 100644 --- a/source/blender/editors/include/ED_lattice.h +++ b/source/blender/editors/include/ED_lattice.h @@ -37,6 +37,5 @@ struct Lattice; void free_editLatt(struct Object *ob); void make_editLatt(struct Object *obedit); void load_editLatt(struct Object *obedit); -void ED_lattice_transform(struct Lattice *lt, float mat[4][4]); #endif /* __ED_LATTICE_H__ */ diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h index 680e9d79109..5e774c63841 100644 --- a/source/blender/editors/include/ED_mball.h +++ b/source/blender/editors/include/ED_mball.h @@ -50,6 +50,4 @@ void load_editMball(struct Object *obedit); void undo_push_mball(struct bContext *C, const char *name); -void ED_mball_transform(struct MetaBall *mb, float mat[4][4]); - #endif /* __ED_MBALL_H__ */ diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index ebc97c58e24..6a562da0a0e 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -119,7 +119,7 @@ void EDBM_mesh_reveal(struct BMEditMesh *em); void EDBM_update_generic(struct BMEditMesh *em, const bool do_tessface, const bool is_destructive); -struct UvElementMap *BM_uv_element_map_create(struct BMesh *em, const bool selected, const bool do_islands); +struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm, const bool selected, const bool do_islands); void BM_uv_element_map_free(struct UvElementMap *vmap); struct UvElement *BM_uv_element_get(struct UvElementMap *map, struct BMFace *efa, struct BMLoop *l); @@ -264,7 +264,6 @@ void ED_mesh_faces_remove(struct Mesh *mesh, struct ReportList *reports, int cou void ED_mesh_edges_remove(struct Mesh *mesh, struct ReportList *reports, int count); void ED_mesh_vertices_remove(struct Mesh *mesh, struct ReportList *reports, int count); -void ED_mesh_transform(struct Mesh *me, float mat[4][4]); void ED_mesh_calc_tessface(struct Mesh *mesh); void ED_mesh_update(struct Mesh *mesh, struct bContext *C, int calc_edges, int calc_tessface); diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h index 4e96ed0c7e7..f9a22429fc2 100644 --- a/source/blender/editors/include/ED_numinput.h +++ b/source/blender/editors/include/ED_numinput.h @@ -64,6 +64,8 @@ enum { /* (1 << 9) and above are reserved for internal flags! */ }; +struct UnitSettings; + /*********************** NumInput ********************************/ /* There are important things to note here for code using numinput: @@ -76,7 +78,7 @@ enum { */ void initNumInput(NumInput *n); -void outputNumInput(NumInput *n, char *str, const float scale_length); +void outputNumInput(NumInput *n, char *str, struct UnitSettings *unit_settings); bool hasNumInput(const NumInput *n); bool applyNumInput(NumInput *n, float *vec); bool handleNumInput(struct bContext *C, NumInput *n, const struct wmEvent *event); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 5504b7e0352..2328f7d5135 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -150,8 +150,9 @@ bool ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, c 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], - bool enter_editmode, unsigned int layer); +struct Object *ED_object_add_type( + struct bContext *C, int type, const float loc[3], const float rot[3], + bool enter_editmode, unsigned int layer) ATTR_RETURNS_NONNULL; 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); diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h index d7e84d8f50d..decd79fcc7b 100644 --- a/source/blender/editors/include/ED_paint.h +++ b/source/blender/editors/include/ED_paint.h @@ -28,9 +28,11 @@ struct bContext; struct RegionView3D; struct wmKeyConfig; +struct wmOperator; /* paint_ops.c */ void ED_operatortypes_paint(void); +void ED_operatormacros_paint(void); void ED_keymap_paint(struct wmKeyConfig *keyconf); /* paint_undo.c */ @@ -41,6 +43,7 @@ enum { typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb); typedef void (*UndoFreeCb)(struct ListBase *lb); +typedef bool (*UndoCleanupCb)(struct bContext *C, struct ListBase *lb); int ED_undo_paint_step(struct bContext *C, int type, int step, const char *name); void ED_undo_paint_step_num(struct bContext *C, int type, int num); @@ -48,7 +51,7 @@ const char *ED_undo_paint_get_name(struct bContext *C, int type, int nr, int *ac void ED_undo_paint_free(void); int ED_undo_paint_valid(int type, const char *name); bool ED_undo_paint_empty(int type); -void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free); +void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup); void ED_undo_paint_push_end(int type); /* paint_image.c */ @@ -57,5 +60,6 @@ void ED_image_undo_restore(struct bContext *C, struct ListBase *lb); void ED_image_undo_free(struct ListBase *lb); void ED_imapaint_clear_partial_redraw(void); void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h); +void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op); #endif /* __ED_PAINT_H__ */ diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h index 4fbe01a5fc7..d268c578cf2 100644 --- a/source/blender/editors/include/ED_space_api.h +++ b/source/blender/editors/include/ED_space_api.h @@ -35,6 +35,7 @@ struct ARegionType; struct bContext; void ED_spacetypes_init(void); +void ED_spacemacros_init(void); /* the pluginnable API for export to editors */ diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 41ff9b88da9..daa6864b5aa 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -98,6 +98,7 @@ enum TfmMode { #define CTX_NDOF (1 << 5) #define CTX_MOVIECLIP (1 << 6) #define CTX_MASK (1 << 7) +#define CTX_PAINT_CURVE (1 << 8) /* Standalone call to get the transformation center corresponding to the current situation * returns 1 if successful, 0 otherwise (usually means there's no selection) diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 04eb829979f..4b82fa40c6a 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -54,7 +54,7 @@ void ED_uvedit_assign_image(struct Main *bmain, struct Scene *scene, struct Obje bool ED_uvedit_minmax(struct Scene *scene, struct Image *ima, struct Object *obedit, float min[2], float max[2]); bool ED_object_get_active_image(struct Object *ob, int mat_nr, - struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node); + struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree); void ED_object_assign_active_image(struct Main *bmain, struct Object *ob, int mat_nr, struct Image *ima); bool ED_uvedit_test(struct Object *obedit); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 76839747076..bd4f37cfb1e 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -56,6 +56,7 @@ struct bContext; struct bPoseChannel; struct bScreen; struct bglMats; +struct rctf; struct rcti; struct wmOperator; struct wmOperatorType; @@ -84,6 +85,7 @@ typedef struct ViewDepths { float *ED_view3d_cursor3d_get(struct Scene *scene, struct View3D *v3d); void ED_view3d_cursor3d_position(struct bContext *C, float fp[3], const int mval[2]); +void ED_view3d_cursor3d_update(struct bContext *C, const int mval[2]); struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d); @@ -217,7 +219,8 @@ void ED_view3d_unproject(struct bglMats *mats, float out[3], const float x, cons /* end */ - +void ED_view3d_dist_range_get(struct View3D *v3d, + float r_dist_range[2]); bool ED_view3d_clip_range_get(struct View3D *v3d, struct RegionView3D *rv3d, float *r_clipsta, float *r_clipend, const bool use_ortho_factor); bool ED_view3d_viewplane_get(struct View3D *v3d, struct RegionView3D *rv3d, int winxi, int winyi, @@ -269,7 +272,7 @@ bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], con /* select */ #define MAXPICKBUF 10000 -short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input); +short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input, bool do_nearest); /* view3d_select.c */ float ED_view3d_select_dist_px(void); @@ -347,6 +350,7 @@ void ED_view3D_background_image_clear(struct View3D *v3d); #define VIEW3D_MARGIN 1.4f #define VIEW3D_DIST_FALLBACK 1.0f + float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float dist_fallback); void ED_view3d_distance_set(struct RegionView3D *rv3d, const float dist); @@ -364,6 +368,6 @@ void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op, int *winx, #endif /* render */ -void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa); +void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, 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 c776026a811..1d79cf749f9 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -668,8 +668,8 @@ DEF_ICON(IPO_EASE_IN_OUT) DEF_ICON(VERTEXSEL) DEF_ICON(EDGESEL) DEF_ICON(FACESEL) +DEF_ICON(LOOPSEL) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK209) DEF_ICON(BLANK210) #endif DEF_ICON(ROTATE) @@ -976,6 +976,8 @@ DEF_ICON(BRUSH_SNAKE_HOOK) DEF_ICON(BRUSH_SOFTEN) DEF_ICON(BRUSH_SUBTRACT) DEF_ICON(BRUSH_TEXDRAW) +DEF_ICON(BRUSH_TEXFILL) +DEF_ICON(BRUSH_TEXMASK) DEF_ICON(BRUSH_THUMB) DEF_ICON(BRUSH_ROTATE) DEF_ICON(BRUSH_VERTEXDRAW) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 1565583b574..1e9756ff771 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -75,6 +75,9 @@ struct ImBuf; struct bNodeTree; struct bNode; struct bNodeSocket; +struct wmDropBox; +struct wmDrag; +struct wmEvent; typedef struct uiBut uiBut; typedef struct uiBlock uiBlock; @@ -99,6 +102,7 @@ typedef struct uiLayout uiLayout; #define UI_EMBOSSN 1 /* Nothing, only icon and/or text */ #define UI_EMBOSSP 2 /* Pulldown menu style */ #define UI_EMBOSST 3 /* Table */ +#define UI_EMBOSSR 4 /* Pie Menu */ /* uiBlock->direction */ #define UI_DIRECTION (UI_TOP | UI_DOWN | UI_LEFT | UI_RIGHT) @@ -134,6 +138,7 @@ typedef struct uiLayout uiLayout; /* block->flag bits 14-17 are identical to but->drawflag bits */ #define UI_BLOCK_LIST_ITEM (1 << 19) +#define UI_BLOCK_RADIAL (1 << 20) /* uiPopupBlockHandle->menuretval */ #define UI_RETURN_CANCEL (1 << 0) /* cancel all menus cascading */ @@ -175,6 +180,7 @@ enum { UI_BUT_DRAG_MULTI = (1 << 25), /* edit this button as well as the active button (not just dragging) */ UI_BUT_SCA_LINK_GREY = (1 << 26), /* used to flag if sca links shoud be grey out */ UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */ + UI_BUT_TIP_FORCE = (1 << 28), /* force show tooltips when holding option/alt if U's USER_TOOLTIPS is off */ }; #define UI_PANEL_WIDTH 340 @@ -288,6 +294,9 @@ typedef enum { #define UI_GRAD_V_ALT 9 #define UI_GRAD_L_ALT 10 +#define UI_PALETTE_COLOR 20 +#define UI_PALETTE_COLOR_ACTIVE 1 + /* Drawing * * Functions to draw various shapes, taking theme settings into account. @@ -353,6 +362,17 @@ struct uiLayout *uiPupMenuLayout(uiPopupMenu *head); void uiPupMenuReports(struct bContext *C, struct ReportList *reports) ATTR_NONNULL(); bool uiPupMenuInvoke(struct bContext *C, const char *idname, struct ReportList *reports) ATTR_NONNULL(1, 2); +/* Pie menus */ +typedef struct uiPieMenu uiPieMenu; + +void uiPieMenuInvoke(struct bContext *C, const char *idname, const struct wmEvent *event); +void uiPieOperatorEnumInvoke(struct bContext *C, const char *title, const char *opname, + const char *propname, const struct wmEvent *event); +void uiPieEnumInvoke(struct bContext *C, const char *title, const char *path, const struct wmEvent *event); + +struct uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const struct wmEvent *event) ATTR_NONNULL(); +void uiPieMenuEnd(struct bContext *C, uiPieMenu *pie); +struct uiLayout *uiPieMenuLayout(struct uiPieMenu *pie); /* Popup Blocks * * Functions used to create popup blocks. These are like popup menus @@ -410,7 +430,8 @@ typedef enum { UI_BLOCK_BOUNDS_TEXT, UI_BLOCK_BOUNDS_POPUP_MOUSE, UI_BLOCK_BOUNDS_POPUP_MENU, - UI_BLOCK_BOUNDS_POPUP_CENTER + UI_BLOCK_BOUNDS_POPUP_CENTER, + UI_BLOCK_BOUNDS_PIE_CENTER, } eBlockBoundsCalc; void uiBoundsBlock(struct uiBlock *block, int addval); @@ -437,6 +458,7 @@ void uiButSetDragValue(uiBut *but); void uiButSetDragImage(uiBut *but, const char *path, int icon, struct ImBuf *ima, float scale); bool UI_but_active_drop_name(struct bContext *C); +bool UI_but_active_drop_color(struct bContext *C); void uiButSetFlag(uiBut *but, int flag); void uiButClearFlag(uiBut *but, int flag); @@ -697,7 +719,7 @@ void UI_panel_category_draw_all(struct ARegion *ar, const * as screen/ if ED_KEYMAP_UI is set, or internally in popup functions. */ void UI_add_region_handlers(struct ListBase *handlers); -void UI_add_popup_handlers(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup); +void UI_add_popup_handlers(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click); void UI_remove_popup_handlers(struct ListBase *handlers, uiPopupBlockHandle *popup); void UI_remove_popup_handlers_all(struct bContext *C, struct ListBase *handlers); @@ -708,7 +730,6 @@ void UI_remove_popup_handlers_all(struct bContext *C, struct ListBase *handlers) void UI_init(void); void UI_init_userdef(void); -void UI_init_userdef_factory(void); void UI_reinit_font(void); void UI_exit(void); @@ -730,6 +751,7 @@ void UI_exit(void); #define UI_LAYOUT_HEADER 1 #define UI_LAYOUT_MENU 2 #define UI_LAYOUT_TOOLBAR 3 +#define UI_LAYOUT_PIEMENU 4 #define UI_UNIT_X ((void)0, U.widget_unit) #define UI_UNIT_Y ((void)0, U.widget_unit) @@ -820,8 +842,8 @@ uiLayout *uiLayoutListBox(uiLayout *layout, struct uiList *ui_list, struct Point uiLayout *uiLayoutAbsolute(uiLayout *layout, int align); uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align); uiLayout *uiLayoutOverlap(uiLayout *layout); - uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout); +uiLayout *uiLayoutRadial(uiLayout *layout); /* templates */ void uiTemplateHeader(uiLayout *layout, struct bContext *C); @@ -847,6 +869,7 @@ void uiTemplateVectorscope(uiLayout *layout, struct PointerRNA *ptr, const char void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type, int levels, int brush, int neg_slope); void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic); +void uiTemplatePalette(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color); void uiTemplateLayers(uiLayout *layout, struct PointerRNA *ptr, const char *propname, PointerRNA *used_ptr, const char *used_propname, int active_layer); void uiTemplateGameStates(uiLayout *layout, struct PointerRNA *ptr, const char *propname, @@ -916,7 +939,14 @@ void uiItemMenuEnumO(uiLayout *layout, struct bContext *C, const char *opname, c void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon); /* UI Operators */ +typedef struct uiDragColorHandle { + float color[3]; + bool gamma_corrected; +} uiDragColorHandle; + void UI_buttons_operatortypes(void); +void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop); +int UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event); /* Helpers for Operators */ uiBut *uiContextActiveButton(const struct bContext *C); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 2e78940a813..872bd32b75b 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -106,6 +106,7 @@ enum { TH_FACE_SELECT, TH_NORMAL, TH_VNORMAL, + TH_LNORMAL, TH_FACE_DOT, TH_FACEDOT_SIZE, TH_CFRAME, @@ -237,6 +238,9 @@ enum { TH_STITCH_PREVIEW_UNSTITCHABLE, TH_STITCH_PREVIEW_ACTIVE, + TH_PAINT_CURVE_HANDLE, + TH_PAINT_CURVE_PIVOT, + TH_UV_SHADOW, TH_UV_OTHERS, diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index c059b16f1a0..c3f63f8a7fe 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -51,6 +51,7 @@ #include "BKE_context.h" #include "BKE_unit.h" +#include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_idprop.h" @@ -97,6 +98,11 @@ bool ui_block_is_menu(const uiBlock *block) ((block->flag & UI_BLOCK_KEEP_OPEN) == 0)); } +bool ui_block_is_pie_menu(const uiBlock *block) +{ + return ((block->flag & UI_BLOCK_RADIAL) != 0); +} + static bool ui_is_but_unit_radians_ex(UnitSettings *unit, const int unit_type) { return (unit->system_rotation == USER_UNIT_ROT_RADIANS && unit_type == PROP_UNIT_ROTATION); @@ -321,6 +327,20 @@ static void ui_centered_bounds_block(wmWindow *window, uiBlock *block) ui_bounds_block(block); } + +static void ui_centered_pie_bounds_block(uiBlock *block) +{ + const int xy[2] = { + block->pie_data.pie_center_spawned[0], + block->pie_data.pie_center_spawned[1] + }; + + ui_block_translate(block, xy[0], xy[1]); + + /* now recompute bounds and safety */ + ui_bounds_block(block); +} + static void ui_popup_bounds_block(wmWindow *window, uiBlock *block, eBlockBoundsCalc bounds_calc, const int xy[2]) { @@ -830,7 +850,7 @@ static void ui_menu_block_set_keyaccels(uiBlock *block) * fun first pass on all buttons so first word chars always get first priority */ for (but = block->buttons.first; but; but = but->next) { - if (!ELEM5(but->type, BUT, BUTM, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) { + if (!ELEM(but->type, BUT, BUTM, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) { /* pass */ } else if (but->menu_key == '\0') { @@ -1062,6 +1082,41 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but, return found; } +/* this goes in a seemingly weird pattern: + * + * 4 + * 5 6 + * 1 2 + * 7 8 + * 3 + * + * but it's actually quite logical. It's designed to be 'upwards compatible' + * for muscle memory so that the menu item locations are fixed and don't move + * as new items are added to the menu later on. It also optimises efficiency - + * a radial menu is best kept symmetrical, with as large an angle between + * items as possible, so that the gestural mouse movements can be fast and inexact. + + * It starts off with two opposite sides for the first two items + * then joined by the one below for the third (this way, even with three items, + * the menu seems to still be 'in order' reading left to right). Then the fourth is + * added to complete the compass directions. From here, it's just a matter of + * subdividing the rest of the angles for the last 4 items. + * + * --Matt 07/2006 + */ +const char ui_radial_dir_order[8] = { + UI_RADIAL_W, UI_RADIAL_E, UI_RADIAL_S, UI_RADIAL_N, + UI_RADIAL_NW, UI_RADIAL_NE, UI_RADIAL_SW, UI_RADIAL_SE}; + +const char ui_radial_dir_to_numpad[8] = {8, 9, 6, 3, 2, 1, 4, 7}; +const short ui_radial_dir_to_angle[8] = {90, 45, 0, 315, 270, 225, 180, 135}; + +static void ui_but_pie_direction_string(uiBut *but, char *buf, int size) +{ + BLI_assert(but->pie_dir < ARRAY_SIZE(ui_radial_dir_to_numpad)); + BLI_snprintf(buf, size, "%d", ui_radial_dir_to_numpad[but->pie_dir]); +} + static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) { uiBut *but; @@ -1071,13 +1126,23 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) if (block->rect.xmin != block->rect.xmax) return; - for (but = block->buttons.first; but; but = but->next) { - - if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) { - ui_but_add_shortcut(but, buf, false); + if (block->flag & UI_BLOCK_RADIAL) { + for (but = block->buttons.first; but; but = but->next) { + if (but->pie_dir != UI_RADIAL_NONE) { + ui_but_pie_direction_string(but, buf, sizeof(buf)); + ui_but_add_shortcut(but, buf, false); + } } - else if (ui_but_event_property_operator_string(C, but, buf, sizeof(buf))) { - ui_but_add_shortcut(but, buf, false); + } + else { + for (but = block->buttons.first; but; but = but->next) { + + if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) { + ui_but_add_shortcut(but, buf, false); + } + else if (ui_but_event_property_operator_string(C, but, buf, sizeof(buf))) { + ui_but_add_shortcut(but, buf, false); + } } } } @@ -1173,6 +1238,9 @@ void uiEndBlock_ex(const bContext *C, uiBlock *block, const int xy[2]) case UI_BLOCK_BOUNDS_POPUP_CENTER: ui_centered_bounds_block(window, block); break; + case UI_BLOCK_BOUNDS_PIE_CENTER: + ui_centered_pie_bounds_block(block); + break; /* fallback */ case UI_BLOCK_BOUNDS_POPUP_MOUSE: @@ -1244,6 +1312,10 @@ void uiDrawBlock(const bContext *C, uiBlock *block) rcti rect; int multisample_enabled; + /* early exit if cancelled */ + if ((block->flag & UI_BLOCK_RADIAL) && (block->pie_data.flags & UI_PIE_FINISHED)) + return; + /* get menu region or area region */ ar = CTX_wm_menu(C); if (!ar) @@ -1276,7 +1348,9 @@ void uiDrawBlock(const bContext *C, uiBlock *block) wmOrtho2(-0.01f, ar->winx - 0.01f, -0.01f, ar->winy - 0.01f); /* back */ - if (block->flag & UI_BLOCK_LOOP) + if (block->flag & UI_BLOCK_RADIAL) + ui_draw_pie_center(block); + else if (block->flag & UI_BLOCK_LOOP) ui_draw_menu_back(&style, block, &rect); else if (block->panel) ui_draw_aligned_panel(&style, block, &rect, UI_panel_category_is_visible(ar)); @@ -1317,7 +1391,7 @@ int ui_is_but_push_ex(uiBut *but, double *value) int is_push = 0; if (but->bit) { - const bool state = ELEM3(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true; + const bool state = ELEM(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true; int lvalue; UI_GET_BUT_VALUE_INIT(but, *value); lvalue = (int)*value; @@ -1446,7 +1520,7 @@ void uiComposeLinks(uiBlock *block) } } else if (link->poin) { - bt = ui_find_inlink(block, *(link->poin) ); + bt = ui_find_inlink(block, *link->poin); if (bt) { if ((but->flag & UI_BUT_SCA_LINK_GREY) || (bt->flag & UI_BUT_SCA_LINK_GREY)) { ui_add_link_line(&link->lines, but, bt, true); @@ -1627,7 +1701,7 @@ bool ui_is_but_float(const uiBut *but) bool ui_is_but_bool(const uiBut *but) { - if (ELEM4(but->type, TOG, TOGN, ICONTOG, ICONTOGN)) + if (ELEM(but->type, TOG, TOGN, ICONTOG, ICONTOGN)) return true; if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_BOOLEAN) @@ -1840,7 +1914,7 @@ void ui_set_but_val(uiBut *but, double value) int ui_get_but_string_max_length(uiBut *but) { - if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) + if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) return but->hardmax; else return UI_MAX_DRAW_STR; @@ -1866,27 +1940,13 @@ static double ui_get_but_scale_unit(uiBut *but, double value) UnitSettings *unit = but->block->unit; int unit_type = uiButGetUnitType(but); - if (unit_type == PROP_UNIT_LENGTH) { - return value * (double)unit->scale_length; - } - else if (unit_type == PROP_UNIT_CAMERA) { - return value * (double)unit->scale_length; - } - else if (unit_type == PROP_UNIT_AREA) { - return value * pow(unit->scale_length, 2); - } - else if (unit_type == PROP_UNIT_VOLUME) { - return value * pow(unit->scale_length, 3); - } - else if (unit_type == PROP_UNIT_MASS) { - return value * pow(unit->scale_length, 3); - } - else if (unit_type == PROP_UNIT_TIME) { /* WARNING - using evil_C :| */ + /* Time unit is a bit special, not handled by BKE_scene_unit_scale() for now. */ + if (unit_type == PROP_UNIT_TIME) { /* WARNING - using evil_C :| */ Scene *scene = CTX_data_scene(but->block->evil_C); return FRA2TIME(value); } else { - return value; + return BKE_scene_unit_scale(unit, RNA_SUBTYPE_UNIT_VALUE(unit_type), value); } } @@ -1955,7 +2015,7 @@ static float ui_get_but_step_unit(uiBut *but, float step_default) */ void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision) { - if (but->rnaprop && ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (but->rnaprop && ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { PropertyType type; const char *buf = NULL; int buf_len; @@ -2092,7 +2152,7 @@ bool ui_set_but_string_eval_num(bContext *C, uiBut *but, const char *str, double bool ui_set_but_string(bContext *C, uiBut *but, const char *str) { - if (but->rnaprop && ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (but->rnaprop && ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { if (RNA_property_editable(&but->rnapoin, but->rnaprop)) { PropertyType type; @@ -2744,7 +2804,7 @@ void uiBlockEndAlign(uiBlock *block) bool ui_but_can_align(uiBut *but) { - return !ELEM5(but->type, LABEL, OPTION, OPTIONN, SEPR, SEPRLINE); + return !ELEM(but->type, LABEL, OPTION, OPTIONN, SEPR, SEPRLINE); } static void ui_block_do_align_but(uiBut *first, short nr) @@ -2999,6 +3059,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str, but->lock = block->lock; but->lockstr = block->lockstr; but->dt = block->dt; + but->pie_dir = UI_RADIAL_NONE; but->block = block; /* pointer back, used for frontbuffer status, and picker */ @@ -3025,8 +3086,11 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str, } } - if ((block->flag & UI_BLOCK_LOOP) || - ELEM8(but->type, MENU, TEX, LABEL, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK)) + if (block->flag & UI_BLOCK_RADIAL) { + but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT); + } + else if ((block->flag & UI_BLOCK_LOOP) || + ELEM(but->type, MENU, TEX, LABEL, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK)) { but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT); } @@ -3045,7 +3109,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str, } /* keep track of UI_interface.h */ - if (ELEM11(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR, SEPRLINE, GRIP)) {} + if (ELEM(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR, SEPRLINE, GRIP)) {} else if (but->type >= SEARCH_MENU) {} else but->flag |= UI_BUT_UNDO; @@ -3210,12 +3274,12 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s int icon = 0; uiMenuCreateFunc func = NULL; - if (ELEM3(type, COLOR, HSVCIRCLE, HSVCUBE)) { + if (ELEM(type, COLOR, HSVCIRCLE, HSVCUBE)) { BLI_assert(index == -1); } /* use rna values if parameters are not specified */ - if ((proptype == PROP_ENUM) && ELEM3(type, MENU, ROW, LISTROW)) { + if ((proptype == PROP_ENUM) && ELEM(type, MENU, ROW, LISTROW)) { /* MENU is handled a little differently here */ EnumPropertyItem *item; int value; @@ -3808,9 +3872,6 @@ void uiBlockFlipOrder(uiBlock *block) but->rect.ymax = centy - (but->rect.ymax - centy); SWAP(float, but->rect.ymin, but->rect.ymax); } - - /* also flip order in block itself, for example for arrowkey */ - BLI_listbase_reverse(&block->buttons); } @@ -4336,7 +4397,7 @@ void uiButGetStrInfo(bContext *C, uiBut *but, ...) } tmp = BLI_strdup(_tmp); } - else if (ELEM3(type, BUT_GET_RNAENUM_IDENTIFIER, BUT_GET_RNAENUM_LABEL, BUT_GET_RNAENUM_TIP)) { + else if (ELEM(type, BUT_GET_RNAENUM_IDENTIFIER, BUT_GET_RNAENUM_LABEL, BUT_GET_RNAENUM_TIP)) { PointerRNA *ptr = NULL; PropertyRNA *prop = NULL; int value = 0; @@ -4426,11 +4487,6 @@ void UI_init_userdef(void) uiStyleInit(); } -void UI_init_userdef_factory(void) -{ - init_userdef_factory(); -} - void UI_reinit_font(void) { uiStyleInit(); diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 29da19acf83..53827a9a7bf 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -695,11 +695,11 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), } /* RGB / YCC (3 channels) */ - else if (ELEM4(scopes->wavefrm_mode, - SCOPES_WAVEFRM_RGB, - SCOPES_WAVEFRM_YCC_601, - SCOPES_WAVEFRM_YCC_709, - SCOPES_WAVEFRM_YCC_JPEG)) + else if (ELEM(scopes->wavefrm_mode, + SCOPES_WAVEFRM_RGB, + SCOPES_WAVEFRM_YCC_601, + SCOPES_WAVEFRM_YCC_709, + SCOPES_WAVEFRM_YCC_JPEG)) { int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB); @@ -1152,9 +1152,11 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti } /* layer: active handle */ - cbd = &coba->data[coba->cur]; - pos = x1 + cbd->pos * (sizex - 1) + 1; - ui_draw_colorband_handle(rect, pos, &cbd->r, display, true); + if (coba->tot != 0) { + cbd = &coba->data[coba->cur]; + pos = x1 + cbd->pos * (sizex - 1) + 1; + ui_draw_colorband_handle(rect, pos, &cbd->r, display, true); + } } void ui_draw_but_NORMAL(uiBut *but, uiWidgetColors *wcol, const rcti *rect) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index e04fef329b1..9818a593174 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -38,6 +38,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_brush_types.h" #include "DNA_sensor_types.h" #include "DNA_controller_types.h" #include "DNA_actuator_types.h" @@ -60,6 +61,7 @@ #include "PIL_time.h" #include "BKE_blender.h" +#include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_idprop.h" @@ -99,6 +101,8 @@ /* drag popups by their header */ #define USE_DRAG_POPUP +#define UI_MAX_PASSWORD_STR 128 + /* proto */ static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to); static void ui_add_link(bContext *C, uiBut *from, uiBut *to); @@ -114,6 +118,7 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve #define BUTTON_TOOLTIP_DELAY 0.500 #define BUTTON_FLASH_DELAY 0.020 #define MENU_SCROLL_INTERVAL 0.1 +#define PIE_MENU_INTERVAL 0.01 #define BUTTON_AUTO_OPEN_THRESH 0.3 #define BUTTON_MOUSE_TOWARDS_THRESH 1.0 /* pixels to move the cursor to get out of keyboard navigation */ @@ -151,7 +156,7 @@ typedef enum uiHandleButtonState { * note: half the height of a button is about right... */ #define DRAG_MULTINUM_THRESHOLD_DRAG_X (UI_UNIT_Y / 4) -/* how far to drag horizontally before we stop checkign which buttons the gesture spans (in pixels), +/* how far to drag horizontally before we stop checking which buttons the gesture spans (in pixels), * locking down the buttons so we can drag freely without worrying about vertical movement. */ #define DRAG_MULTINUM_THRESHOLD_DRAG_Y (UI_UNIT_Y / 4) @@ -383,16 +388,16 @@ void ui_pan_to_scroll(const wmEvent *event, int *type, int *val) } } -static bool ui_but_editable(uiBut *but) +bool ui_but_is_editable(const uiBut *but) { - return ELEM6(but->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX, PROGRESSBAR); + return !ELEM(but->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX, PROGRESSBAR); } static uiBut *ui_but_prev(uiBut *but) { while (but->prev) { but = but->prev; - if (!ui_but_editable(but)) return but; + if (ui_but_is_editable(but)) return but; } return NULL; } @@ -401,7 +406,7 @@ static uiBut *ui_but_next(uiBut *but) { while (but->next) { but = but->next; - if (!ui_but_editable(but)) return but; + if (ui_but_is_editable(but)) return but; } return NULL; } @@ -412,7 +417,7 @@ static uiBut *ui_but_first(uiBlock *block) but = block->buttons.first; while (but) { - if (!ui_but_editable(but)) return but; + if (ui_but_is_editable(but)) return but; but = but->next; } return NULL; @@ -424,7 +429,7 @@ static uiBut *ui_but_last(uiBlock *block) but = block->buttons.last; while (but) { - if (!ui_but_editable(but)) return but; + if (ui_but_is_editable(but)) return but; but = but->prev; } return NULL; @@ -433,7 +438,7 @@ static uiBut *ui_but_last(uiBlock *block) static bool ui_is_a_warp_but(uiBut *but) { if (U.uiflag & USER_CONTINUOUS_MOUSE) { - if (ELEM6(but->type, NUM, NUMSLI, HSVCIRCLE, TRACKPREVIEW, HSVCUBE, BUT_CURVE)) { + if (ELEM(but->type, NUM, NUMSLI, HSVCIRCLE, TRACKPREVIEW, HSVCUBE, BUT_CURVE)) { return true; } } @@ -463,7 +468,7 @@ bool ui_is_but_utf8(const uiBut *but) { if (but->rnaprop) { const int subtype = RNA_property_subtype(but->rnaprop); - return !(ELEM4(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME, PROP_BYTESTRING)); + return !(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME, PROP_BYTESTRING)); } else { return !(but->flag & UI_BUT_NO_UTF8); @@ -599,7 +604,13 @@ static void ui_apply_autokey(bContext *C, uiBut *but) /* make a little report about what we've done! */ if (but->rnaprop) { - char *buf = WM_prop_pystring_assign(C, &but->rnapoin, but->rnaprop, but->rnaindex); + char *buf; + + if (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD) { + return; + } + + buf = WM_prop_pystring_assign(C, &but->rnapoin, but->rnaprop, but->rnaindex); if (buf) { BKE_report(CTX_wm_reports(C), RPT_PROPERTY, buf); MEM_freeN(buf); @@ -633,7 +644,7 @@ static void ui_apply_but_funcs_after(bContext *C) } if (after.optype) - WM_operator_name_call(C, after.optype->idname, after.opcontext, (after.opptr) ? &opptr : NULL); + WM_operator_name_call_ptr(C, after.optype, after.opcontext, (after.opptr) ? &opptr : NULL); if (after.opptr) WM_operator_properties_free(&opptr); @@ -717,7 +728,7 @@ static void ui_apply_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data) if (value == 0.0) push = 1; else push = 0; - if (ELEM3(but->type, TOGN, ICONTOGN, OPTIONN)) push = !push; + if (ELEM(but->type, TOGN, ICONTOGN, OPTIONN)) push = !push; ui_set_but_val(but, (double)push); if (but->type == ICONTOG || but->type == ICONTOGN) ui_check_but(but); } @@ -1189,7 +1200,7 @@ static bool ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, const wmEvent *eve BLI_rcti_rctf_copy(&rect, &but->rect); - if (but->imb) { + if (but->imb || but->type == COLOR) { /* use button size itself */ } else if (but->drawflag & UI_BUT_ICON_LEFT) { @@ -1236,16 +1247,48 @@ static bool ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data, WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_drag_toggle, ui_handler_region_drag_toggle_remove, - drag_info); + drag_info, false); CTX_wm_region_set(C, ar_prev); } else #endif - { + if (but->type == COLOR) { + bool valid = false; + uiDragColorHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__); + + /* TODO support more button pointer types */ + if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) { + RNA_property_float_get_array(&but->rnapoin, but->rnaprop, drag_info->color); + drag_info->gamma_corrected = true; + valid = true; + } + else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) { + RNA_property_float_get_array(&but->rnapoin, but->rnaprop, drag_info->color); + drag_info->gamma_corrected = false; + valid = true; + } + else if (but->pointype == UI_BUT_POIN_FLOAT) { + copy_v3_v3(drag_info->color, (float *)but->poin); + valid = true; + } + else if (but->pointype == UI_BUT_POIN_CHAR) { + rgb_uchar_to_float(drag_info->color, (unsigned char *)but->poin); + valid = true; + } + + if (valid) { + WM_event_start_drag(C, ICON_COLOR, WM_DRAG_COLOR, drag_info, 0.0, WM_DRAG_FREE_DATA); + } + else { + MEM_freeN(drag_info); + return false; + } + } + else { wmDrag *drag; - drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but)); + drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but), WM_DRAG_NOP); if (but->imb) WM_event_drag_image(drag, but->imb, but->imb_scale, BLI_rctf_size_x(&but->rect), BLI_rctf_size_y(&but->rect)); } @@ -1655,7 +1698,7 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB for (wmd = drags->first; wmd; wmd = wmd->next) { if (wmd->type == WM_DRAG_ID) { /* align these types with UI_but_active_drop_name */ - if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { ID *id = (ID *)wmd->poin; button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); @@ -1802,7 +1845,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, } /* text/string and ID data */ - else if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + else if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { uiHandleButtonData *active_data = but->active; if (but->poin == NULL && but->rnapoin.data == NULL) { @@ -1911,28 +1954,35 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, static int ui_text_position_from_hidden(uiBut *but, int pos) { - const char *strpos; + const char *strpos, *butstr; int i; - for (i = 0, strpos = but->drawstr; i < pos; i++) + butstr = (but->editstr) ? but->editstr : but->drawstr; + + for (i = 0, strpos = butstr; i < pos; i++) strpos = BLI_str_find_next_char_utf8(strpos, NULL); - return (strpos - but->drawstr); + return (strpos - butstr); } static int ui_text_position_to_hidden(uiBut *but, int pos) { - return BLI_strnlen_utf8(but->drawstr, pos); + const char *butstr = butstr = (but->editstr) ? but->editstr : but->drawstr; + return BLI_strnlen_utf8(butstr, pos); } -void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore) +void ui_button_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], uiBut *but, const bool restore) { + char *butstr; + if (!(but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_PASSWORD)) return; + butstr = (but->editstr) ? but->editstr : but->drawstr; + if (restore) { /* restore original string */ - BLI_strncpy(but->drawstr, password_str, UI_MAX_DRAW_STR); + BLI_strncpy(butstr, password_str, UI_MAX_PASSWORD_STR); /* remap cursor positions */ if (but->pos >= 0) { @@ -1942,8 +1992,8 @@ void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but } } else { - /* convert text to hidden test using asterisks (e.g. pass -> ****) */ - const size_t len = BLI_strlen_utf8(but->drawstr); + /* convert text to hidden text using asterisks (e.g. pass -> ****) */ + const size_t len = BLI_strlen_utf8(butstr); /* remap cursor positions */ if (but->pos >= 0) { @@ -1953,10 +2003,9 @@ void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but } /* save original string */ - BLI_strncpy(password_str, but->drawstr, UI_MAX_DRAW_STR); - - memset(but->drawstr, '*', len); - but->drawstr[len] = '\0'; + BLI_strncpy(password_str, butstr, UI_MAX_PASSWORD_STR); + memset(butstr, '*', len); + butstr[len] = '\0'; } } @@ -1992,7 +2041,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con float startx = but->rect.xmin; float starty_dummy = 0.0f; - char *origstr, password_str[UI_MAX_DRAW_STR]; + char *origstr, password_str[UI_MAX_PASSWORD_STR]; ui_block_to_window_fl(data->region, but->block, &startx, &starty_dummy); @@ -2009,7 +2058,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con BLI_strncpy(origstr, but->editstr, data->maxlen); - if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { if (but->flag & UI_HAS_ICON) { startx += UI_DPI_ICON_SIZE / aspect; } @@ -2461,11 +2510,11 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa uiBut *but; /* label and roundbox can overlap real buttons (backdrops...) */ - if (ELEM5(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX)) + if (ELEM(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX)) return; for (but = actbut->next; but; but = but->next) { - if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { if (!(but->flag & UI_BUT_DISABLED)) { data->postbut = but; data->posttype = BUTTON_ACTIVATE_TEXT_EDITING; @@ -2474,7 +2523,7 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa } } for (but = block->buttons.first; but != actbut; but = but->next) { - if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { if (!(but->flag & UI_BUT_DISABLED)) { data->postbut = but; data->posttype = BUTTON_ACTIVATE_TEXT_EDITING; @@ -2489,11 +2538,11 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa uiBut *but; /* label and roundbox can overlap real buttons (backdrops...) */ - if (ELEM5(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX)) + if (ELEM(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX)) return; for (but = actbut->prev; but; but = but->prev) { - if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { if (!(but->flag & UI_BUT_DISABLED)) { data->postbut = but; data->posttype = BUTTON_ACTIVATE_TEXT_EDITING; @@ -2502,7 +2551,7 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa } } for (but = block->buttons.last; but != actbut; but = but->prev) { - if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { if (!(but->flag & UI_BUT_DISABLED)) { data->postbut = but; data->posttype = BUTTON_ACTIVATE_TEXT_EDITING; @@ -2803,7 +2852,7 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data) data->coba = (ColorBand *)but->poin; but->editcoba = data->coba; } - else if (ELEM4(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE, COLOR)) { + else if (ELEM(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE, COLOR)) { ui_get_but_vectorf(but, data->origvec); copy_v3_v3(data->vec, data->origvec); but->editvec = data->vec; @@ -2990,7 +3039,7 @@ static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, cons static int ui_do_but_HOTKEYEVT(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) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { but->drawstr[0] = 0; but->modifier_key = 0; button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT); @@ -3053,7 +3102,7 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data static int ui_do_but_KEYEVT(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) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT); return WM_UI_HANDLER_BREAK; } @@ -3078,7 +3127,7 @@ static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, c static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { - if (ELEM4(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) { + if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) { if (ELEM(event->type, PADENTER, RETKEY) && (!ui_is_but_utf8(but))) { /* pass - allow filesel, enter to execute */ } @@ -3106,7 +3155,7 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { /* unlink icon is on right */ - if (ELEM4(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS && + if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS && ui_is_but_search_unlink_visible(but)) { ARegion *ar = data->region; @@ -3156,7 +3205,7 @@ 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 (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { #if 0 /* UNUSED */ data->togdual = event->ctrl; data->togonly = !event->shift; @@ -3194,7 +3243,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con } #endif - if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { int ret = WM_UI_HANDLER_BREAK; /* XXX (a bit ugly) Special case handling for filebrowser drag button */ if (but->dragpoin && but->imb && ui_but_mouse_inside_icon(but, data->region, event)) { @@ -3243,7 +3292,7 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa if (bUnit_IsValid(unit->system, unit_type)) { fac = (float)bUnit_BaseScalar(unit->system, unit_type); - if (ELEM3(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) { + if (ELEM(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) { fac /= unit->scale_length; } } @@ -3478,7 +3527,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton click = 1; } else if (event->val == KM_PRESS) { - if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) { button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); retval = WM_UI_HANDLER_BREAK; } @@ -3767,7 +3816,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton click = 2; } else if (event->val == KM_PRESS) { - if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) { button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); retval = WM_UI_HANDLER_BREAK; } @@ -4024,7 +4073,7 @@ static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data, /* hack to pass on ctrl+click and double click to overlapping text * editing field for editing list item names */ - if ((ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS && event->ctrl) || + if ((ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS && event->ctrl) || (event->type == LEFTMOUSE && event->val == KM_DBL_CLICK)) { uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_TEXT_EDITING); @@ -4053,7 +4102,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co } } #ifdef USE_DRAG_TOGGLE - if (event->type == LEFTMOUSE && ui_is_but_drag_toggle(but)) { + if (event->type == LEFTMOUSE && event->val == KM_PRESS && (ui_is_but_drag_toggle(but))) { button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); data->dragstartx = event->x; data->dragstarty = event->y; @@ -4061,7 +4110,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co } #endif /* regular open menu */ - if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { button_activate_state(C, but, BUTTON_STATE_MENU_OPEN); return WM_UI_HANDLER_BREAK; } @@ -4206,11 +4255,29 @@ static bool ui_numedit_but_NORMAL(uiBut *but, uiHandleButtonData *data, 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) { + /* first handle click on icondrag type button */ + if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) { + if (ui_but_mouse_inside_icon(but, data->region, event)) { + button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); + data->dragstartx = event->x; + data->dragstarty = event->y; + return WM_UI_HANDLER_BREAK; + } + } +#ifdef USE_DRAG_TOGGLE + if (event->type == LEFTMOUSE && event->val == KM_PRESS) { + button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); + data->dragstartx = event->x; + data->dragstarty = event->y; + return WM_UI_HANDLER_BREAK; + } +#endif + /* regular open menu */ + if (ELEM(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) { + else if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) { float *hsv = ui_block_hsv_get(but->block); float col[3]; @@ -4233,6 +4300,84 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co ui_apply_button(C, but->block, but, data, true); return WM_UI_HANDLER_BREAK; } + else if ((int)(but->a1) == UI_PALETTE_COLOR && + event->type == DELKEY && event->val == KM_PRESS) + { + Scene *scene = CTX_data_scene(C); + Paint *paint = BKE_paint_get_active(scene); + Palette *palette = BKE_paint_palette(paint); + PaletteColor *color = but->rnapoin.data; + + BKE_palette_color_remove(palette, color); + + button_activate_state(C, but, BUTTON_STATE_EXIT); + return WM_UI_HANDLER_BREAK; + } + } + else if (data->state == BUTTON_STATE_WAIT_DRAG) { + + /* this function also ends state */ + if (ui_but_start_drag(C, but, data, event)) { + return WM_UI_HANDLER_BREAK; + } + + /* outside icon quit, not needed if drag activated */ + if (0 == ui_but_mouse_inside_icon(but, data->region, event)) { + button_activate_state(C, but, BUTTON_STATE_EXIT); + data->cancel = true; + return WM_UI_HANDLER_BREAK; + } + + if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { + if ((int)(but->a1) == UI_PALETTE_COLOR) { + Palette *palette = but->rnapoin.id.data; + PaletteColor *color = but->rnapoin.data; + palette->active_color = BLI_findindex(&palette->colors, color); + + /* enforce redraw, sometimes state here can already be exit */ + ED_region_tag_redraw(data->region); + + if (!event->ctrl) { + float color[3]; + Scene *scene = CTX_data_scene(C); + Paint *paint = BKE_paint_get_active(scene); + Brush *brush = BKE_paint_brush(paint); + + if (brush->flag & BRUSH_USE_GRADIENT) { + float *target = &brush->gradient->data[brush->gradient->cur].r; + + if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) { + RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target); + ui_block_to_scene_linear_v3(but->block, target); + } + else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) { + RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target); + } + } + else { + if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) { + RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color); + BKE_brush_color_set(scene, brush, color); + } + else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) { + RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color); + ui_block_to_display_space_v3(but->block, color); + BKE_brush_color_set(scene, brush, color); + } + } + + button_activate_state(C, but, BUTTON_STATE_EXIT); + } + else { + button_activate_state(C, but, BUTTON_STATE_MENU_OPEN); + } + } + else { + button_activate_state(C, but, BUTTON_STATE_MENU_OPEN); + } + return WM_UI_HANDLER_BREAK; + } + } return WM_UI_HANDLER_CONTINUE; @@ -4412,7 +4557,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, } if (snap != SNAP_OFF) { - if (ELEM3((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) { + if (ELEM((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) { ui_color_snap_hue(snap, &hsv[0]); } } @@ -4489,7 +4634,7 @@ static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, } if (snap != SNAP_OFF) { - if (ELEM3((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) { + if (ELEM((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) { ui_color_snap_hue(snap, &hsv[0]); } } @@ -4878,6 +5023,9 @@ static bool ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int m if (data->draglastx == mx) return changed; + if (data->coba->tot == 0) + return changed; + dx = ((float)(mx - data->draglastx)) / BLI_rctf_size_x(&but->rect); data->dragcbd->pos += dx; CLAMP(data->dragcbd->pos, 0.0f, 1.0f); @@ -6012,7 +6160,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * } /* handle drivers */ else if ((event->type == DKEY) && - !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && + !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && (event->val == KM_PRESS)) { if (event->alt) @@ -6026,7 +6174,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * } /* handle keyingsets */ else if ((event->type == KKEY) && - !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && + !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && (event->val == KM_PRESS)) { if (event->alt) @@ -6250,7 +6398,34 @@ static bool ui_but_contains_pt(uiBut *but, float mx, float my) return BLI_rctf_isect_pt(&but->rect, mx, my); } -static uiBut *ui_but_find_activated(ARegion *ar) +void ui_but_pie_dir(RadialDirection dir, float vec[2]) +{ + float angle; + + BLI_assert(dir != UI_RADIAL_NONE); + + angle = DEG2RADF((float)ui_radial_dir_to_angle[dir]); + vec[0] = cosf(angle); + vec[1] = sinf(angle); +} + +static bool ui_but_isect_pie_seg(uiBlock *block, uiBut *but) +{ + const float angle_range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? M_PI_4 : M_PI_4 / 2.0; + float vec[2]; + + if (block->pie_data.flags & UI_PIE_INVALID_DIR) + return false; + + ui_but_pie_dir(but->pie_dir, vec); + + if (saacos(dot_v2v2(vec, block->pie_data.pie_dir)) < angle_range) + return true; + + return false; +} + +uiBut *ui_but_find_activated(ARegion *ar) { uiBlock *block; uiBut *but; @@ -6298,13 +6473,27 @@ bool UI_but_active_drop_name(bContext *C) uiBut *but = ui_but_find_activated(ar); if (but) { - if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) + if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) return 1; } return 0; } +bool UI_but_active_drop_color(bContext *C) +{ + ARegion *ar = CTX_wm_region(C); + + if (ar) { + uiBut *but = ui_but_find_activated(ar); + + if (but && but->type == COLOR) + return true; + } + + return false; +} + static void ui_blocks_set_tooltips(ARegion *ar, const bool enable) { uiBlock *block; @@ -6354,6 +6543,7 @@ static bool ui_mouse_inside_region(ARegion *ar, int x, int y) static bool ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y) { + uiBlock *block = but->block; float mx, my; if (!ui_mouse_inside_region(ar, x, y)) return false; @@ -6361,10 +6551,16 @@ static bool ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y) mx = x; my = y; - ui_window_to_block_fl(ar, but->block, &mx, &my); + ui_window_to_block_fl(ar, block, &mx, &my); - if (!ui_but_contains_pt(but, mx, my)) + if (but->dt == UI_EMBOSSR) { + if (!ui_but_isect_pie_seg(block, but)) { + return false; + } + } + else if (!ui_but_contains_pt(but, mx, my)) { return false; + } return true; } @@ -6378,7 +6574,7 @@ static bool ui_is_but_interactive(const uiBut *but, const bool labeledit) /* note, LABEL is included for highlights, this allows drags */ if ((but->type == LABEL) && but->dragpoin == NULL) return false; - if (ELEM4(but->type, ROUNDBOX, SEPR, SEPRLINE, LISTBOX)) + if (ELEM(but->type, ROUNDBOX, SEPR, SEPRLINE, LISTBOX)) return false; if (but->flag & UI_HIDDEN) return false; @@ -6418,7 +6614,13 @@ static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, c for (but = block->buttons.last; but; but = but->prev) { if (ui_is_but_interactive(but, labeledit)) { - if (ui_but_contains_pt(but, mx, my)) { + if (but->pie_dir != UI_RADIAL_NONE) { + if (ui_but_isect_pie_seg(block, but)) { + butover = but; + break; + } + } + else if (ui_but_contains_pt(but, mx, my)) { butover = but; break; } @@ -6471,9 +6673,13 @@ static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y) static bool button_modal_state(uiHandleButtonState state) { - return ELEM6(state, BUTTON_STATE_WAIT_RELEASE, BUTTON_STATE_WAIT_KEY_EVENT, - BUTTON_STATE_NUM_EDITING, BUTTON_STATE_TEXT_EDITING, - BUTTON_STATE_TEXT_SELECTING, BUTTON_STATE_MENU_OPEN); + return ELEM(state, + BUTTON_STATE_WAIT_RELEASE, + BUTTON_STATE_WAIT_KEY_EVENT, + BUTTON_STATE_NUM_EDITING, + BUTTON_STATE_TEXT_EDITING, + BUTTON_STATE_TEXT_SELECTING, + BUTTON_STATE_MENU_OPEN); } static void button_timers_tooltip_remove(bContext *C, uiBut *but) @@ -6511,10 +6717,13 @@ static void button_tooltip_timer_reset(bContext *C, uiBut *but) data->tooltiptimer = NULL; } - if (U.flag & USER_TOOLTIPS) - if (!but->block->tooltipdisabled) - if (!wm->drags.first) + if ((U.flag & USER_TOOLTIPS) || (but->flag & UI_BUT_TIP_FORCE)) { + if (!but->block->tooltipdisabled) { + if (!wm->drags.first) { data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_TOOLTIP_DELAY); + } + } + } } static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state) @@ -6619,7 +6828,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s if (!(but->block->handle && but->block->handle->popup)) { if (button_modal_state(state)) { if (!button_modal_state(data->state)) - WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data); + WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data, false); } else { if (button_modal_state(data->state)) { @@ -6664,7 +6873,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA copy_v2_fl(data->ungrab_mval, FLT_MAX); #endif - if (ELEM3(but->type, BUT_CURVE, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, BUT_CURVE, SEARCH_MENU, SEARCH_MENU_UNLINK)) { /* XXX curve is temp */ } else { @@ -7023,6 +7232,13 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *ar) if (event->type == MOUSEMOVE) { but = ui_but_find_mouse_over(ar, event); if (but) { + if (event->alt) { + /* display tooltips if holding alt on mouseover when tooltips are off in prefs */ + but->flag |= UI_BUT_TIP_FORCE; + } + else { + but->flag &= ~UI_BUT_TIP_FORCE; + } button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER); } } @@ -7054,6 +7270,17 @@ void ui_button_activate_do(bContext *C, ARegion *ar, uiBut *but) ui_do_button(C, but->block, but, &event); } +/** + * Simulate moving the mouse over a button (or navigating to it with arrow keys). + * + * exported so menus can start with a highlighted button, + * even if the mouse isnt over it + */ +void ui_button_activate_over(bContext *C, ARegion *ar, uiBut *but) +{ + button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER); +} + void ui_button_execute_begin(struct bContext *UNUSED(C), struct ARegion *ar, uiBut *but, void **active_back) { /* note: ideally we would not have to change 'but->active' however @@ -7116,12 +7343,20 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) retval = WM_UI_HANDLER_CONTINUE; break; case MOUSEMOVE: - /* verify if we are still over the button, if not exit */ - if (!ui_mouse_inside_button(ar, but, event->x, event->y)) { - data->cancel = true; - button_activate_state(C, but, BUTTON_STATE_EXIT); + { + uiBut *but_other = ui_but_find_mouse_over(ar, event); + bool exit = false; + + if ((!ui_block_is_menu(block) || ui_block_is_pie_menu(but->block)) && + !ui_mouse_inside_button(ar, but, event->x, event->y)) + { + exit = true; + } + else if (but_other && ui_but_is_editable(but_other) && (but_other != but)) { + exit = true; } - else if (ui_but_find_mouse_over(ar, event) != but) { + + if (exit) { data->cancel = true; button_activate_state(C, but, BUTTON_STATE_EXIT); } @@ -7132,6 +7367,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) } break; + } case TIMER: { /* handle tooltip timer */ @@ -7715,6 +7951,25 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock int retval; if (but) { + /* Its possible there is an active menu item NOT under the mouse, + * in this case ignore mouse clicks outside the button (but Enter etc is accepted) */ + if (event->val == KM_RELEASE) { + /* pass, needed so we can exit active menu-items when click-dragging out of them */ + } + else if (!ui_block_is_menu(but->block) || ui_block_is_pie_menu(but->block)) { + /* pass, skip for dialogs */ + } + else if (!ui_mouse_inside_region(but->active->region, event->x, event->y)) { + /* pass, needed to click-exit outside of non-flaoting menus */ + } + else if ((!ELEM(event->type, MOUSEMOVE, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN)) && ISMOUSE(event->type)) { + if (!ui_mouse_inside_button(but->active->region, but, event->x, event->y)) { + but = NULL; + } + } + } + + if (but) { ScrArea *ctx_area = CTX_wm_area(C); ARegion *ctx_region = CTX_wm_region(C); @@ -7733,6 +7988,30 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock return retval; } +void ui_block_calculate_pie_segment(uiBlock *block, const float event_xy[2]) +{ + float seg1[2]; + float seg2[2]; + float len; + + if (block->pie_data.flags & UI_PIE_INITIAL_DIRECTION) { + copy_v2_v2(seg1, block->pie_data.pie_center_init); + } + else { + copy_v2_v2(seg1, block->pie_data.pie_center_spawned); + } + + sub_v2_v2v2(seg2, event_xy, seg1); + + len = normalize_v2_v2(block->pie_data.pie_dir, seg2); + + /* ten pixels for now, a bit arbitrary */ + if (len < U.pie_menu_threshold * U.pixelsize) + block->pie_data.flags |= UI_PIE_INVALID_DIR; + else + block->pie_data.flags &= ~UI_PIE_INVALID_DIR; +} + static int ui_handle_menu_event( bContext *C, const wmEvent *event, uiPopupBlockHandle *menu, int level, const bool is_parent_inside, const bool is_parent_menu, const bool is_floating) @@ -7764,6 +8043,7 @@ static int ui_handle_menu_event( if (menu->is_grab) { if (event->type == LEFTMOUSE) { menu->is_grab = false; + retval = WM_UI_HANDLER_BREAK; } else { if (event->type == MOUSEMOVE) { @@ -7968,7 +8248,7 @@ static int ui_handle_menu_event( for (but = block->buttons.first; but; but = but->next) { bool doit = false; - if (!ELEM3(but->type, LABEL, SEPR, SEPRLINE)) + if (!ELEM(but->type, LABEL, SEPR, SEPRLINE)) count++; /* exception for rna layer buts */ @@ -8079,7 +8359,7 @@ static int ui_handle_menu_event( if (inside == 0) { uiSafetyRct *saferct = block->saferct.first; - if (ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) && + if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) && ELEM(event->val, KM_PRESS, KM_DBL_CLICK)) { if ((is_parent_menu == false) && (U.uiflag & USER_MENUOPENAUTO) == 0) { @@ -8121,9 +8401,14 @@ static int ui_handle_menu_event( else if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && (inside && is_floating && inside_title)) { - if (!ui_but_find_activated(ar)) { + if (!but || !ui_mouse_inside_button(ar, but, event->x, event->y)) { + if (but) { + button_timers_tooltip_remove(C, but); + } + menu->is_grab = true; copy_v2_v2_int(menu->grab_xy_prev, &event->x); + retval = WM_UI_HANDLER_BREAK; } } #endif @@ -8228,10 +8513,326 @@ static int ui_handle_menu_return_submenu(bContext *C, const wmEvent *event, uiPo ui_mouse_motion_towards_reinit(menu, &event->x); } - if (menu->menuretval) + if (menu->menuretval) { + /* pie menus should not close but wait for release instead */ + if ((block->flag & UI_BLOCK_RADIAL) && + !(block->pie_data.flags & UI_PIE_CLICK_STYLE)) + { + menu->menuretval = 0; + block->pie_data.flags |= UI_PIE_FINISHED; + } + return WM_UI_HANDLER_CONTINUE; - else + } + else { + return WM_UI_HANDLER_BREAK; + } +} + +static bool ui_but_pie_menu_supported_apply(uiBut *but) +{ + return (but->type != NUMSLI); +} + +static int ui_but_pie_menu_apply(bContext *C, uiPopupBlockHandle *menu, uiBut *but, bool force_close, bool click_style) +{ + int retval = WM_UI_HANDLER_BREAK; + + if (but && ui_but_pie_menu_supported_apply(but)) { + if (but->type == MENU) { + /* forcing the pie menu to close will not handle menus */ + if (!force_close) { + uiBut *active_but = ui_but_find_activated(menu->region); + + if (active_but) { + button_activate_exit(C, active_but, active_but->active, false, false); + } + + button_activate_init(C, menu->region, but, BUTTON_ACTIVATE_OPEN); + return retval; + } + else { + menu->menuretval = UI_RETURN_CANCEL; + } + } + else { + ui_apply_button(C, but->block, but, but->active, false); + button_activate_exit((bContext *)C, but, but->active, false, true); + + if (!(click_style || force_close)) { + but->block->pie_data.flags |= UI_PIE_FINISHED; + menu->menuretval = 0; + } + else { + menu->menuretval = UI_RETURN_OK; + } + } + } + else { + uiBlock *block = menu->region->uiblocks.first; + + if (!(click_style || force_close)) { + block->pie_data.flags |= UI_PIE_FINISHED; + } + else { + menu->menuretval = UI_RETURN_CANCEL; + } + + ED_region_tag_redraw(menu->region); + } + + return retval; +} + +static uiBut *ui_block_pie_dir_activate(uiBlock *block, const wmEvent *event, RadialDirection dir) +{ + uiBut *but; + + if ((block->flag & UI_BLOCK_NUMSELECT) && event->val == KM_PRESS) { + for (but = block->buttons.first; but; but = but->next) { + if (but->pie_dir == dir && !ELEM(but->type, SEPR, SEPRLINE)) { + return but; + } + } + } + + return NULL; +} + +static int ui_but_pie_button_activate(bContext *C, uiBut *but, uiPopupBlockHandle *menu, bool is_click_style) +{ + uiBut *active_but; + + if (but == NULL) + return WM_UI_HANDLER_BREAK; + + active_but = ui_but_find_activated(menu->region); + + if (active_but) + button_activate_exit(C, active_but, active_but->active, false, false); + + button_activate_init(C, menu->region, but, BUTTON_ACTIVATE_OVER); + return ui_but_pie_menu_apply(C, menu, but, false, is_click_style); +} + +static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle *menu) +{ + ARegion *ar; + uiBlock *block; + uiBut *but; + float event_xy[2]; + double duration; + bool is_click_style; + + /* we block all events, this is modal interaction, except for drop events which is described below */ + int retval = WM_UI_HANDLER_BREAK; + + if (event->type == EVT_DROP) { + /* may want to leave this here for later if we support pie ovens */ + + retval = WM_UI_HANDLER_CONTINUE; + } + + ar = menu->region; + block = ar->uiblocks.first; + + is_click_style = (block->pie_data.flags & UI_PIE_CLICK_STYLE); + + if (menu->scrolltimer == NULL) { + menu->scrolltimer = + WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, PIE_MENU_INTERVAL); + menu->scrolltimer->duration = 0.0; + } + + duration = menu->scrolltimer->duration; + + if (event->type == TIMER) { + if (event->customdata == menu->scrolltimer) { + /* deactivate initial direction after a while */ + if (duration > 0.01 * U.pie_initial_timeout) { + block->pie_data.flags &= ~UI_PIE_INITIAL_DIRECTION; + } + + /* handle animation */ + if (!(block->pie_data.flags & UI_PIE_ANIMATION_FINISHED)) { + uiBut *but; + double final_time = 0.01 * U.pie_animation_timeout; + float fac = duration / final_time; + float pie_radius = U.pie_menu_radius * UI_DPI_FAC; + + if (fac > 1.0f) { + fac = 1.0f; + block->pie_data.flags |= UI_PIE_ANIMATION_FINISHED; + } + + for (but = block->buttons.first; but; but = but->next) { + if (but->pie_dir != UI_RADIAL_NONE) { + float vec[2]; + float center[2]; + + ui_but_pie_dir(but->pie_dir, vec); + + center[0] = (vec[0] > 0.01f) ? 0.5f : ((vec[0] < -0.01f) ? -0.5f : 0.0f); + center[1] = (vec[1] > 0.99f) ? 0.5f : ((vec[1] < -0.99f) ? -0.5f : 0.0f); + + center[0] *= BLI_rctf_size_x(&but->rect); + center[1] *= BLI_rctf_size_y(&but->rect); + + mul_v2_fl(vec, pie_radius); + add_v2_v2(vec, center); + mul_v2_fl(vec, fac); + add_v2_v2(vec, block->pie_data.pie_center_spawned); + + BLI_rctf_recenter(&but->rect, vec[0], vec[1]); + } + } + block->pie_data.alphafac = fac; + + ED_region_tag_redraw(ar); + } + } + } + + event_xy[0] = event->x; + event_xy[1] = event->y; + + ui_window_to_block_fl(ar, block, &event_xy[0], &event_xy[1]); + + ui_block_calculate_pie_segment(block, event_xy); + + if (block->pie_data.flags & UI_PIE_FINISHED) { + if ((event->type == block->pie_data.event && event->val == KM_RELEASE) || + ((event->type == RIGHTMOUSE || event->type == ESCKEY) && (event->val == KM_PRESS))) + { + menu->menuretval = UI_RETURN_OK; + } + + ED_region_tag_redraw(ar); return WM_UI_HANDLER_BREAK; + } + + if (event->type == block->pie_data.event) { + if (event->val != KM_RELEASE) { + ui_handle_menu_button(C, event, menu); + + if (len_squared_v2v2(event_xy, block->pie_data.pie_center_init) > PIE_CLICK_THRESHOLD_SQ) { + block->pie_data.flags |= UI_PIE_DRAG_STYLE; + } + /* why redraw here? It's simple, we are getting many double click events here. + * Those operate like mouse move events almost */ + ED_region_tag_redraw(ar); + } + else { + /* distance from initial point */ + if (!(block->pie_data.flags & UI_PIE_DRAG_STYLE)) { + block->pie_data.flags |= UI_PIE_CLICK_STYLE; + } + else if (!is_click_style) { + uiBut *but = ui_but_find_activated(menu->region); + + retval = ui_but_pie_menu_apply(C, menu, but, true, is_click_style); + } + } + } + else { + /* direction from numpad */ + RadialDirection num_dir = UI_RADIAL_NONE; + + switch (event->type) { + case MOUSEMOVE: + if (len_squared_v2v2(event_xy, block->pie_data.pie_center_init) > PIE_CLICK_THRESHOLD_SQ) { + block->pie_data.flags |= UI_PIE_DRAG_STYLE; + } + ui_handle_menu_button(C, event, menu); + + /* mouse move should always refresh the area for pie menus */ + ED_region_tag_redraw(ar); + break; + + case LEFTMOUSE: + if (event->val == KM_PRESS) { + uiBut *but = ui_but_find_activated(menu->region); + retval = ui_but_pie_menu_apply(C, menu, but, false, is_click_style); + } + break; + + case ESCKEY: + case RIGHTMOUSE: + if (!is_click_style) { + block->pie_data.flags |= UI_PIE_FINISHED; + menu->menuretval = 0; + ED_region_tag_redraw(ar); + } + else + menu->menuretval = UI_RETURN_CANCEL; + break; + + case AKEY: + case BKEY: + case CKEY: + case DKEY: + case EKEY: + case FKEY: + case GKEY: + case HKEY: + case IKEY: + case JKEY: + case KKEY: + case LKEY: + case MKEY: + case NKEY: + case OKEY: + case PKEY: + case QKEY: + case RKEY: + case SKEY: + case TKEY: + case UKEY: + case VKEY: + case WKEY: + case XKEY: + case YKEY: + case ZKEY: + { + if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) && + (event->shift == 0) && + (event->ctrl == 0) && + (event->oskey == 0)) + { + for (but = block->buttons.first; but; but = but->next) { + if (but->menu_key == event->type) { + ui_but_pie_button_activate(C, but, menu, is_click_style); + } + } + } + break; + } + +#define CASE_NUM_TO_DIR(n, d) \ + case (ZEROKEY + n): case (PAD0 + n): \ + { if (num_dir == UI_RADIAL_NONE) num_dir = d; } (void)0 + + CASE_NUM_TO_DIR(1, UI_RADIAL_SW); + CASE_NUM_TO_DIR(2, UI_RADIAL_S); + CASE_NUM_TO_DIR(3, UI_RADIAL_SE); + CASE_NUM_TO_DIR(4, UI_RADIAL_W); + CASE_NUM_TO_DIR(6, UI_RADIAL_E); + CASE_NUM_TO_DIR(7, UI_RADIAL_NW); + CASE_NUM_TO_DIR(8, UI_RADIAL_N); + CASE_NUM_TO_DIR(9, UI_RADIAL_NE); + { + but = ui_block_pie_dir_activate(block, event, num_dir); + retval = ui_but_pie_button_activate(C, but, menu, is_click_style); + break; + } +#undef CASE_NUM_TO_DIR + default: + retval = ui_handle_menu_button(C, event, menu); + break; + } + } + + return retval; } static int ui_handle_menus_recursive( @@ -8253,17 +8854,21 @@ static int ui_handle_menus_recursive( uiBlock *block = menu->region->uiblocks.first; const bool is_menu = ui_block_is_menu(block); bool inside = false; + /* root pie menus accept the key that spawned them as double click to improve responsiveness */ + bool do_recursion = (!(block->flag & UI_BLOCK_RADIAL) || event->type != block->pie_data.event); - if (is_parent_inside == false) { - int mx, my; + if (do_recursion) { + if (is_parent_inside == false) { + int mx, my; - mx = event->x; - my = event->y; - ui_window_to_block(menu->region, block, &mx, &my); - inside = BLI_rctf_isect_pt(&block->rect, mx, my); - } + mx = event->x; + my = event->y; + ui_window_to_block(menu->region, block, &mx, &my); + inside = BLI_rctf_isect_pt(&block->rect, mx, my); + } - retval = ui_handle_menus_recursive(C, event, submenu, level + 1, is_parent_inside || inside, is_menu, false); + retval = ui_handle_menus_recursive(C, event, submenu, level + 1, is_parent_inside || inside, is_menu, false); + } } /* now handle events for our own menu */ @@ -8296,7 +8901,12 @@ static int ui_handle_menus_recursive( } } else { - retval = ui_handle_menu_event(C, event, menu, level, is_parent_inside, is_parent_menu, is_floating); + uiBlock *block = menu->region->uiblocks.first; + + if (block->flag & UI_BLOCK_RADIAL) + retval = ui_handler_pie(C, event, menu); + else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK) + retval = ui_handle_menu_event(C, event, menu, level, is_parent_inside, is_parent_menu, is_floating); } } @@ -8458,15 +9068,15 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata) /* free if done, does not free handle itself */ if (menu->menuretval) { + wmWindow *win = CTX_wm_window(C); /* copy values, we have to free first (closes region) */ uiPopupBlockHandle temp = *menu; ui_popup_block_free(C, menu); - UI_remove_popup_handlers(&CTX_wm_window(C)->modalhandlers, menu); + UI_remove_popup_handlers(&win->modalhandlers, menu); #ifdef USE_DRAG_TOGGLE { - wmWindow *win = CTX_wm_window(C); WM_event_free_ui_handler_all(C, &win->modalhandlers, ui_handler_region_drag_toggle, ui_handler_region_drag_toggle_remove); } @@ -8476,7 +9086,7 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata) if (temp.popup_func) temp.popup_func(C, temp.popup_arg, temp.retvalue); if (temp.optype) - WM_operator_name_call(C, temp.optype->idname, temp.opcontext, NULL); + WM_operator_name_call_ptr(C, temp.optype, temp.opcontext, NULL); } else if (temp.cancel_func) temp.cancel_func(C, temp.popup_arg); @@ -8511,12 +9121,12 @@ static void ui_handler_remove_popup(bContext *C, void *userdata) void UI_add_region_handlers(ListBase *handlers) { WM_event_remove_ui_handler(handlers, ui_handler_region, ui_handler_remove_region, NULL, false); - WM_event_add_ui_handler(NULL, handlers, ui_handler_region, ui_handler_remove_region, NULL); + WM_event_add_ui_handler(NULL, handlers, ui_handler_region, ui_handler_remove_region, NULL, false); } -void UI_add_popup_handlers(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup) +void UI_add_popup_handlers(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click) { - WM_event_add_ui_handler(C, handlers, ui_handler_popup, ui_handler_remove_popup, popup); + WM_event_add_ui_handler(C, handlers, ui_handler_popup, ui_handler_remove_popup, popup, accept_dbl_click); } void UI_remove_popup_handlers(ListBase *handlers, uiPopupBlockHandle *popup) diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index be6752953d1..cc8fc941ae7 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -508,6 +508,8 @@ static void init_brush_icons(void) INIT_BRUSH_ICON(ICON_BRUSH_SOFTEN, soften); INIT_BRUSH_ICON(ICON_BRUSH_SUBTRACT, subtract); INIT_BRUSH_ICON(ICON_BRUSH_TEXDRAW, texdraw); + INIT_BRUSH_ICON(ICON_BRUSH_TEXFILL, texfill); + INIT_BRUSH_ICON(ICON_BRUSH_TEXMASK, texmask); INIT_BRUSH_ICON(ICON_BRUSH_THUMB, thumb); INIT_BRUSH_ICON(ICON_BRUSH_ROTATE, twist); INIT_BRUSH_ICON(ICON_BRUSH_VERTEXDRAW, vertexdraw); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index cd3b6390184..cdc611a60f4 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -88,6 +88,7 @@ typedef enum { UI_WTYPE_PULLDOWN, UI_WTYPE_MENU_ITEM, + UI_WTYPE_MENU_ITEM_RADIAL, UI_WTYPE_MENU_BACK, /* specials */ @@ -121,6 +122,23 @@ enum { /* warn: rest of uiBut->flag in UI_interface.h */ }; +/* but->pie_dir */ +typedef enum RadialDirection { + UI_RADIAL_NONE = -1, + UI_RADIAL_N = 0, + UI_RADIAL_NE = 1, + UI_RADIAL_E = 2, + UI_RADIAL_SE = 3, + UI_RADIAL_S = 4, + UI_RADIAL_SW = 5, + UI_RADIAL_W = 6, + UI_RADIAL_NW = 7, +} RadialDirection; + +extern const char ui_radial_dir_order[8]; +extern const char ui_radial_dir_to_numpad[8]; +extern const short ui_radial_dir_to_angle[8]; + /* internal panel drawing defines */ #define PNL_GRID (UI_UNIT_Y / 5) /* 4 default */ #define PNL_HEADER (UI_UNIT_Y + 4) /* 24 default */ @@ -144,6 +162,19 @@ enum { /* split numbuts by ':' and align l/r */ #define USE_NUMBUTS_LR_ALIGN +/* PieMenuData->flags */ +enum { + UI_PIE_DEGREES_RANGE_LARGE = (1 << 0), /* pie menu item collision is detected at 90 degrees */ + UI_PIE_INITIAL_DIRECTION = (1 << 1), /* use initial center of pie menu to calculate direction */ + UI_PIE_DRAG_STYLE = (1 << 2), /* pie menu is drag style */ + UI_PIE_INVALID_DIR = (1 << 3), /* mouse not far enough from center position */ + UI_PIE_FINISHED = (1 << 4), /* pie menu finished but we still wait for a release event */ + UI_PIE_CLICK_STYLE = (1 << 5), /* pie menu changed to click style, click to confirm */ + UI_PIE_ANIMATION_FINISHED = (1 << 6), /* pie animation finished, do not calculate any more motio */ +}; + +#define PIE_CLICK_THRESHOLD_SQ 50.0f + typedef struct uiLinkLine { /* only for draw/edit */ struct uiLinkLine *next, *prev; struct uiBut *from, *to; @@ -186,6 +217,7 @@ struct uiBut { * (type == LABEL), Use (a1 == 1.0f) to use a2 as a blending factor (wow, this is imaginative!). * (type == SCROLL) Use as scroll size. * (type == SEARCH_MENU) Use as number or rows. + * (type == COLOR) Use as indication of color palette */ float a1; @@ -193,6 +225,7 @@ struct uiBut { * (type == NUM), Use to store RNA 'precision' value, for dragging and click-step. * (type == LABEL), If (a1 == 1.0f) use a2 as a blending factor. * (type == SEARCH_MENU) Use as number or columns. + * (type == COLOR) Use as indication of active palette color */ float a2; @@ -225,6 +258,7 @@ struct uiBut { BIFIconID icon; bool lock; char dt; /* drawtype: UI_EMBOSS, UI_EMBOSSN ... etc, copied from the block */ + signed char pie_dir; /* direction in a pie menu, used for collision detection (RadialDirection) */ char changed; /* could be made into a single flag */ unsigned char unit_type; /* so buttons can support unit systems which are not RNA */ short modifier_key; @@ -272,6 +306,15 @@ struct uiBut { uiBlock *block; }; +struct PieMenuData { + float pie_dir[2]; + float pie_center_init[2]; + float pie_center_spawned[2]; + int flags; + int event; /* initial event used to fire the pie menu, store here so we can query for release */ + float alphafac; +}; + struct uiBlock { uiBlock *next, *prev; @@ -354,6 +397,7 @@ struct uiBlock { char display_device[64]; /* display device name used to display this block, * used by color widgets to transform colors from/to scene linear */ + struct PieMenuData pie_data; }; typedef struct uiSafetyRct { @@ -369,6 +413,7 @@ extern void ui_delete_linkline(uiLinkLine *line, uiBut *but); void ui_fontscale(short *points, float aspect); extern bool ui_block_is_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; +extern bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; extern void ui_block_to_window_fl(const struct ARegion *ar, uiBlock *block, float *x, float *y); extern void ui_block_to_window(const struct ARegion *ar, uiBlock *block, int *x, int *y); extern void ui_block_to_window_rctf(const struct ARegion *ar, uiBlock *block, rctf *rct_dst, const rctf *rct_src); @@ -550,12 +595,19 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol PointerRNA *ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, int opcontext, bool create_props); extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val); extern void ui_button_activate_do(struct bContext *C, struct ARegion *ar, uiBut *but); +extern void ui_button_activate_over(struct bContext *C, struct ARegion *ar, uiBut *but); extern void ui_button_execute_begin(struct bContext *C, struct ARegion *ar, uiBut *but, void **active_back); extern void ui_button_execute_end(struct bContext *C, struct ARegion *ar, uiBut *but, void *active_back); extern void ui_button_active_free(const struct bContext *C, uiBut *but); extern bool ui_button_is_active(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT; extern int ui_button_open_menu_direction(uiBut *but); extern void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore); +extern uiBut *ui_but_find_activated(struct ARegion *ar); +bool ui_but_is_editable(const uiBut *but); +void ui_but_pie_dir_visual(RadialDirection dir, float vec[2]); +void ui_but_pie_dir(RadialDirection dir, float vec[2]); +void ui_block_calculate_pie_segment(struct uiBlock *block, const float event_xy[2]); + void ui_button_clipboard_free(void); void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa); uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new); @@ -565,6 +617,7 @@ uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new); void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha); void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect); +void ui_draw_pie_center(uiBlock *block); uiWidgetColors *ui_tooltip_get_theme(void); void ui_draw_tooltip_background(uiStyle *UNUSED(style), uiBlock *block, rcti *rect); void ui_draw_search_back(struct uiStyle *style, uiBlock *block, rcti *rect); @@ -589,7 +642,6 @@ int ui_id_icon_get(struct bContext *C, struct ID *id, const bool big); /* resources.c */ void init_userdef_do_versions(void); -void init_userdef_factory(void); void ui_theme_init_default(void); void ui_style_init_default(void); void ui_resources_init(void); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 789c10d6693..27af550b173 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -106,6 +106,7 @@ typedef enum uiItemType { ITEM_LAYOUT_ABSOLUTE, ITEM_LAYOUT_SPLIT, ITEM_LAYOUT_OVERLAP, + ITEM_LAYOUT_RADIAL, ITEM_LAYOUT_ROOT #if 0 @@ -218,7 +219,9 @@ static int ui_item_fit(int item, int pos, int all, int available, int last, int static int ui_layout_vary_direction(uiLayout *layout) { - return (layout->root->type == UI_LAYOUT_HEADER || layout->alignment != UI_LAYOUT_ALIGN_EXPAND) ? UI_ITEM_VARY_X : UI_ITEM_VARY_Y; + return ((ELEM(layout->root->type, UI_LAYOUT_HEADER, UI_LAYOUT_PIEMENU) || + (layout->alignment != UI_LAYOUT_ALIGN_EXPAND)) ? + UI_ITEM_VARY_X : UI_ITEM_VARY_Y); } /* estimated size of text + icon */ @@ -553,15 +556,24 @@ static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *pt */ uiBut *but; + uiLayout *layout_radial = NULL; EnumPropertyItem *item, *item_array; const char *name; int itemw, icon, value; bool free; + bool radial = (layout->root->type == UI_LAYOUT_PIEMENU); - RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item_array, NULL, &free); + if (radial) + RNA_property_enum_items_gettexted_all(block->evil_C, ptr, prop, &item_array, NULL, &free); + else + RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item_array, NULL, &free); /* we dont want nested rows, cols in menus */ - if (layout->root->type != UI_LAYOUT_MENU) { + if (radial) { + layout_radial = uiLayoutRadial(layout); + uiBlockSetCurLayout(block, layout_radial); + } + else if (layout->root->type != UI_LAYOUT_MENU) { uiBlockSetCurLayout(block, ui_item_local_sublayout(layout, layout, 1)); } else { @@ -569,8 +581,11 @@ static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *pt } for (item = item_array; item->identifier; item++) { - if (!item->identifier[0]) + if (!item->identifier[0]) { + if (radial) + uiItemS(layout_radial); continue; + } name = (!uiname || uiname[0]) ? item->name : ""; icon = item->icon; @@ -869,6 +884,8 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname PointerRNA ptr; PropertyRNA *prop; uiBlock *block = layout->root->block; + const bool radial = (layout->item.type == ITEM_LAYOUT_RADIAL) || + ((layout->item.type == ITEM_LAYOUT_ROOT) && (layout->root->type == UI_LAYOUT_PIEMENU)); if (!ot || !ot->srna) { ui_item_disabled(layout, opname); @@ -887,10 +904,24 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname if (prop && RNA_property_type(prop) == PROP_ENUM) { EnumPropertyItem *item, *item_array = NULL; bool free; - uiLayout *split = uiLayoutSplit(layout, 0.0f, false); - uiLayout *column = uiLayoutColumn(split, layout->align); + uiLayout *split; + uiLayout *target; + + if (radial) { + target = uiLayoutRadial(layout); + } + else { + split = uiLayoutSplit(layout, 0.0f, false); + target = uiLayoutColumn(split, layout->align); + } + + if (radial) { + RNA_property_enum_items_gettexted_all(block->evil_C, &ptr, prop, &item_array, NULL, &free); + } + else { + RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, NULL, &free); + } - RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, NULL, &free); for (item = item_array; item->identifier; item++) { if (item->identifier[0]) { PointerRNA tptr; @@ -905,20 +936,24 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname } RNA_property_enum_set(&tptr, prop, item->value); - uiItemFullO_ptr(column, ot, item->name, item->icon, tptr.data, context, flag); + uiItemFullO_ptr(target, ot, item->name, item->icon, tptr.data, context, flag); + ui_but_tip_from_enum_item(block->buttons.last, item); } else { if (item->name) { uiBut *but; - if (item != item_array) { - column = uiLayoutColumn(split, layout->align); + + if (item != item_array && !radial) { + target = uiLayoutColumn(split, layout->align); + /* inconsistent, but menus with labels do not look good flipped */ block->flag |= UI_BLOCK_NO_FLIP; } - if (item->icon) { - uiItemL(column, item->name, item->icon); + if (item->icon || radial) { + uiItemL(target, item->name, item->icon); + but = block->buttons.last; } else { @@ -928,8 +963,14 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname } ui_but_tip_from_enum_item(but, item); } - else { /* XXX bug here, colums draw bottom item badly */ - uiItemS(column); + else { + if (radial) { + uiItemS(target); + } + else { + /* XXX bug here, colums draw bottom item badly */ + uiItemS(target); + } } } } @@ -1181,7 +1222,7 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index if (flag & UI_ITEM_R_ICON_ONLY) { /* pass */ } - else if (ELEM4(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) { + else if (ELEM(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) { name = ui_item_name_add_colon(name, namestr); } else if (type == PROP_BOOLEAN && is_array && index == RNA_NO_INDEX) { @@ -1323,9 +1364,9 @@ void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *pr for (a = 0; item[a].identifier; a++) { if (item[a].value == ivalue) { - const char *item_name = CTX_IFACE_(RNA_property_translation_context(prop), item[a].name); + const char *item_name = name ? name : CTX_IFACE_(RNA_property_translation_context(prop), item[a].name); - uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name ? item_name : name, icon ? icon : item[a].icon); + uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name, icon ? icon : item[a].icon); break; } } @@ -1559,7 +1600,7 @@ void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propna } type = RNA_property_type(prop); - if (!ELEM3(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) { + if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) { RNA_warning("Property %s must be a pointer, string or enum", propname); return; } @@ -2072,16 +2113,135 @@ static void ui_litem_layout_column(uiLayout *litem) litem->y = y; } +/* calculates the angle of a specified button in a radial menu, + * stores a float vector in unit circle */ +static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum) +{ + RadialDirection dir; + BLI_assert(itemnum < 8); + + dir = ui_radial_dir_order[itemnum]; + ui_but_pie_dir(dir, vec); + + return dir; +} + +static bool ui_item_is_radial_displayable(uiItem *item) +{ + + if ((item->type == ITEM_BUTTON) && (((uiButtonItem *)item)->but->type == LABEL)) + return false; + + return true; +} + +static bool ui_item_is_radial_drawable(uiButtonItem *bitem) +{ + + if (ELEM(bitem->but->type, SEPR, SEPRLINE)) + return false; + + return true; +} + +static void ui_litem_layout_radial(uiLayout *litem) +{ + uiItem *item; + int itemh, itemw, x, y; + int itemnum = 0; + int totitems = 0; + + int minx, miny, maxx, maxy; + /* For the radial layout we will use Matt Ebb's design + * for radiation, see http://mattebb.com/weblog/radiation/ + * also the old code at http://developer.blender.org/T5103 + */ + + int pie_radius = U.pie_menu_radius * UI_DPI_FAC; + + x = litem->x; + y = litem->y; + + minx = x, miny = y, maxx = x, maxy = y; + + /* first count total items */ + for (item = litem->items.first; item; item = item->next) + totitems++; + + if (totitems < 5) + litem->root->block->pie_data.flags |= UI_PIE_DEGREES_RANGE_LARGE; + + for (item = litem->items.first; item; item = item->next) { + /* not all button types are drawn in a radial menu, do filtering here */ + if (ui_item_is_radial_displayable(item)) { + RadialDirection dir; + float vec[2]; + float factor[2]; + + dir = ui_get_radialbut_vec(vec, itemnum); + factor[0] = (vec[0] > 0.01f) ? 0.0f : ((vec[0] < -0.01f) ? -1.0f : -0.5f); + factor[1] = (vec[1] > 0.99f) ? 0.0f : ((vec[1] < -0.99f) ? -1.0f : -0.5f); + + itemnum++; + + if (item->type == ITEM_BUTTON) { + uiButtonItem *bitem = (uiButtonItem *) item; + + bitem->but->pie_dir = dir; + /* scale the buttons */ + bitem->but->rect.ymax *= 1.5f; + /* add a little bit more here to include number */ + bitem->but->rect.xmax += 1.5f * UI_UNIT_X; + /* enable drawing as pie item if supported by widget */ + if (ui_item_is_radial_drawable(bitem)) + bitem->but->dt = UI_EMBOSSR; + } + + ui_item_size(item, &itemw, &itemh); + + ui_item_position(item, x + vec[0] * pie_radius + factor[0] * itemw, y + vec[1] * pie_radius + factor[1] * itemh, itemw, itemh); + + minx = min_ii(minx, x + vec[0] * pie_radius - itemw / 2); + maxx = max_ii(maxx, x + vec[0] * pie_radius + itemw / 2); + miny = min_ii(miny, y + vec[1] * pie_radius - itemh / 2); + maxy = max_ii(maxy, y + vec[1] * pie_radius + itemh / 2); + } + } + + litem->x = minx; + litem->y = miny; + litem->w = maxx - minx; + litem->h = maxy - miny; +} + /* root layout */ static void ui_litem_estimate_root(uiLayout *UNUSED(litem)) { /* nothing to do */ } +static void ui_litem_layout_root_radial(uiLayout *litem) +{ + /* first item is pie menu title, align on center of menu */ + uiItem *item = litem->items.first; + + if (item->type == ITEM_BUTTON) { + int itemh, itemw, x, y; + x = litem->x; + y = litem->y; + + ui_item_size(item, &itemw, &itemh); + + ui_item_position(item, x - itemw / 2, y + U.pixelsize * (U.pie_menu_threshold + 9.0f), itemw, itemh); + } +} + static void ui_litem_layout_root(uiLayout *litem) { if (litem->root->type == UI_LAYOUT_HEADER) ui_litem_layout_row(litem); + else if (litem->root->type == UI_LAYOUT_PIEMENU) + ui_litem_layout_root_radial(litem); else ui_litem_layout_column(litem); } @@ -2497,6 +2657,40 @@ static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type) return box; } +uiLayout *uiLayoutRadial(uiLayout *layout) +{ + uiLayout *litem; + uiItem *item; + + /* radial layouts are only valid for radial menus */ + if (layout->root->type != UI_LAYOUT_PIEMENU) + return ui_item_local_sublayout(layout, layout, 0); + + /* only one radial wheel per root layout is allowed, so check and return that, if it exists */ + for (item = layout->root->layout->items.first; item; item = item->next) { + litem = (uiLayout *)item; + if (litem->item.type == ITEM_LAYOUT_RADIAL) { + uiBlockSetCurLayout(layout->root->block, litem); + return litem; + } + } + + litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRadial"); + litem->item.type = ITEM_LAYOUT_RADIAL; + litem->root = layout->root; + litem->active = true; + litem->enabled = true; + litem->context = layout->context; + litem->redalert = layout->redalert; + litem->w = layout->w; + BLI_addtail(&layout->root->layout->items, litem); + + uiBlockSetCurLayout(layout->root->block, litem); + + return litem; +} + + uiLayout *uiLayoutBox(uiLayout *layout) { return (uiLayout *)ui_layout_box(layout, ROUNDBOX); @@ -2843,6 +3037,9 @@ static void ui_item_layout(uiItem *item) case ITEM_LAYOUT_OVERLAP: ui_litem_layout_overlap(litem); break; + case ITEM_LAYOUT_RADIAL: + ui_litem_layout_radial(litem); + break; default: break; } @@ -2916,7 +3113,7 @@ uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int siz layout->enabled = 1; layout->context = NULL; - if (type == UI_LAYOUT_MENU) + if (type == UI_LAYOUT_MENU || type == UI_LAYOUT_PIEMENU) layout->space = 0; if (dir == UI_LAYOUT_HORIZONTAL) { diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 316a4d34881..817445cc14e 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -35,6 +35,7 @@ #include "DNA_text_types.h" /* for UI_OT_reports_to_text */ #include "BLI_blenlib.h" +#include "BLI_math_color.h" #include "BLF_api.h" #include "BLF_translation.h" @@ -44,6 +45,7 @@ #include "BKE_global.h" #include "BKE_text.h" /* for UI_OT_reports_to_text */ #include "BKE_report.h" +#include "BKE_paint.h" #include "RNA_access.h" #include "RNA_define.h" @@ -55,6 +57,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "ED_paint.h" + /* only for UI_OT_editsource */ #include "ED_screen.h" #include "BKE_main.h" @@ -258,28 +262,43 @@ static void UI_OT_unset_property_button(wmOperatorType *ot) /* Copy To Selected Operator ------------------------ */ -static bool copy_to_selected_list(bContext *C, PointerRNA *ptr, ListBase *lb, bool *use_path) +static bool copy_to_selected_list( + bContext *C, PointerRNA *ptr, PropertyRNA *prop, + ListBase *r_lb, bool *r_use_path_from_id, char **r_path) { - *use_path = false; + *r_use_path_from_id = false; + *r_path = NULL; - if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) - *lb = CTX_data_collection_get(C, "selected_editable_bones"); - else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) - *lb = CTX_data_collection_get(C, "selected_pose_bones"); - else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) - *lb = CTX_data_collection_get(C, "selected_editable_sequences"); - else { + if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) { + *r_lb = CTX_data_collection_get(C, "selected_editable_bones"); + } + else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) { + *r_lb = CTX_data_collection_get(C, "selected_pose_bones"); + } + else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) { + *r_lb = CTX_data_collection_get(C, "selected_editable_sequences"); + } + else if (ptr->id.data) { ID *id = ptr->id.data; - if (id && GS(id->name) == ID_OB) { - *lb = CTX_data_collection_get(C, "selected_editable_objects"); - *use_path = true; + if (GS(id->name) == ID_OB) { + *r_lb = CTX_data_collection_get(C, "selected_editable_objects"); + *r_use_path_from_id = true; + *r_path = RNA_path_from_ID_to_property(ptr, prop); } - else { - return false; + else if (GS(id->name) == ID_SCE) { + /* Sequencer's ID is scene :/ */ + /* Try to recursively find an RNA_Sequence ancestor, to handle situations like T41062... */ + if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) { + *r_lb = CTX_data_collection_get(C, "selected_editable_sequences"); + } } + return (*r_path != NULL); } - + else { + return false; + } + return true; } @@ -303,47 +322,54 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll) /* if there is a valid property that is editable... */ if (ptr.data && prop) { char *path = NULL; - bool use_path; + bool use_path_from_id; CollectionPointerLink *link; ListBase lb; - if (!copy_to_selected_list(C, &ptr, &lb, &use_path)) + if (!copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) return success; - if (!use_path || (path = RNA_path_from_ID_to_property(&ptr, prop))) { - for (link = lb.first; link; link = link->next) { - if (link->ptr.data != ptr.data) { - if (use_path) { - lprop = NULL; - RNA_id_pointer_create(link->ptr.id.data, &idptr); - RNA_path_resolve_property(&idptr, path, &lptr, &lprop); - } - else { - lptr = link->ptr; - lprop = prop; - } + for (link = lb.first; link; link = link->next) { + if (link->ptr.data != ptr.data) { + if (use_path_from_id) { + /* Path relative to ID. */ + lprop = NULL; + RNA_id_pointer_create(link->ptr.id.data, &idptr); + RNA_path_resolve_property(&idptr, path, &lptr, &lprop); + } + else if (path) { + /* Path relative to elements from list. */ + lprop = NULL; + RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); + } + else { + lptr = link->ptr; + lprop = prop; + } - if (lprop == prop) { - if (RNA_property_editable(&lptr, lprop)) { - if (poll) { + if (lptr.data == ptr.data) { + /* lptr might not be the same as link->ptr! */ + continue; + } + + if (lprop == prop) { + if (RNA_property_editable(&lptr, lprop)) { + if (poll) { + success = true; + break; + } + else { + if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) { + RNA_property_update(C, &lptr, prop); success = true; - break; - } - else { - if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) { - RNA_property_update(C, &lptr, prop); - success = true; - } } } } } } - - if (path) - MEM_freeN(path); } + MEM_SAFE_FREE(path); BLI_freelistN(&lb); } @@ -693,6 +719,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op) int ret = OPERATOR_CANCELLED; if (but) { + wmOperatorType *ot; PointerRNA ptr; char popath[FILE_MAX]; const char *root = U.i18ndir; @@ -714,7 +741,8 @@ static int edittranslation_exec(bContext *C, wmOperator *op) "Directory' path to a valid directory"); return OPERATOR_CANCELLED; } - if (!WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0)) { + ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0); + if (ot == NULL) { BKE_reportf(op->reports, RPT_ERROR, "Could not find operator '%s'! Please enable ui_translate addon " "in the User Preferences", EDTSRC_I18N_OP_NAME); return OPERATOR_CANCELLED; @@ -730,7 +758,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op) uiButGetStrInfo(C, but, &but_label, &rna_label, &enum_label, &but_tip, &rna_tip, &enum_tip, &rna_struct, &rna_prop, &rna_enum, &rna_ctxt, NULL); - WM_operator_properties_create(&ptr, EDTSRC_I18N_OP_NAME); + WM_operator_properties_create_ptr(&ptr, ot); RNA_string_set(&ptr, "lang", uilng); RNA_string_set(&ptr, "po_file", popath); RNA_string_set(&ptr, "but_label", but_label.strinfo); @@ -743,7 +771,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op) RNA_string_set(&ptr, "rna_prop", rna_prop.strinfo); RNA_string_set(&ptr, "rna_enum", rna_enum.strinfo); RNA_string_set(&ptr, "rna_ctxt", rna_ctxt.strinfo); - ret = WM_operator_name_call(C, EDTSRC_I18N_OP_NAME, WM_OP_INVOKE_DEFAULT, &ptr); + ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); /* Clean up */ if (but_label.strinfo) @@ -808,6 +836,99 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot) ot->exec = reloadtranslation_exec; } +int UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event)) +{ + /* should only return true for regions that include buttons, for now + * return true always */ + if (drag->type == WM_DRAG_COLOR) { + SpaceImage *sima = CTX_wm_space_image(C); + ARegion *ar = CTX_wm_region(C); + + if (UI_but_active_drop_color(C)) + return 1; + + if (sima && (sima->mode == SI_MODE_PAINT) && + sima->image && (ar && ar->regiontype == RGN_TYPE_WINDOW)) + { + return 1; + } + } + + return 0; +} + +void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop) +{ + uiDragColorHandle *drag_info = (uiDragColorHandle *)drag->poin; + + RNA_float_set_array(drop->ptr, "color", drag_info->color); + RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected); +} + +static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + ARegion *ar = CTX_wm_region(C); + uiBut *but = NULL; + float color[4]; + bool gamma; + + RNA_float_get_array(op->ptr, "color", color); + gamma = RNA_boolean_get(op->ptr, "gamma"); + + /* find button under mouse, check if it has RNA color property and + * if it does copy the data */ + but = ui_but_find_activated(ar); + + if (but && but->type == COLOR && but->rnaprop) { + const int color_len = RNA_property_array_length(&but->rnapoin, but->rnaprop); + BLI_assert(color_len <= 4); + + /* keep alpha channel as-is */ + if (color_len == 4) { + color[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3); + } + + if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) { + if (!gamma) + ui_block_to_display_space_v3(but->block, color); + RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color); + RNA_property_update(C, &but->rnapoin, but->rnaprop); + } + else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) { + if (gamma) + ui_block_to_scene_linear_v3(but->block, color); + RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color); + RNA_property_update(C, &but->rnapoin, but->rnaprop); + } + } + else { + if (gamma) { + srgb_to_linearrgb_v3_v3(color, color); + } + + ED_imapaint_bucket_fill(C, color, op); + } + + ED_region_tag_redraw(ar); + + return OPERATOR_FINISHED; +} + + +static void UI_OT_drop_color(wmOperatorType *ot) +{ + ot->name = "Drop Color"; + ot->idname = "UI_OT_drop_color"; + ot->description = "Drop colors to buttons"; + + ot->invoke = drop_color_invoke; + + RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0); + RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected "); +} + + + /* ********************************************************* */ /* Registration */ @@ -819,7 +940,7 @@ void UI_buttons_operatortypes(void) 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? */ - + WM_operatortype_append(UI_OT_drop_color); #ifdef WITH_PYTHON WM_operatortype_append(UI_OT_editsource); WM_operatortype_append(UI_OT_edittranslation_init); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 2ccb3740777..9265ca0d4b9 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -120,7 +120,7 @@ static int panel_aligned(ScrArea *sa, ARegion *ar) return BUT_VERTICAL; else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW) return BUT_VERTICAL; - else if (ELEM3(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) + else if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) return BUT_VERTICAL; return 0; @@ -201,20 +201,33 @@ static void ui_panel_copy_offset(Panel *pa, Panel *papar) pa->ofsy = papar->ofsy + papar->sizey - pa->sizey; } + +/* XXX Disabled paneltab handling for now. Old 2.4x feature, *DO NOT* confuse it with new tool tabs in 2.70. ;) + * See also T41704. + */ +/* #define UI_USE_PANELTAB */ + Panel *uiPanelFindByType(ARegion *ar, PanelType *pt) { Panel *pa; - const char *idname = pt->idname; - const char *tabname = pt->idname; +#ifdef UI_USE_PANELTAB + const char *tabname = pt->idname; for (pa = ar->panels.first; pa; pa = pa->next) { if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) { - if (STREQLEN(pa->tabname, tabname, sizeof(pa->panelname))) { + if (STREQLEN(pa->tabname, tabname, sizeof(pa->tabname))) { return pa; } } } +#else + for (pa = ar->panels.first; pa; pa = pa->next) { + if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) { + return pa; + } + } +#endif return NULL; } @@ -224,11 +237,13 @@ Panel *uiPanelFindByType(ARegion *ar, PanelType *pt) */ Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Panel *pa, bool *r_open) { - Panel *patab, *palast, *panext; + Panel *palast, *panext; const char *drawname = CTX_IFACE_(pt->translation_context, pt->label); const char *idname = pt->idname; +#ifdef UI_USE_PANELTAB const char *tabname = pt->idname; const char *hookname = NULL; +#endif const bool newpanel = (pa == NULL); int align = panel_aligned(sa, ar); @@ -240,7 +255,6 @@ Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Pan pa = MEM_callocN(sizeof(Panel), "new panel"); pa->type = pt; BLI_strncpy(pa->panelname, idname, sizeof(pa->panelname)); - BLI_strncpy(pa->tabname, tabname, sizeof(pa->tabname)); if (pt->flag & PNL_DEFAULT_CLOSED) { if (align == BUT_VERTICAL) @@ -256,9 +270,13 @@ Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Pan pa->runtime_flag |= PNL_NEW_ADDED; BLI_addtail(&ar->panels, pa); - + +#ifdef UI_USE_PANELTAB + BLI_strncpy(pa->tabname, tabname, sizeof(pa->tabname)); + /* make new Panel tabbed? */ if (hookname) { + Panel *patab; for (patab = ar->panels.first; patab; patab = patab->next) { if ((patab->runtime_flag & PNL_ACTIVE) && patab->paneltab == NULL) { if (STREQLEN(hookname, patab->panelname, sizeof(patab->panelname))) { @@ -271,6 +289,9 @@ Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Pan } } } +#else + BLI_strncpy(pa->tabname, idname, sizeof(pa->tabname)); +#endif } /* Do not allow closed panels without headers! Else user could get "disappeared" UI! */ @@ -462,31 +483,41 @@ static void ui_draw_panel_scalewidget(const rcti *rect) fdrawline(xmin + dx, ymin + 1, xmax, ymax - dy + 1); glDisable(GL_BLEND); } - static void ui_draw_panel_dragwidget(const rctf *rect) { - float xmin, xmax, dx; - float ymin, ymax, dy; - - xmin = rect->xmin; - xmax = rect->xmax; - ymin = rect->ymin; - ymax = rect->ymax; - - dx = (xmax - xmin) / 3.0f; - dy = (ymax - ymin) / 3.0f; - - glEnable(GL_BLEND); - glColor4ub(255, 255, 255, 50); - fdrawline(xmin, ymax, xmax, ymin); - fdrawline(xmin + dx, ymax, xmax, ymin + dy); - fdrawline(xmin + 2 * dx, ymax, xmax, ymin + 2 * dy); - - glColor4ub(0, 0, 0, 50); - fdrawline(xmin, ymax + 1, xmax, ymin + 1); - fdrawline(xmin + dx, ymax + 1, xmax, ymin + dy + 1); - fdrawline(xmin + 2 * dx, ymax + 1, xmax, ymin + 2 * dy + 1); - glDisable(GL_BLEND); + unsigned char col_back[3], col_high[3], col_dark[3]; + const int col_tint = 84; + + const int px = (int)U.pixelsize; + const int px_zoom = max_ii(iroundf(BLI_rctf_size_y(rect) / 22.0f), 1); + + const int box_margin = max_ii(iroundf((float)(px_zoom * 2.0f)), px); + const int box_size = max_ii(iroundf((BLI_rctf_size_y(rect) / 8.0f) - px), px); + + const int x_min = rect->xmin; + const int y_min = rect->ymin; + const int y_ofs = max_ii(iroundf(BLI_rctf_size_y(rect) / 3.0f), px); + const int x_ofs = y_ofs; + int i_x, i_y; + + + UI_GetThemeColor3ubv(UI_GetThemeValue(TH_PANEL_SHOW_HEADER) ? TH_PANEL_HEADER : TH_PANEL_BACK, col_back); + UI_GetColorPtrShade3ubv(col_back, col_high, col_tint); + UI_GetColorPtrShade3ubv(col_back, col_dark, -col_tint); + + + /* draw multiple boxes */ + for (i_x = 0; i_x < 4; i_x++) { + for (i_y = 0; i_y < 2; i_y++) { + const int x_co = (x_min + x_ofs) + (i_x * (box_size + box_margin)); + const int y_co = (y_min + y_ofs) + (i_y * (box_size + box_margin)); + + glColor3ubv(col_dark); + glRectf(x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom); + glColor3ubv(col_high); + glRectf(x_co - box_size, y_co, x_co, y_co + box_size); + } + } } @@ -1131,7 +1162,7 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in button = 1; else if (event == AKEY) button = 1; - else if (ELEM3(event, 0, RETKEY, LEFTMOUSE) && shift) { + else if (ELEM(event, 0, RETKEY, LEFTMOUSE) && shift) { block->panel->flag ^= PNL_PIN; button = 2; } @@ -1524,6 +1555,12 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) const bool is_active = STREQ(category_id, category_id_active); +#ifdef DEBUG + if (STREQ(category_id, PNL_CATEGORY_FALLBACK)) { + printf("WARNING: Panel has no 'bl_category', script needs updating!\n"); + } +#endif + glEnable(GL_BLEND); #ifdef USE_FLAT_INACTIVE @@ -1716,7 +1753,7 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar) /* XXX hardcoded key warning */ if ((inside || inside_header) && event->val == KM_PRESS) { - if (event->type == AKEY && !ELEM4(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) { + if (event->type == AKEY && !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) { if (pa->flag & PNL_CLOSEDY) { if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) @@ -1902,7 +1939,7 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat data = MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData"); pa->activedata = data; - WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa); + WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, false); } if (ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG)) diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index c32f0de937e..1960c77bc95 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -43,6 +43,8 @@ #include "BLI_utildefines.h" #include "BLI_ghash.h" +#include "PIL_time.h" + #include "BKE_context.h" #include "BKE_screen.h" #include "BKE_report.h" @@ -392,7 +394,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) data->totline++; } - if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { /* better not show the value of a password */ if ((but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD)) == 0) { /* full string */ @@ -1163,8 +1165,9 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but) /* widget rect, in region coords */ data->bbox.xmin = width; data->bbox.xmax = BLI_rcti_size_x(&ar->winrct) - width; - data->bbox.ymin = width; - data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - width; + /* Do not use shadow width for height, gives insane margin with big shadows, and issue T41548 with small ones */ + data->bbox.ymin = 8 * UI_DPI_FAC; + data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - 8 * UI_DPI_FAC; /* check if button is lower half */ if (but->rect.ymax < BLI_rctf_cent_y(&but->block->rect)) { @@ -1704,18 +1707,69 @@ uiBlock *ui_popup_block_refresh( BLI_addhead(&block->saferct, saferct); } - /* clip block with window boundary */ - ui_popup_block_clip(window, block); - - /* the block and buttons were positioned in window space as in 2.4x, now - * these menu blocks are regions so we bring it back to region space. - * additionally we add some padding for the menu shadow or rounded menus */ - ar->winrct.xmin = block->rect.xmin - width; - ar->winrct.xmax = block->rect.xmax + width; - ar->winrct.ymin = block->rect.ymin - width; - ar->winrct.ymax = block->rect.ymax + MENU_TOP; - - ui_block_translate(block, -ar->winrct.xmin, -ar->winrct.ymin); + if (block->flag & UI_BLOCK_RADIAL) { + uiBut *but; + int win_width = UI_SCREEN_MARGIN; + int winx, winy; + + int x_offset = 0, y_offset = 0; + + winx = WM_window_pixels_x(window); + winy = WM_window_pixels_y(window); + + copy_v2_v2(block->pie_data.pie_center_init, block->pie_data.pie_center_spawned); + + /* only try translation if area is large enough */ + if (BLI_rctf_size_x(&block->rect) < winx - (2.0f * win_width)) { + if (block->rect.xmin < win_width ) x_offset += win_width - block->rect.xmin; + if (block->rect.xmax > winx - win_width) x_offset += winx - win_width - block->rect.xmax; + } + + if (BLI_rctf_size_y(&block->rect) < winy - (2.0f * win_width)) { + if (block->rect.ymin < win_width ) y_offset += win_width - block->rect.ymin; + if (block->rect.ymax > winy - win_width) y_offset += winy - win_width - block->rect.ymax; + } + /* if we are offsetting set up initial data for timeout functionality */ + + if ((x_offset != 0) || (y_offset != 0)) { + block->pie_data.pie_center_spawned[0] += x_offset; + block->pie_data.pie_center_spawned[1] += y_offset; + + ui_block_translate(block, x_offset, y_offset); + + if (U.pie_initial_timeout > 0) + block->pie_data.flags |= UI_PIE_INITIAL_DIRECTION; + } + + ar->winrct.xmin = 0; + ar->winrct.xmax = winx; + ar->winrct.ymin = 0; + ar->winrct.ymax = winy; + + ui_block_calculate_pie_segment(block, block->pie_data.pie_center_init); + + /* lastly set the buttons at the center of the pie menu, ready for animation */ + if (U.pie_animation_timeout > 0) { + for (but = block->buttons.first; but; but = but->next) { + if (but->pie_dir != UI_RADIAL_NONE) { + BLI_rctf_recenter(&but->rect, UNPACK2(block->pie_data.pie_center_spawned)); + } + } + } + } + else { + /* clip block with window boundary */ + ui_popup_block_clip(window, block); + /* the block and buttons were positioned in window space as in 2.4x, now + * these menu blocks are regions so we bring it back to region space. + * additionally we add some padding for the menu shadow or rounded menus */ + ar->winrct.xmin = block->rect.xmin - width; + ar->winrct.xmax = block->rect.xmax + width; + ar->winrct.ymin = block->rect.ymin - width; + ar->winrct.ymax = block->rect.ymax + MENU_TOP; + + ui_block_translate(block, -ar->winrct.xmin, -ar->winrct.ymin); + } if (block_old) { block->oldblock = block_old; @@ -1872,7 +1926,7 @@ static void ui_update_block_buts_rgb(uiBlock *block, const float rgb[3], bool is if (rgb_gamma[2] > 1.0f) rgb_gamma[2] = modf(rgb_gamma[2], &intpart); rgb_float_to_uchar(rgb_gamma_uchar, rgb_gamma); - BLI_snprintf(col, sizeof(col), "%02X%02X%02X", UNPACK3OP((unsigned int), rgb_gamma_uchar)); + BLI_snprintf(col, sizeof(col), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, )); strcpy(bt->poin, col); } @@ -2160,7 +2214,7 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper } rgb_float_to_uchar(rgb_gamma_uchar, rgb_gamma); - BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3OP((unsigned int), rgb_gamma_uchar)); + BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, )); yco = -3.0f * UI_UNIT_Y; bt = uiDefBut(block, TEX, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)")); @@ -2353,6 +2407,12 @@ struct uiPopupMenu { void *menu_arg; }; +struct uiPieMenu { + uiBlock *block_radial; /* radial block of the pie menu (more could be added later) */ + uiLayout *layout; + int mx, my; +}; + static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, void *arg_pup) { uiBlock *block; @@ -2408,6 +2468,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT); if (pup->popup) { + uiBut *but_activate = NULL; uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_NUMSELECT); uiBlockSetDirection(block, direction); @@ -2421,6 +2482,10 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi * block to be under the mouse */ offset[0] = -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect)); offset[1] = -(bt->rect.ymin + 0.5f * UI_UNIT_Y); + + if (ui_but_is_editable(bt)) { + but_activate = bt; + } } else { /* position mouse at 0.8*width of the button and below the tile @@ -2430,6 +2495,20 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi offset[0] = min_ii(offset[0], -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect))); offset[1] = 2.1 * UI_UNIT_Y; + + for (bt = block->buttons.first; bt; bt = bt->next) { + if (ui_but_is_editable(bt)) { + but_activate = bt; + break; + } + } + } + + /* in rare cases this is needed since moving the popup + * to be within the window bounds may move it away from the mouse, + * This ensures we set an item to be active. */ + if (but_activate) { + ui_button_activate_over(C, handle->region, but_activate); } block->minbounds = minwidth; @@ -2507,7 +2586,7 @@ uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut if (!but) { handle->popup = true; - UI_add_popup_handlers(C, &window->modalhandlers, handle); + UI_add_popup_handlers(C, &window->modalhandlers, handle, false); WM_event_add_mousemove(C); } @@ -2569,7 +2648,7 @@ void uiPupMenuEnd(bContext *C, uiPopupMenu *pup) menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPUP, pup); menu->popup = true; - UI_add_popup_handlers(C, &window->modalhandlers, menu); + UI_add_popup_handlers(C, &window->modalhandlers, menu, false); WM_event_add_mousemove(C); MEM_freeN(pup); @@ -2580,6 +2659,178 @@ uiLayout *uiPupMenuLayout(uiPopupMenu *pup) return pup->layout; } +/*************************** Pie Menus ***************************************/ + +static uiBlock *ui_block_func_PIE(bContext *UNUSED(C), uiPopupBlockHandle *handle, void *arg_pie) +{ + uiBlock *block; + uiPieMenu *pie = arg_pie; + int minwidth, width, height; + + minwidth = 50; + block = pie->block_radial; + + /* in some cases we create the block before the region, + * so we set it delayed here if necessary */ + if (BLI_findindex(&handle->region->uiblocks, block) == -1) + uiBlockSetRegion(block, handle->region); + + uiBlockLayoutResolve(block, &width, &height); + + uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_NUMSELECT); + + block->minbounds = minwidth; + block->bounds = 1; + block->mx = 0; + block->my = 0; + block->bounds_type = UI_BLOCK_BOUNDS_PIE_CENTER; + + block->pie_data.pie_center_spawned[0] = pie->mx; + block->pie_data.pie_center_spawned[1] = pie->my; + + return pie->block_radial; +} + +static float uiPieTitleWidth(const char *name, int icon) +{ + return (UI_GetStringWidth(name) + + (UI_UNIT_X * (1.50f + (icon ? 0.25f : 0.0f)))); +} + +uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const wmEvent *event) +{ + uiStyle *style = UI_GetStyleDraw(); + uiPieMenu *pie = MEM_callocN(sizeof(uiPopupMenu), "pie menu"); + + pie->block_radial = uiBeginBlock(C, NULL, __func__, UI_EMBOSS); + /* may be useful later to allow spawning pies + * from old positions */ + /* pie->block_radial->flag |= UI_BLOCK_POPUP_MEMORY; */ + pie->block_radial->puphash = ui_popup_menu_hash(title); + pie->block_radial->flag |= UI_BLOCK_RADIAL; + pie->block_radial->pie_data.event = event->type; + + pie->layout = uiBlockLayout(pie->block_radial, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style); + pie->mx = event->x; + pie->my = event->y; + + /* create title button */ + if (title[0]) { + uiBut *but; + char titlestr[256]; + int w; + if (icon) { + BLI_snprintf(titlestr, sizeof(titlestr), " %s", title); + w = uiPieTitleWidth(titlestr, icon); + but = uiDefIconTextBut(pie->block_radial, LABEL, 0, icon, titlestr, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); + } + else { + w = uiPieTitleWidth(title, 0); + but = uiDefBut(pie->block_radial, LABEL, 0, title, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); + } + /* do not align left */ + but->drawflag &= ~UI_BUT_TEXT_LEFT; + } + + return pie; +} + +void uiPieMenuEnd(bContext *C, uiPieMenu *pie) +{ + wmWindow *window = CTX_wm_window(C); + uiPopupBlockHandle *menu; + + menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_PIE, pie); + menu->popup = true; + menu->towardstime = PIL_check_seconds_timer(); + + UI_add_popup_handlers(C, &window->modalhandlers, menu, true); + WM_event_add_mousemove(C); + + MEM_freeN(pie); +} + +uiLayout *uiPieMenuLayout(uiPieMenu *pie) +{ + return pie->layout; +} + +void uiPieMenuInvoke(struct bContext *C, const char *idname, const wmEvent *event) +{ + uiPieMenu *pie; + uiLayout *layout; + Menu menu; + MenuType *mt = WM_menutype_find(idname, true); + + if (mt == NULL) { + printf("%s: named menu \"%s\" not found\n", __func__, idname); + return; + } + + if (mt->poll && mt->poll(C, mt) == 0) + return; + + pie = uiPieMenuBegin(C, IFACE_(mt->label), ICON_NONE, event); + layout = uiPieMenuLayout(pie); + + menu.layout = layout; + menu.type = mt; + + if (G.debug & G_DEBUG_WM) { + printf("%s: opening menu \"%s\"\n", __func__, idname); + } + + mt->draw(C, &menu); + + uiPieMenuEnd(C, pie); +} + +void uiPieOperatorEnumInvoke(struct bContext *C, const char *title, const char *opname, + const char *propname, const wmEvent *event) +{ + uiPieMenu *pie; + uiLayout *layout; + + pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event); + layout = uiPieMenuLayout(pie); + + layout = uiLayoutRadial(layout); + uiItemsEnumO(layout, opname, propname); + + uiPieMenuEnd(C, pie); +} + +void uiPieEnumInvoke(struct bContext *C, const char *title, const char *path, + const wmEvent *event) +{ + PointerRNA ctx_ptr; + PointerRNA r_ptr; + PropertyRNA *r_prop; + uiPieMenu *pie; + uiLayout *layout; + + RNA_pointer_create(NULL, &RNA_Context, C, &ctx_ptr); + + if (!RNA_path_resolve(&ctx_ptr, path, &r_ptr, &r_prop)) { + return; + } + + /* invalid property, only accept enums */ + if (RNA_property_type(r_prop) != PROP_ENUM) { + BLI_assert(0); + return; + } + + pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event); + layout = uiPieMenuLayout(pie); + + layout = uiLayoutRadial(layout); + uiItemFullR(layout, &r_ptr, r_prop, RNA_NO_INDEX, 0, UI_ITEM_R_EXPAND, NULL, 0); + + uiPieMenuEnd(C, pie); +} + + /*************************** Standard Popup Menus ****************************/ void uiPupMenuReports(bContext *C, ReportList *reports) @@ -2676,7 +2927,7 @@ void uiPupBlockO(bContext *C, uiBlockCreateFunc func, void *arg, const char *opn handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL; handle->opcontext = opcontext; - UI_add_popup_handlers(C, &window->modalhandlers, handle); + UI_add_popup_handlers(C, &window->modalhandlers, handle, false); WM_event_add_mousemove(C); } @@ -2699,7 +2950,7 @@ void uiPupBlockEx(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_f handle->cancel_func = cancel_func; // handle->opcontext = opcontext; - UI_add_popup_handlers(C, &window->modalhandlers, handle); + UI_add_popup_handlers(C, &window->modalhandlers, handle, false); WM_event_add_mousemove(C); } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 243aa452f17..364a62bd2a0 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -36,6 +36,8 @@ #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_object_force.h" +#include "DNA_brush_types.h" +#include "DNA_texture_types.h" #include "BLI_utildefines.h" #include "BLI_string.h" @@ -60,6 +62,7 @@ #include "BKE_object.h" #include "BKE_packedFile.h" #include "BKE_particle.h" +#include "BKE_paint.h" #include "BKE_report.h" #include "BKE_sca.h" #include "BKE_screen.h" @@ -349,6 +352,8 @@ static const char *template_id_browse_tip(StructRNA *type) case ID_BR: return N_("Browse Brush to be linked"); case ID_PA: return N_("Browse Particle Settings to be linked"); case ID_GD: return N_("Browse Grease Pencil Data to be linked"); + case ID_PAL: return N_("Browse Palette Data to be linked"); + case ID_PC: return N_("Browse Paint Curve Data to be linked"); } } return N_("Browse ID data to be linked"); @@ -489,7 +494,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str if (user_alert) uiButSetFlag(but, UI_BUT_REDALERT); - if (id->lib == NULL && !(ELEM5(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) { + if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) { uiDefButR(block, TOG, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL); } } @@ -571,24 +576,33 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str /* delete button */ /* don't use RNA_property_is_unlink here */ - if (id && (flag & UI_ID_DELETE) && (RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) { + if (id && (flag & UI_ID_DELETE)) { + /* allow unlink if 'unlinkop' is passed, even when 'PROP_NEVER_UNLINK' is set */ + but = NULL; + if (unlinkop) { but = uiDefIconButO(block, BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL); /* so we can access the template from operators, font unlinking needs this */ uiButSetNFunc(but, NULL, MEM_dupallocN(template), NULL); } else { - but = uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, - TIP_("Unlink datablock " - "(Shift + Click to set users to zero, data will then not be saved)")); - uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE)); + if ((RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) { + but = uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, + TIP_("Unlink datablock " + "(Shift + Click to set users to zero, data will then not be saved)")); + uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE)); - if (RNA_property_flag(template->prop) & PROP_NEVER_NULL) - uiButSetFlag(but, UI_BUT_DISABLED); + if (RNA_property_flag(template->prop) & PROP_NEVER_NULL) { + uiButSetFlag(but, UI_BUT_DISABLED); + } + } } - if ((idfrom && idfrom->lib) || !editable) - uiButSetFlag(but, UI_BUT_DISABLED); + if (but) { + if ((idfrom && idfrom->lib) || !editable) { + uiButSetFlag(but, UI_BUT_DISABLED); + } + } } if (idcode == ID_TE) @@ -751,28 +765,6 @@ void uiTemplatePathBuilder(uiLayout *layout, PointerRNA *ptr, const char *propna #define ERROR_LIBDATA_MESSAGE IFACE_("Can't edit external libdata") -static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v) -{ - Scene *scene = CTX_data_scene(C); - Object *ob = ob_v; - ModifierData *md = md_v; - int i, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 0); - - /* undo button operation */ - md->mode ^= eModifierMode_OnCage; - - for (i = 0, md = ob->modifiers.first; md; ++i, md = md->next) { - if (md == md_v) { - if (i >= cageIndex) - md->mode ^= eModifierMode_OnCage; - break; - } - } - - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); -} - static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v) { Object *ob = ob_v; @@ -808,7 +800,7 @@ static int modifier_can_delete(ModifierData *md) static int modifier_is_simulation(ModifierData *md) { /* Physic Tab */ - if (ELEM7(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke, + if (ELEM(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke, eModifierType_Softbody, eModifierType_Surface, eModifierType_DynamicPaint)) { return 1; @@ -829,7 +821,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob, PointerRNA ptr; uiBut *but; uiBlock *block; - uiLayout *box, *column, *row; + uiLayout *box, *column, *row, *sub; uiLayout *result = NULL; int isVirtual = (md->mode & eModifierMode_Virtual); char str[128]; @@ -870,7 +862,11 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob, uiBlockSetEmboss(block, UI_EMBOSS); /* modifier name */ + if (mti->isDisabled && mti->isDisabled(md, 0)) { + uiLayoutSetRedAlert(row, true); + } uiItemR(row, &ptr, "name", 0, "", ICON_NONE); + uiLayoutSetRedAlert(row, false); /* mode enabling buttons */ uiBlockBeginAlign(block); @@ -881,39 +877,32 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob, uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE); uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE); - if (mti->flags & eModifierTypeFlag_SupportsEditmode) - uiItemR(row, &ptr, "show_in_editmode", 0, "", ICON_NONE); + if (mti->flags & eModifierTypeFlag_SupportsEditmode) { + sub = uiLayoutRow(row, true); + if (!(md->mode & eModifierMode_Realtime)) { + uiLayoutSetActive(sub, false); + } + uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE); + } } if (ob->type == OB_MESH) { - if (modifier_couldBeCage(scene, md) && (index <= lastCageIndex)) { - /* -- convert to rna ? */ - but = uiDefIconButBitI(block, TOG, eModifierMode_OnCage, 0, ICON_MESH_DATA, 0, 0, - UI_UNIT_X - 2, UI_UNIT_Y, &md->mode, 0.0, 0.0, 0.0, 0.0, - TIP_("Apply modifier to editing cage during Edit mode")); - if (index < cageIndex) - uiButSetFlag(but, UI_BUT_DISABLED); - uiButSetFunc(but, modifiers_setOnCage, ob, md); - } - else if (modifier_supportsCage(scene, md) && (index <= lastCageIndex)) { - uiBlockEndAlign(block); - - /* place holder button */ - uiBlockSetEmboss(block, UI_EMBOSSN); - but = uiDefIconBut(block, BUT, 0, ICON_NONE, 0, 0, UI_UNIT_X - 2, UI_UNIT_Y, - NULL, 0.0, 0.0, 0.0, 0.0, NULL); - uiButSetFlag(but, UI_BUT_DISABLED); - uiBlockSetEmboss(block, UI_EMBOSS); + if (modifier_supportsCage(scene, md) && (index <= lastCageIndex)) { + sub = uiLayoutRow(row, true); + if (index < cageIndex || !modifier_couldBeCage(scene, md)) { + uiLayoutSetActive(sub, false); + } + uiItemR(sub, &ptr, "show_on_cage", 0, "", ICON_NONE); } } /* tessellation point for curve-typed objects */ - else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { /* some modifiers could work with pre-tessellated curves only */ - if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) { + if (ELEM(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) { /* add disabled pre-tessellated button, so users could have * message for this modifiers */ but = uiDefIconButBitI(block, TOG, eModifierMode_ApplyOnSpline, 0, ICON_SURFACE_DATA, 0, 0, UI_UNIT_X - 2, UI_UNIT_Y, &md->mode, 0.0, 0.0, 0.0, 0.0, - TIP_("This modifier could be applied on splines' points only")); + TIP_("This modifier can only be applied on splines' points")); uiButSetFlag(but, UI_BUT_DISABLED); } else if (mti->type != eModifierTypeType_Constructive) { @@ -979,7 +968,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob, uiBlockClearButLock(block); uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE); - if (!ELEM5(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem, + if (!ELEM(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem, eModifierType_Cloth, eModifierType_Smoke)) { uiItemO(row, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"), ICON_NONE, @@ -1298,7 +1287,7 @@ void uiTemplatePreview(uiLayout *layout, bContext *C, ID *id, int show_buttons, char _preview_id[UI_MAX_NAME_STR]; - if (id && !ELEM5(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA, ID_LS)) { + if (id && !ELEM(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA, ID_LS)) { RNA_warning("Expected ID of type material, texture, lamp, world or line style"); return; } @@ -1525,7 +1514,15 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand row = uiLayoutRow(split, false); - uiItemR(row, &ptr, "interpolation", 0, "", ICON_NONE); + uiBlockBeginAlign(block); + uiItemR(row, &ptr, "color_mode", 0, "", ICON_NONE); + if (ELEM(coba->color_mode, COLBAND_BLEND_HSV, COLBAND_BLEND_HSL)) { + uiItemR(row, &ptr, "hue_interpolation", 0, "", ICON_NONE); + } + else { /* COLBAND_BLEND_RGB */ + uiItemR(row, &ptr, "interpolation", 0, "", ICON_NONE); + } + uiBlockEndAlign(block); row = uiLayoutRow(layout, false); @@ -1563,7 +1560,7 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand uiDefButS(block, NUM, 0, "", 0, 0, 5.0f * UI_UNIT_X, UI_UNIT_Y, &coba->cur, 0.0, (float)(MAX2(0, coba->tot - 1)), 0, 0, TIP_("Choose active color stop")); row = uiLayoutRow(subsplit, false); - uiItemR(row, &ptr, "position", 0, IFACE_("Pos"), ICON_NONE); + uiItemR(row, &ptr, "position", UI_ITEM_R_SLIDER, IFACE_("Pos"), ICON_NONE); bt = block->buttons.last; uiButSetFunc(bt, colorband_update_cb, bt, coba); @@ -2363,6 +2360,61 @@ void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propna } } +void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname, int UNUSED(colors)) +{ + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); + PointerRNA cptr; + Palette *palette; + PaletteColor *color; + uiBlock *block; + uiLayout *col; + int row_cols = 0, col_id = 0; + int cols_per_row = MAX2(uiLayoutGetWidth(layout) / UI_UNIT_X, 1); + + if (!prop) { + RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); + return; + } + + cptr = RNA_property_pointer_get(ptr, prop); + if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Palette)) + return; + + block = uiLayoutGetBlock(layout); + + palette = cptr.data; + + /* first delete any pending colors */ + BKE_palette_cleanup(palette); + + color = palette->colors.first; + + col = uiLayoutColumn(layout, true); + uiLayoutRow(col, true); + uiDefIconButO(block, BUT, "PALETTE_OT_color_add", WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL); + uiDefIconButO(block, BUT, "PALETTE_OT_color_delete", WM_OP_INVOKE_DEFAULT, ICON_ZOOMOUT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL); + + col = uiLayoutColumn(layout, true); + uiLayoutRow(col, true); + + for (; color; color = color->next) { + PointerRNA ptr; + + if (row_cols >= cols_per_row) { + uiLayoutRow(col, true); + row_cols = 0; + } + + RNA_pointer_create(&palette->id, &RNA_PaletteColor, color, &ptr); + uiDefButR(block, COLOR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, &ptr, "color", -1, 0.0, 1.0, + UI_PALETTE_COLOR, (col_id == palette->active_color) ? UI_PALETTE_COLOR_ACTIVE : 0.0, ""); + + row_cols++; + col_id++; + } +} + + /********************* Layer Buttons Template ************************/ static void handle_layer_buttons(bContext *C, void *arg1, void *arg2) @@ -2593,8 +2645,8 @@ static void uilist_filter_items_default(struct uiList *ui_list, struct bContext 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; + const bool filter_exclude = (ui_list->filter_flag & UILST_FLT_EXCLUDE) != 0; + const 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; @@ -2903,8 +2955,8 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co /* 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; + const int filter_exclude = ui_list->filter_flag & UILST_FLT_EXCLUDE; + const 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; @@ -3188,7 +3240,7 @@ static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2) wmOperatorType *ot = arg2; if (ot) - WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, NULL); } static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items) @@ -3443,13 +3495,9 @@ 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); + const bool is_set = RNA_property_is_set(ptr, prop); uiBut *but; - if (flag & PROP_HIDDEN) - continue; - /* recurse for nested properties */ if (RNA_property_type(prop) == PROP_POINTER) { PointerRNA propptr = RNA_property_pointer_get(ptr, prop); @@ -3543,7 +3591,7 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), P col = uiLayoutColumn(layout, false); row = uiLayoutRow(col, false); - uiItemR(row, &view_transform_ptr, "view_transform", UI_ITEM_R_EXPAND, IFACE_("View"), ICON_NONE); + uiItemR(row, &view_transform_ptr, "view_transform", 0, IFACE_("View"), ICON_NONE); col = uiLayoutColumn(layout, false); uiItemR(col, &view_transform_ptr, "exposure", 0, NULL, ICON_NONE); diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 744ed7e5b72..008ea84b607 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -151,7 +151,7 @@ int uiDefAutoButsRNA(uiLayout *layout, PointerRNA *ptr, const char *name; int tot = 0; - assert(ELEM3(label_align, '\0', 'H', 'V')); + assert(ELEM(label_align, '\0', 'H', 'V')); RNA_STRUCT_BEGIN (ptr, prop) { diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 1a614bc7012..6d497fa474c 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -33,6 +33,7 @@ #include <string.h> #include <assert.h> +#include "DNA_brush_types.h" #include "DNA_screen_types.h" #include "DNA_userdef_types.h" @@ -845,7 +846,7 @@ static void widget_draw_icon(const uiBut *but, BIFIconID icon, float alpha, cons height = ICON_DEFAULT_HEIGHT / aspect; /* calculate blend color */ - if (ELEM4(but->type, TOG, ROW, TOGN, LISTROW)) { + if (ELEM(but->type, TOG, ROW, TOGN, LISTROW)) { if (but->flag & UI_SELECT) {} else if (but->flag & UI_ACTIVE) {} else alpha = 0.5f; @@ -918,45 +919,12 @@ static void ui_text_clip_give_next_off(uiBut *but, const char *str) but->ofs += bytes; } -/** - * Cut off the start of the text to fit into the width of \a rect - * - * \note Sets but->ofs to make sure text is correctly visible. - * \note Clips right in some cases, this function could be cleaned up. - */ -static void ui_text_clip_left(uiFontStyle *fstyle, uiBut *but, const rcti *rect) -{ - /* We are not supposed to use labels with that clipping, so we can always apply margins. */ - const int border = (int)(UI_TEXT_CLIP_MARGIN + 0.5f); - const int okwidth = max_ii(BLI_rcti_size_x(rect) - border, 0); - - /* need to set this first */ - uiStyleFontSet(fstyle); - - if (fstyle->kerning == 1) /* for BLF_width */ - BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - - but->ofs = 0; - but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr, sizeof(but->drawstr)); - - if ((okwidth > 0.0f) && (but->strwidth > okwidth)) { - float strwidth; - but->ofs = BLF_width_to_rstrlen(fstyle->uifont_id, but->drawstr, - sizeof(but->drawstr), okwidth, &strwidth); - but->strwidth = strwidth; - } - - if (fstyle->kerning == 1) { - BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); - } -} - /* Helper. * This func assumes things like kerning handling have already been handled! * Return the length of modified (right-clipped + ellipsis) string. */ static void ui_text_clip_right_ex(uiFontStyle *fstyle, char *str, const size_t max_len, const float okwidth, - const char *sep, const int sep_len, const float sep_strwidth) + const char *sep, const int sep_len, const float sep_strwidth, size_t *r_final_len) { float tmp; int l_end; @@ -969,19 +937,27 @@ static void ui_text_clip_right_ex(uiFontStyle *fstyle, char *str, const size_t m if (sep_strwidth / okwidth > 0.2f) { l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, &tmp); str[l_end] = '\0'; + if (r_final_len) { + *r_final_len = (size_t)l_end; + } } else { l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, &tmp); memcpy(str + l_end, sep, sep_len + 1); /* +1 for trailing '\0'. */ + if (r_final_len) { + *r_final_len = (size_t)(l_end + sep_len); + } } } /** * Cut off the middle of the text to fit into the given width. * Note in case this middle clipping would just remove a few chars, it rather clips right, which is more readable. + * If rpart_sep is not Null, the part of str starting to first occurrence of rpart_sep is preserved at all cost (useful + * for strings with shortcuts, like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O'). */ -static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, const float okwidth, const float minwidth, - const size_t max_len) +static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, float okwidth, const float minwidth, + const size_t max_len, const char *rpart_sep) { float strwidth; @@ -1000,37 +976,76 @@ static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, const float /* utf8 ellipsis '...', some compilers complain */ const char sep[] = {0xe2, 0x80, 0xa6, 0x0}; const int sep_len = sizeof(sep) - 1; + const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1); + float parts_strwidth; size_t l_end; - const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1); - const float parts_strwidth = ((float)okwidth - sep_strwidth) / 2.0f; + char *rpart = NULL, rpart_buf[UI_MAX_DRAW_STR]; + float rpart_width = 0.0f; + size_t rpart_len = 0; + size_t final_lpart_len; + + if (rpart_sep) { + rpart = strstr(str, rpart_sep); + + if (rpart) { + rpart_len = strlen(rpart); + rpart_width = BLF_width(fstyle->uifont_id, rpart, rpart_len); + okwidth -= rpart_width; + strwidth -= rpart_width; + + if (okwidth < 0.0f) { + /* Not enough place for actual label, just display protected right part. + * Here just for safety, should never happen in real life! */ + memmove(str, rpart, rpart_len + 1); + rpart = NULL; + okwidth += rpart_width; + strwidth = rpart_width; + } + } + } + + parts_strwidth = (okwidth - sep_strwidth) / 2.0f; + + if (rpart) { + strcpy(rpart_buf, rpart); + *rpart = '\0'; + rpart = rpart_buf; + } - if (min_ff(parts_strwidth, strwidth - okwidth) < minwidth) { + l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, parts_strwidth, &rpart_width); + if (l_end < 10 || min_ff(parts_strwidth, strwidth - okwidth) < minwidth) { /* If we really have no place, or we would clip a very small piece of string in the middle, * only show start of string. */ - ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth); + ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len); } else { size_t r_offset, r_len; - l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, parts_strwidth, &strwidth); - r_offset = BLF_width_to_rstrlen(fstyle->uifont_id, str, max_len, parts_strwidth, &strwidth); - r_len = strlen(str + r_offset) + 1; /* +1 for the trailing '\0'... */ + r_offset = BLF_width_to_rstrlen(fstyle->uifont_id, str, max_len, parts_strwidth, &rpart_width); + r_len = strlen(str + r_offset) + 1; /* +1 for the trailing '\0'. */ - if (l_end + sep_len + r_len > max_len) { + if (l_end + sep_len + r_len + rpart_len > max_len) { /* Corner case, the str already takes all available mem, and the ellipsis chars would actually * add more chars... * Better to just trim one or two letters to the right in this case... * Note: with a single-char ellipsis, this should never happen! But better be safe here... */ - ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth); + ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len); } else { memmove(str + l_end + sep_len, str + r_offset, r_len); memcpy(str + l_end, sep, sep_len); + final_lpart_len = (size_t)(l_end + sep_len + r_len - 1); /* -1 to remove trailing '\0'! */ } } + + if (rpart) { + /* Add back preserved right part to our shorten str. */ + memcpy(str + final_lpart_len, rpart, rpart_len + 1); /* +1 for trailing '\0'. */ + } + strwidth = BLF_width(fstyle->uifont_id, str, max_len); } @@ -1041,6 +1056,9 @@ static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, const float return strwidth; } +/** + * Wrapper around ui_text_clip_middle_ex. + */ static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rect) { /* No margin for labels! */ @@ -1050,7 +1068,23 @@ static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rec const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f; but->ofs = 0; - but->strwidth = ui_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len); + but->strwidth = ui_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, NULL); +} + +/** + * Like ui_text_clip_middle(), but protect/preserve at all cost the right part of the string after sep. + * Useful for strings with shortcuts (like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O'). + */ +static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, const rcti *rect, const char *rsep) +{ + /* No margin for labels! */ + const int border = ELEM(but->type, LABEL, MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f); + const float okwidth = (float)max_ii(BLI_rcti_size_x(rect) - border, 0); + const size_t max_len = sizeof(but->drawstr); + const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f; + + but->ofs = 0; + but->strwidth = ui_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, rsep); } /** @@ -1427,14 +1461,9 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB else if (ELEM(but->type, NUM, NUMSLI)) { ui_text_clip_right_label(fstyle, but, rect); } -#if 0 - /* Special hack for non-embossed TEX buttons in uiList (we want them to behave as much as possible as labels). */ - else if ((but->type == TEX) && (but->flag & UI_BUT_LIST_ITEM) && (but->dt & UI_EMBOSSN)) { - but->ofs = 0; - } -#endif else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == BUT)) { - ui_text_clip_left(fstyle, but, rect); + /* Clip middle, but protect in all case right part containing the shortcut, if any. */ + ui_text_clip_middle_protect_right(fstyle, but, rect, "|"); } else { ui_text_clip_middle(fstyle, but, rect); @@ -1592,6 +1621,21 @@ static struct uiWidgetColors wcol_menu_back = { 25, -20 }; +/* pie menus */ +static struct uiWidgetColors wcol_pie_menu = { + {10, 10, 10, 200}, + {25, 25, 25, 230}, + {140, 140, 140, 255}, + {45, 45, 45, 230}, + + {160, 160, 160, 255}, + {255, 255, 255, 255}, + + 1, + 10, -10 +}; + + /* tooltip color */ static struct uiWidgetColors wcol_tooltip = { {0, 0, 0, 255}, @@ -1739,6 +1783,7 @@ void ui_widget_color_init(ThemeUI *tui) tui->wcol_menu = wcol_menu; tui->wcol_pulldown = wcol_pulldown; tui->wcol_menu_back = wcol_menu_back; + tui->wcol_pie_menu = wcol_pie_menu; tui->wcol_tooltip = wcol_tooltip; tui->wcol_menu_item = wcol_menu_item; tui->wcol_box = wcol_box; @@ -1887,6 +1932,34 @@ static void widget_state_pulldown(uiWidgetType *wt, int state) copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel); } +/* special case, pie menu items */ +static void widget_state_pie_menu_item(uiWidgetType *wt, int state) +{ + wt->wcol = *(wt->wcol_theme); + + /* active and disabled (not so common) */ + if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) { + widget_state_blend(wt->wcol.text, wt->wcol.text_sel, 0.5f); + /* draw the backdrop at low alpha, helps navigating with keys + * when disabled items are active */ + copy_v4_v4_char(wt->wcol.inner, wt->wcol.item); + wt->wcol.inner[3] = 64; + } + /* regular disabled */ + else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) { + widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f); + } + /* regular active */ + else if (state & UI_SELECT) { + copy_v4_v4_char(wt->wcol.outline, wt->wcol.inner_sel); + copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel); + } + else if (state & UI_ACTIVE) { + copy_v4_v4_char(wt->wcol.inner, wt->wcol.item); + copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel); + } +} + /* special case, menu items */ static void widget_state_menu_item(uiWidgetType *wt, int state) { @@ -2822,6 +2895,17 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat widgetbase_draw(&wtb, wcol); + if (but->a1 == UI_PALETTE_COLOR && but->a2 == UI_PALETTE_COLOR_ACTIVE) { + float width = rect->xmax - rect->xmin; + float height = rect->ymax - rect->ymin; + + glColor4ubv((unsigned char *)wcol->outline); + glBegin(GL_TRIANGLES); + glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.9f * height); + glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.5f * height); + glVertex2f(rect->xmin + 0.5f * width, rect->ymin + 0.9f * height); + glEnd(); + } } static void widget_normal(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign)) @@ -2958,6 +3042,29 @@ static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(sta widgetbase_draw(&wtb, wcol); } +static void widget_menu_radial_itembut(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign)) +{ + uiWidgetBase wtb; + float rad; + float fac = but->block->pie_data.alphafac; + + widget_init(&wtb); + + wtb.emboss = 0; + + rad = 0.5f * BLI_rcti_size_y(rect); + round_box_edges(&wtb, UI_CNR_ALL, rect, rad); + + wcol->inner[3] *= fac; + wcol->inner_sel[3] *= fac; + wcol->item[3] *= fac; + wcol->text[3] *= fac; + wcol->text_sel[3] *= fac; + wcol->outline[3] *= fac; + + widgetbase_draw(&wtb, wcol); +} + static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign)) { uiWidgetBase wtb; @@ -3276,6 +3383,12 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) wt.wcol_theme = &btheme->tui.wcol_progress; wt.custom = widget_progressbar; break; + + case UI_WTYPE_MENU_ITEM_RADIAL: + wt.wcol_theme = &btheme->tui.wcol_pie_menu; + wt.custom = widget_menu_radial_itembut; + wt.state = widget_state_pie_menu_item; + break; } return &wt; @@ -3382,6 +3495,9 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct /* "nothing" */ wt = widget_type(UI_WTYPE_ICON); } + else if (but->dt == UI_EMBOSSR) { + wt = widget_type(UI_WTYPE_MENU_ITEM_RADIAL); + } else { switch (but->type) { @@ -3634,6 +3750,125 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect) } } +static void draw_disk_shaded( + float start, float angle, + float radius_int, float radius_ext, int subd, + const char col1[4], const char col2[4], + bool shaded) +{ + const float radius_ext_scale = (0.5f / radius_ext); /* 1 / (2 * radius_ext) */ + int i; + + float s, c; + float y1, y2; + float fac; + unsigned char r_col[4]; + + glBegin(GL_TRIANGLE_STRIP); + + s = sinf(start); + c = cosf(start); + + y1 = s * radius_int; + y2 = s * radius_ext; + + if (shaded) { + fac = (y1 + radius_ext) * radius_ext_scale; + round_box_shade_col4_r(r_col, col1, col2, fac); + + glColor4ubv(r_col); + } + + glVertex2f(c * radius_int, s * radius_int); + + if (shaded) { + fac = (y2 + radius_ext) * radius_ext_scale; + round_box_shade_col4_r(r_col, col1, col2, fac); + + glColor4ubv(r_col); + } + glVertex2f(c * radius_ext, s * radius_ext); + + for (i = 1; i < subd; i++) { + float a; + + a = start + ((i) / (float)(subd - 1)) * angle; + s = sinf(a); + c = cosf(a); + y1 = s * radius_int; + y2 = s * radius_ext; + + if (shaded) { + fac = (y1 + radius_ext) * radius_ext_scale; + round_box_shade_col4_r(r_col, col1, col2, fac); + + glColor4ubv(r_col); + } + glVertex2f(c * radius_int, s * radius_int); + + if (shaded) { + fac = (y2 + radius_ext) * radius_ext_scale; + round_box_shade_col4_r(r_col, col1, col2, fac); + + glColor4ubv(r_col); + } + glVertex2f(c * radius_ext, s * radius_ext); + } + glEnd(); + +} + +void ui_draw_pie_center(uiBlock *block) +{ + bTheme *btheme = UI_GetTheme(); + float cx = block->pie_data.pie_center_spawned[0]; + float cy = block->pie_data.pie_center_spawned[1]; + + float *pie_dir = block->pie_data.pie_dir; + + float pie_radius_internal = U.pixelsize * U.pie_menu_threshold; + float pie_radius_external = U.pixelsize * (U.pie_menu_threshold + 7.0f); + + int subd = 40; + + float angle = atan2(pie_dir[1], pie_dir[0]); + float range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? ((float)M_PI / 2.0f) : ((float)M_PI / 4.0f); + + glPushMatrix(); + glTranslatef(cx, cy, 0.0f); + + glEnable(GL_BLEND); + if (btheme->tui.wcol_pie_menu.shaded) { + char col1[4], col2[4]; + shadecolors4(col1, col2, btheme->tui.wcol_pie_menu.inner, btheme->tui.wcol_pie_menu.shadetop, btheme->tui.wcol_pie_menu.shadedown); + draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, col1, col2, true); + } + else { + glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.inner); + draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, NULL, NULL, false); + } + + if (!(block->pie_data.flags & UI_PIE_INVALID_DIR)) { + if (btheme->tui.wcol_pie_menu.shaded) { + char col1[4], col2[4]; + shadecolors4(col1, col2, btheme->tui.wcol_pie_menu.inner_sel, btheme->tui.wcol_pie_menu.shadetop, btheme->tui.wcol_pie_menu.shadedown); + draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, col1, col2, true); + } + else { + glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.inner_sel); + draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, NULL, NULL, false); + } + } + + glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.outline); + glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_internal, subd); + glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_external, subd); + + glDisable(GL_BLEND); + glPopMatrix(); +} + + uiWidgetColors *ui_tooltip_get_theme(void) { uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP); @@ -3711,7 +3946,7 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic const float minwidth = (float)(UI_DPI_ICON_SIZE); BLI_strncpy(drawstr, name, sizeof(drawstr)); - ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len); + ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL); glColor4ubv((unsigned char *)wt->wcol.text); uiStyleFontDraw(fstyle, rect, drawstr); @@ -3786,7 +4021,7 @@ void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, const char *name, int const float minwidth = (float)(UI_DPI_ICON_SIZE); BLI_strncpy(drawstr, name, sizeof(drawstr)); - ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len); + ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL); glColor4ubv((unsigned char *)wt->wcol.text); uiStyleFontDraw(fstyle, &trect, drawstr); diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 372ced0a6fd..0879f335c68 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -36,11 +36,10 @@ #include "MEM_guardedalloc.h" #include "DNA_curve_types.h" -#include "DNA_userdef_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" -#include "DNA_mesh_types.h" /* init_userdef_factory */ #include "BLI_blenlib.h" #include "BLI_utildefines.h" @@ -51,7 +50,6 @@ #include "BKE_main.h" #include "BKE_texture.h" - #include "BIF_gl.h" #include "UI_interface.h" @@ -337,6 +335,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo cp = ts->normal; break; case TH_VNORMAL: cp = ts->vertex_normal; break; + case TH_LNORMAL: + cp = ts->loop_normal; break; case TH_BONE_SOLID: cp = ts->bone_solid; break; case TH_BONE_POSE: @@ -537,6 +537,13 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo cp = ts->preview_stitch_active; break; + case TH_PAINT_CURVE_HANDLE: + cp = ts->paint_curve_handle; + break; + case TH_PAINT_CURVE_PIVOT: + cp = ts->paint_curve_pivot; + break; + case TH_UV_OTHERS: cp = ts->uv_others; break; @@ -774,6 +781,8 @@ static void ui_theme_space_init_handles_color(ThemeSpace *theme_space) rgba_char_args_set(theme_space->handle_sel_auto, 0xf0, 0xff, 0x40, 255); rgba_char_args_set(theme_space->handle_sel_vect, 0x40, 0xc0, 0x30, 255); rgba_char_args_set(theme_space->handle_sel_align, 0xf0, 0x90, 0xa0, 255); + rgba_char_args_set(theme_space->handle_vertex, 0x00, 0x00, 0x00, 0xff); + rgba_char_args_set(theme_space->handle_vertex_select, 0xff, 0xff, 0, 0xff); rgba_char_args_set(theme_space->act_spline, 0xdb, 0x25, 0x12, 255); } @@ -859,6 +868,7 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tv3d.face_select, 255, 133, 0, 60); rgba_char_args_set(btheme->tv3d.normal, 0x22, 0xDD, 0xDD, 255); rgba_char_args_set(btheme->tv3d.vertex_normal, 0x23, 0x61, 0xDD, 255); + rgba_char_args_set(btheme->tv3d.loop_normal, 0xDD, 0x23, 0xDD, 255); rgba_char_args_set(btheme->tv3d.face_dot, 255, 133, 0, 255); rgba_char_args_set(btheme->tv3d.editmesh_active, 255, 255, 255, 128); rgba_char_args_set_fl(btheme->tv3d.edge_crease, 0.8, 0, 0.6, 1.0); @@ -871,6 +881,8 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tv3d.title, 0, 0, 0, 255); rgba_char_args_set(btheme->tv3d.freestyle_edge_mark, 0x7f, 0xff, 0x7f, 255); rgba_char_args_set(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51); + rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f); + rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f); btheme->tv3d.facedot_size = 4; @@ -1129,8 +1141,6 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tclip.path_after, 0x00, 0x00, 0xff, 255); rgba_char_args_set(btheme->tclip.grid, 0x5e, 0x5e, 0x5e, 255); rgba_char_args_set(btheme->tclip.cframe, 0x60, 0xc0, 0x40, 255); - rgba_char_args_set(btheme->tclip.handle_vertex, 0x00, 0x00, 0x00, 0xff); - rgba_char_args_set(btheme->tclip.handle_vertex_select, 0xff, 0xff, 0, 0xff); rgba_char_args_set(btheme->tclip.list, 0x66, 0x66, 0x66, 0xff); rgba_char_args_set(btheme->tclip.strip, 0x0c, 0x0a, 0x0a, 0x80); rgba_char_args_set(btheme->tclip.strip_select, 0xff, 0x8c, 0x00, 0xff); @@ -2427,9 +2437,39 @@ void init_userdef_do_versions(void) } } - { + if (U.versionfile < 272 || (U.versionfile == 272 && U.subversionfile < 2)) { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f); + rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f); + rgba_char_args_set_fl(btheme->tima.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f); + rgba_char_args_set_fl(btheme->tima.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f); + } + } + + if (U.versionfile < 271 || (U.versionfile == 271 && U.subversionfile < 5)) { bTheme *btheme; + + struct uiWidgetColors wcol_pie_menu = { + {10, 10, 10, 200}, + {25, 25, 25, 230}, + {140, 140, 140, 255}, + {45, 45, 45, 230}, + + {160, 160, 160, 255}, + {255, 255, 255, 255}, + + 1, + 10, -10 + }; + + U.pie_menu_radius = 100; + U.pie_menu_threshold = 12; + U.pie_animation_timeout = 6; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + btheme->tui.wcol_pie_menu = wcol_pie_menu; + ui_theme_space_init_handles_color(&btheme->tclip); ui_theme_space_init_handles_color(&btheme->tima); btheme->tima.handle_vertex_size = 5; @@ -2437,6 +2477,16 @@ void init_userdef_do_versions(void) } } + if (U.versionfile < 271 || (U.versionfile == 271 && U.subversionfile < 6)) { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + /* check for (alpha == 0) is safe, then color was never set */ + if (btheme->tv3d.loop_normal[3] == 0) { + rgba_char_args_set(btheme->tv3d.loop_normal, 0xDD, 0x23, 0xDD, 255); + } + } + } + if (U.pixelsize == 0.0f) U.pixelsize = 1.0f; @@ -2449,25 +2499,3 @@ void init_userdef_do_versions(void) // XXX reset_autosave(); } - -/** - * Override values in in-memory startup.blend, avoids resaving for small changes. - */ -void init_userdef_factory(void) -{ - /* defaults from T37518 */ - - U.uiflag |= USER_ZBUF_CURSOR; - U.uiflag |= USER_QUIT_PROMPT; - U.uiflag |= USER_CONTINUOUS_MOUSE; - - U.versions = 1; - U.savetime = 2; - - { - Mesh *me; - for (me = G.main->mesh.first; me; me = me->id.next) { - me->flag &= ~ME_TWOSIDED; - } - } -} diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index 45dd47097f5..ccc6f6de94e 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -384,7 +384,7 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_ * - cur must not fall outside of tot * - axis locks (zoom and offset) must be maintained * - zoom must not be excessive (check either sizes or zoom values) - * - aspect ratio should be respected (NOTE: this is quite closely realted to zoom too) + * - aspect ratio should be respected (NOTE: this is quite closely related to zoom too) */ /* Step 1: if keepzoom, adjust the sizes of the rects only diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index e30c6ca61ba..2b84c0678ae 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -767,6 +767,8 @@ static int view_zoomin_invoke(bContext *C, wmOperator *op, const wmEvent *event) static void VIEW2D_OT_zoom_in(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Zoom In"; ot->description = "Zoom in the view"; @@ -778,10 +780,12 @@ static void VIEW2D_OT_zoom_in(wmOperatorType *ot) ot->poll = view_zoom_poll; /* rna - must keep these in sync with the other operators */ - RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX); - RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX); + prop = RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); } - + /* this operator only needs this single callback, where it calls the view_zoom_*() methods */ static int view_zoomout_exec(bContext *C, wmOperator *op) { @@ -828,6 +832,8 @@ static int view_zoomout_invoke(bContext *C, wmOperator *op, const wmEvent *event static void VIEW2D_OT_zoom_out(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Zoom Out"; ot->description = "Zoom out the view"; @@ -839,8 +845,10 @@ static void VIEW2D_OT_zoom_out(wmOperatorType *ot) ot->poll = view_zoom_poll; /* rna - must keep these in sync with the other operators */ - RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX); - RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX); + prop = RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); } /* ********************************************************* */ @@ -1139,6 +1147,7 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event static void VIEW2D_OT_zoom(wmOperatorType *ot) { + PropertyRNA *prop; /* identifiers */ ot->name = "Zoom 2D View"; ot->description = "Zoom in/out the view"; @@ -1156,8 +1165,10 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot) ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER; /* rna - must keep these in sync with the other operators */ - RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX); - RNA_def_float(ot->srna, "deltay", 0, -FLT_MAX, FLT_MAX, "Delta Y", "", -FLT_MAX, FLT_MAX); + prop = RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_float(ot->srna, "deltay", 0, -FLT_MAX, FLT_MAX, "Delta Y", "", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); } /* ********************************************************* */ @@ -1522,6 +1533,7 @@ typedef struct v2dScrollerMove { short zone; /* -1 is min zoomer, 0 is bar, 1 is max zoomer */ // XXX find some way to provide visual feedback of this (active color?) float fac; /* view adjustment factor, based on size of region */ + float fac_round; /* for pixel rounding (avoid visible UI jitter) */ float delta; /* amount moved by mouse on axis of interest */ float scrollbarwidth; /* width of the scrollbar itself, used for page up/down clicks */ @@ -1560,7 +1572,7 @@ enum { */ static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_min, int sh_max) { - short in_min, in_max, in_bar, out_min, out_max, in_view = 1; + bool in_min, in_max, in_bar, out_min, out_max, in_view = 1; /* firstly, check if * - 'bubble' fills entire scroller @@ -1583,9 +1595,9 @@ static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_ /* check if mouse is in or past either handle */ /* TODO: check if these extents are still valid or not */ - in_max = ( (mouse >= (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse <= (sh_max + V2D_SCROLLER_HANDLE_SIZE)) ); - in_min = ( (mouse <= (sh_min + V2D_SCROLLER_HANDLE_SIZE)) && (mouse >= (sh_min - V2D_SCROLLER_HANDLE_SIZE)) ); - in_bar = ( (mouse < (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse > (sh_min + V2D_SCROLLER_HANDLE_SIZE)) ); + in_max = ((mouse >= (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse <= (sh_max + V2D_SCROLLER_HANDLE_SIZE))); + in_min = ((mouse <= (sh_min + V2D_SCROLLER_HANDLE_SIZE)) && (mouse >= (sh_min - V2D_SCROLLER_HANDLE_SIZE))); + in_bar = ((mouse < (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse > (sh_min + V2D_SCROLLER_HANDLE_SIZE))); out_min = mouse < (sh_min - V2D_SCROLLER_HANDLE_SIZE); out_max = mouse > (sh_max + V2D_SCROLLER_HANDLE_SIZE); @@ -1640,7 +1652,10 @@ static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *e /* horizontal scroller - calculate adjustment factor first */ mask_size = (float)BLI_rcti_size_x(&v2d->hor); vsm->fac = BLI_rctf_size_x(&tot_cur_union) / mask_size; - + + /* pixel rounding */ + vsm->fac_round = (BLI_rctf_size_x(&v2d->cur)) / (float)(BLI_rcti_size_x(&ar->winrct) + 1); + /* get 'zone' (i.e. which part of scroller is activated) */ vsm->zone = mouse_in_scroller_handle(event->mval[0], v2d->hor.xmin, v2d->hor.xmax, @@ -1659,6 +1674,9 @@ static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *e mask_size = (float)BLI_rcti_size_y(&v2d->vert); vsm->fac = BLI_rctf_size_y(&tot_cur_union) / mask_size; + /* pixel rounding */ + vsm->fac_round = (BLI_rctf_size_y(&v2d->cur)) / (float)(BLI_rcti_size_y(&ar->winrct) + 1); + /* get 'zone' (i.e. which part of scroller is activated) */ vsm->zone = mouse_in_scroller_handle(event->mval[1], v2d->vert.ymin, v2d->vert.ymax, @@ -1706,6 +1724,9 @@ static void scroller_activate_apply(bContext *C, wmOperator *op) /* calculate amount to move view by */ temp = vsm->fac * vsm->delta; + + /* round to pixel */ + temp = roundf(temp / vsm->fac_round) * vsm->fac_round; /* type of movement */ switch (vsm->zone) { diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index 4d2ea0e64f4..a4130540b1b 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -250,7 +250,7 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr) row = uiLayoutRow(box, false); split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT); - uiItemL(split, IFACE_("Transformation Type"), ICON_NONE); + uiItemL(split, IFACE_("Transformation Type"), ICON_NONE); uiItemR(split, imfptr, "export_transformation_type_selection", 0, "", ICON_NONE); row = uiLayoutRow(box, false); diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index 25888a5fef0..8018d549b09 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -133,9 +133,12 @@ static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float c } static void draw_circle(const float x, const float y, - const float size, const float xscale, const float yscale) + const float size, const bool fill, + const float xscale, const float yscale) { - static GLuint displist = 0; + static GLuint wire_displist = 0; + static GLuint fill_displist = 0; + GLuint displist = fill ? fill_displist : wire_displist; /* Initialize round circle shape. */ if (displist == 0) { @@ -145,11 +148,18 @@ static void draw_circle(const float x, const float y, glNewList(displist, GL_COMPILE); qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); + gluQuadricDrawStyle(qobj, fill ? GLU_FILL : GLU_SILHOUETTE); gluDisk(qobj, 0, 0.7, 8, 1); gluDeleteQuadric(qobj); glEndList(); + + if (fill) { + fill_displist = displist; + } + else { + wire_displist = displist; + } } glPushMatrix(); @@ -219,7 +229,7 @@ static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoin UI_ThemeColor(TH_HANDLE_VERTEX); } - draw_circle(handle_pos[0], handle_pos[1], handle_size, xscale, yscale); + draw_circle(handle_pos[0], handle_pos[1], handle_size, false, xscale, yscale); } /* return non-zero if spline is selected */ @@ -237,6 +247,7 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline int i, handle_size, tot_feather_point; float (*feather_points)[2], (*fp)[2]; + float min[2], max[2]; if (!spline->tot_point) return; @@ -301,6 +312,7 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline } /* control points */ + INIT_MINMAX2(min, max); for (i = 0; i < spline->tot_point; i++) { /* watch it! this is intentionally not the deform array, only check for sel */ @@ -353,6 +365,25 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline glBegin(GL_POINTS); glVertex2fv(vert); glEnd(); + + minmax_v2v2_v2(min, max, vert); + } + + if (is_spline_sel) { + float x = (min[0] + max[0]) / 2.0f; + float y = (min[1] + max[1]) / 2.0f; + /* TODO(sergey): Remove hardcoded colors. */ + if (masklay->act_spline == spline) { + glColor3ub(255, 255, 255); + } + else { + glColor3ub(255, 255, 0); + } + + draw_circle(x, y, 6.0f, true, xscale, yscale); + + glColor3ub(0, 0, 0); + draw_circle(x, y, 6.0f, false, xscale, yscale); } glPointSize(1.0f); @@ -801,13 +832,14 @@ void ED_mask_draw_region(Mask *mask, ARegion *ar, /* apply transformation so mask editing tools will assume drawing from the origin in normalized space */ glPushMatrix(); - glTranslatef(x + xofs, y + yofs, 0); - glScalef(maxdim * zoomx, maxdim * zoomy, 0); if (stabmat) { glMultMatrixf(stabmat); } + glTranslatef(x + xofs, y + yofs, 0); + glScalef(maxdim * zoomx, maxdim * zoomy, 0); + if (do_draw_cb) { ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); } diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index a882284f5e3..9f8388f1fe0 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -458,7 +458,8 @@ enum { SLIDE_ACTION_NONE = 0, SLIDE_ACTION_POINT = 1, SLIDE_ACTION_HANDLE = 2, - SLIDE_ACTION_FEATHER = 3 + SLIDE_ACTION_FEATHER = 3, + SLIDE_ACTION_SPLINE = 4 }; typedef struct SlidePointData { @@ -497,6 +498,96 @@ typedef struct SlidePointData { float weight, weight_scalar; } SlidePointData; +static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float co[2]) +{ + BKE_mask_coord_to_movieclip(sc->clip, &sc->user, r_co, co); + ED_clip_point_undistorted_pos(sc, r_co, r_co); + BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co); +} + +static bool spline_under_mouse_get(const bContext *C, + Mask *mask, const float co[2], + MaskLayer **mask_layer_r, + MaskSpline **mask_spline_r) +{ + ScrArea *sa = CTX_wm_area(C); + SpaceClip *sc = CTX_wm_space_clip(C); + MaskLayer *mask_layer; + int width, height; + float pixel_co[2]; + float closest_dist_squared; + MaskLayer *closest_layer = NULL; + MaskSpline *closest_spline = NULL; + bool undistort = false; + *mask_layer_r = NULL; + *mask_spline_r = NULL; + ED_mask_get_size(sa, &width, &height); + pixel_co[0] = co[0] * width; + pixel_co[1] = co[1] * height; + if (sc != NULL) { + undistort = (sc->clip != NULL) && + (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0; + } + for (mask_layer = mask->masklayers.first; + mask_layer != NULL; + mask_layer = mask_layer->next) + { + MaskSpline *spline; + if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) { + continue; + } + + for (spline = mask_layer->splines.first; + spline != NULL; + spline = spline->next) + { + MaskSplinePoint *points_array; + float min[2], max[2], center[2]; + float dist_squared; + int i; + float max_bb_side; + if ((spline->flag & SELECT) == 0) { + continue; + } + + points_array = BKE_mask_spline_point_array(spline); + INIT_MINMAX2(min, max); + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point_deform = &points_array[i]; + BezTriple *bezt = &point_deform->bezt; + + float vert[2]; + + copy_v2_v2(vert, bezt->vec[1]); + + if (undistort) { + mask_point_undistort_pos(sc, vert, vert); + } + + minmax_v2v2_v2(min, max, vert); + } + + center[0] = (min[0] + max[0]) / 2.0f * width; + center[1] = (min[1] + max[1]) / 2.0f * height; + dist_squared = len_squared_v2v2(pixel_co, center); + max_bb_side = min_ff((max[0] - min[0]) * width, (max[1] - min[1]) * height); + if (dist_squared <= max_bb_side * max_bb_side * 0.5f && + (closest_spline == NULL || dist_squared < closest_dist_squared)) + { + closest_layer = mask_layer; + closest_spline = spline; + closest_dist_squared = dist_squared; + } + } + } + if (closest_spline != NULL) { + *mask_layer_r = closest_layer; + *mask_spline_r = closest_spline; + return true; + } + return false; +} + static bool slide_point_check_initial_feather(MaskSpline *spline) { int i; @@ -607,9 +698,14 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * point = cv_point; } - if (action != SLIDE_ACTION_NONE) { - select_sliding_point(mask, masklay, spline, point, which_handle); + if (action == SLIDE_ACTION_NONE) { + if (spline_under_mouse_get(C, mask, co, &masklay, &spline)) { + action = SLIDE_ACTION_SPLINE; + point = NULL; + } + } + if (action != SLIDE_ACTION_NONE) { customdata = MEM_callocN(sizeof(SlidePointData), "mask slide point data"); customdata->event_invoke_type = event->type; customdata->mask = mask; @@ -621,12 +717,14 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * customdata->action = action; customdata->uw = uw; - customdata->old_h1 = point->bezt.h1; - customdata->old_h2 = point->bezt.h2; - customdata->is_sliding_new_point = RNA_boolean_get(op->ptr, "is_new_point"); - check_sliding_handle_type(point, which_handle); + if (customdata->action != SLIDE_ACTION_SPLINE) { + customdata->old_h1 = point->bezt.h1; + customdata->old_h2 = point->bezt.h2; + select_sliding_point(mask, masklay, spline, point, which_handle); + check_sliding_handle_type(point, which_handle); + } if (uw) { float co_uw[2]; @@ -639,7 +737,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * madd_v2_v2v2fl(customdata->prev_feather_coord, co_uw, customdata->no, uw->w * weight_scalar); } - else { + else if (customdata->action != SLIDE_ACTION_SPLINE) { BezTriple *bezt = &point->bezt; customdata->weight = bezt->weight; @@ -653,10 +751,12 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * customdata->is_initial_feather = slide_point_check_initial_feather(spline); } - copy_m3_m3(customdata->vec, point->bezt.vec); - if (which_handle != MASK_WHICH_HANDLE_NONE) { - BKE_mask_point_handle(point, which_handle, customdata->orig_handle_coord); - copy_v2_v2(customdata->prev_handle_coord, customdata->orig_handle_coord); + if (customdata->action != SLIDE_ACTION_SPLINE) { + copy_m3_m3(customdata->vec, point->bezt.vec); + if (which_handle != MASK_WHICH_HANDLE_NONE) { + BKE_mask_point_handle(point, which_handle, customdata->orig_handle_coord); + copy_v2_v2(customdata->prev_handle_coord, customdata->orig_handle_coord); + } } customdata->which_handle = which_handle; @@ -738,7 +838,7 @@ static void cancel_slide_point(SlidePointData *data) else data->point->bezt.weight = data->weight; } - else { + else if (data->action != SLIDE_ACTION_SPLINE) { copy_m3_m3(data->point->bezt.vec, data->vec); data->point->bezt.h1 = data->old_h1; data->point->bezt.h2 = data->old_h2; @@ -935,6 +1035,20 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event) copy_v2_v2(data->prev_feather_coord, offco); } } + else if (data->action == SLIDE_ACTION_SPLINE) { + int i; + + if (data->orig_spline == NULL) { + data->orig_spline = BKE_mask_spline_copy(data->spline); + } + + for (i = 0; i < data->spline->tot_point; i++) { + MaskSplinePoint *point = &data->spline->points[i]; + add_v2_v2(point->bezt.vec[0], delta); + add_v2_v2(point->bezt.vec[1], delta); + add_v2_v2(point->bezt.vec[2], delta); + } + } WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask); DAG_id_tag_update(&data->mask->id, 0); @@ -970,8 +1084,12 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event) free_slide_point_data(op->customdata); /* keep this last! */ return OPERATOR_FINISHED; } - - break; + else if (event->type != data->event_invoke_type && event->val == KM_PRESS) { + /* pass to ESCKEY */ + } + else { + break; + } case ESCKEY: cancel_slide_point(op->customdata); diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index a5e98b651a3..db20d42f39d 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -46,6 +46,7 @@ set(SRC editmesh_bisect.c editmesh_extrude.c editmesh_inset.c + editmesh_intersect.c editmesh_knife.c editmesh_knife_project.c editmesh_loopcut.c diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index e25919b7400..48d5113a279 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -73,9 +73,9 @@ typedef struct { #define HEADER_LENGTH 180 -static void edbm_bevel_update_header(wmOperator *op, bContext *C) +static void edbm_bevel_update_header(bContext *C, wmOperator *op) { - const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Offset: %s, Segments: %d"); + const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Offset: %s, Segments: %d"); char msg[HEADER_LENGTH]; ScrArea *sa = CTX_wm_area(C); @@ -84,15 +84,19 @@ static void edbm_bevel_update_header(wmOperator *op, bContext *C) if (sa) { BevelData *opdata = op->customdata; char offset_str[NUM_STR_REP_LEN]; + const char *type_str; + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type"); if (hasNumInput(&opdata->num_input)) { - outputNumInput(&opdata->num_input, offset_str, sce->unit.scale_length); + outputNumInput(&opdata->num_input, offset_str, &sce->unit); } else { BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "offset")); } - BLI_snprintf(msg, HEADER_LENGTH, str, offset_str, RNA_int_get(op->ptr, "segments")); + RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &type_str); + + BLI_snprintf(msg, HEADER_LENGTH, str, type_str, offset_str, RNA_int_get(op->ptr, "segments")); ED_area_headerprint(sa, msg); } @@ -146,15 +150,19 @@ static bool edbm_bevel_calc(wmOperator *op) const int segments = RNA_int_get(op->ptr, "segments"); const float profile = RNA_float_get(op->ptr, "profile"); const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); + int material = RNA_int_get(op->ptr, "material"); /* revert to original mesh */ if (opdata->is_modal) { EDBM_redo_state_restore(opdata->mesh_backup, em, false); } + if (em->ob) + material = CLAMPIS(material, -1, em->ob->totcol - 1); + EDBM_op_init(em, &bmop, op, - "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f", - BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile); + "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f material=%i", + BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, material); BMO_op_exec(em->bm, &bmop); @@ -254,7 +262,7 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event) opdata->initial_length = len_v2(mlen); opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; - edbm_bevel_update_header(op, C); + edbm_bevel_update_header(C, op); if (!edbm_bevel_calc(op)) { edbm_bevel_cancel(C, op); @@ -269,44 +277,40 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event) static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event) { BevelData *opdata = op->customdata; - bool use_dist = true; - bool is_percent = false; + bool use_dist; + bool is_percent; float mdiff[2]; float factor; mdiff[0] = opdata->mcenter[0] - event->mval[0]; mdiff[1] = opdata->mcenter[1] - event->mval[1]; is_percent = (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT); + use_dist = !is_percent; - if (use_dist) { - factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size; - } - else { - factor = (len_v2(mdiff) - MVAL_PIXEL_MARGIN) / opdata->initial_length; - factor = factor - 1.0f; /* a different kind of buffer where nothing happens */ - } + factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size; /* Fake shift-transform... */ if (event->shift) { if (opdata->shift_factor < 0.0f) { opdata->shift_factor = RNA_float_get(op->ptr, "offset"); + if (is_percent) { + opdata->shift_factor /= 100.0f; + } } factor = (factor - opdata->shift_factor) * 0.1f + opdata->shift_factor; } - else if (opdata->shift_factor >= 0.0f) + else if (opdata->shift_factor >= 0.0f) { opdata->shift_factor = -1.0f; + } /* clamp differently based on distance/factor */ if (use_dist) { if (factor < 0.0f) factor = 0.0f; } else { + CLAMP(factor, 0.0f, 1.0f); if (is_percent) { factor *= 100.0f; - CLAMP(factor, 0.0f, 100.0f); - } - else { - CLAMP(factor, 0.0f, 1.0f); } } @@ -317,17 +321,16 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) { BevelData *opdata = op->customdata; int segments = RNA_int_get(op->ptr, "segments"); - - if (event->val == KM_PRESS && hasNumInput(&opdata->num_input)) { - /* Modal numinput active, try to handle numeric inputs first... */ - if (handleNumInput(C, &opdata->num_input, event)) { - float value = RNA_float_get(op->ptr, "offset"); - applyNumInput(&opdata->num_input, &value); - RNA_float_set(op->ptr, "offset", value); - edbm_bevel_calc(op); - edbm_bevel_update_header(op, C); - return OPERATOR_RUNNING_MODAL; - } + const bool has_numinput = hasNumInput(&opdata->num_input); + + /* Modal numinput active, try to handle numeric inputs first... */ + if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input, event)) { + float value = RNA_float_get(op->ptr, "offset"); + applyNumInput(&opdata->num_input, &value); + RNA_float_set(op->ptr, "offset", value); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + return OPERATOR_RUNNING_MODAL; } else { bool handled = false; @@ -338,12 +341,12 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; case MOUSEMOVE: - if (!hasNumInput(&opdata->num_input)) { + if (!has_numinput) { const float factor = edbm_bevel_mval_factor(op, event); RNA_float_set(op->ptr, "offset", factor); edbm_bevel_calc(op); - edbm_bevel_update_header(op, C); + edbm_bevel_update_header(C, op); handled = true; } break; @@ -368,7 +371,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) segments++; RNA_int_set(op->ptr, "segments", segments); edbm_bevel_calc(op); - edbm_bevel_update_header(op, C); + edbm_bevel_update_header(C, op); handled = true; break; @@ -380,21 +383,41 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) segments = max_ii(segments - 1, 1); RNA_int_set(op->ptr, "segments", segments); edbm_bevel_calc(op); - edbm_bevel_update_header(op, C); + edbm_bevel_update_header(C, op); handled = true; break; - } - if (!handled && event->val == KM_PRESS) { - /* Modal numinput inactive, try to handle numeric inputs last... */ - if (handleNumInput(C, &opdata->num_input, event)) { - float value = RNA_float_get(op->ptr, "offset"); - applyNumInput(&opdata->num_input, &value); - RNA_float_set(op->ptr, "offset", value); + case MKEY: + if (event->val == KM_RELEASE) + break; + + { + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type"); + int type = RNA_property_enum_get(op->ptr, prop); + type++; + if (type > BEVEL_AMT_PERCENT) { + type = BEVEL_AMT_OFFSET; + } + RNA_property_enum_set(op->ptr, prop, type); + } + /* Update factor accordingly to new offset_type. */ + if (!has_numinput) { + RNA_float_set(op->ptr, "offset", edbm_bevel_mval_factor(op, event)); + } edbm_bevel_calc(op); - edbm_bevel_update_header(op, C); - return OPERATOR_RUNNING_MODAL; - } + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + /* Modal numinput inactive, try to handle numeric inputs last... */ + if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input, event)) { + float value = RNA_float_get(op->ptr, "offset"); + applyNumInput(&opdata->num_input, &value); + RNA_float_set(op->ptr, "offset", value); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + return OPERATOR_RUNNING_MODAL; } } @@ -445,4 +468,5 @@ void MESH_OT_bevel(wmOperatorType *ot) RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8); RNA_def_float(ot->srna, "profile", 0.5f, 0.15f, 1.0f, "Profile", "Controls profile shape (0.5 = round)", 0.15f, 1.0f); RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex only", "Bevel only vertices"); + RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100); } diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 595c43c1060..3e403387a67 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -33,6 +33,7 @@ #include "DNA_object_types.h" #include "BLI_math.h" +#include "BLI_listbase.h" #include "BKE_context.h" #include "BKE_global.h" @@ -65,6 +66,75 @@ static void add_normal_aligned(float nor[3], const float add[3]) } } +static void edbm_extrude_edge_exclude_mirror( + Object *obedit, BMEditMesh *em, + const char hflag, + BMOperator *op, BMOpSlot *slot_edges_exclude) +{ + BMesh *bm = em->bm; + ModifierData *md; + + /* If a mirror modifier with clipping is on, we need to adjust some + * of the cases above to handle edges on the line of symmetry. + */ + for (md = obedit->modifiers.first; md; md = md->next) { + if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) { + MirrorModifierData *mmd = (MirrorModifierData *) md; + + if (mmd->flag & MOD_MIR_CLIPPING) { + BMIter iter; + BMEdge *edge; + + float mtx[4][4]; + if (mmd->mirror_ob) { + float imtx[4][4]; + invert_m4_m4(imtx, mmd->mirror_ob->obmat); + mul_m4_m4m4(mtx, imtx, obedit->obmat); + } + + BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(edge, hflag) && + BM_edge_is_boundary(edge) && + BM_elem_flag_test(edge->l->f, hflag)) + { + float co1[3], co2[3]; + + copy_v3_v3(co1, edge->v1->co); + copy_v3_v3(co2, edge->v2->co); + + if (mmd->mirror_ob) { + mul_v3_m4v3(co1, mtx, co1); + mul_v3_m4v3(co2, mtx, co2); + } + + if (mmd->flag & MOD_MIR_AXIS_X) { + if ((fabsf(co1[0]) < mmd->tolerance) && + (fabsf(co2[0]) < mmd->tolerance)) + { + BMO_slot_map_empty_insert(op, slot_edges_exclude, edge); + } + } + if (mmd->flag & MOD_MIR_AXIS_Y) { + if ((fabsf(co1[1]) < mmd->tolerance) && + (fabsf(co2[1]) < mmd->tolerance)) + { + BMO_slot_map_empty_insert(op, slot_edges_exclude, edge); + } + } + if (mmd->flag & MOD_MIR_AXIS_Z) { + if ((fabsf(co1[2]) < mmd->tolerance) && + (fabsf(co2[2]) < mmd->tolerance)) + { + BMO_slot_map_empty_insert(op, slot_edges_exclude, edge); + } + } + } + } + } + } + } +} + /* individual face extrude */ /* will use vertex normals for extrusion directions, so *nor is unaffected */ static short edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor)) @@ -75,7 +145,10 @@ static short edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const c BMLoop *l; BMOperator bmop; - EDBM_op_init(em, &bmop, op, "extrude_discrete_faces faces=%hf", hflag); + EDBM_op_init( + em, &bmop, op, + "extrude_discrete_faces faces=%hf use_select_history=%b", + hflag, true); /* deselect original verts */ EDBM_flag_disable_all(em, BM_ELEM_SELECT); @@ -101,12 +174,18 @@ static short edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const c /* extrudes individual edges */ static short edbm_extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor)) { + BMesh *bm = em->bm; BMOperator bmop; - EDBM_op_init(em, &bmop, op, "extrude_edge_only edges=%he", hflag); + EDBM_op_init( + em, &bmop, op, + "extrude_edge_only edges=%he use_select_history=%b", + hflag, true); /* deselect original verts */ + BM_SELECT_HISTORY_BACKUP(bm); EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BM_SELECT_HISTORY_RESTORE(bm); BMO_op_exec(em->bm, &bmop); BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true); @@ -123,7 +202,10 @@ static short edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char { BMOperator bmop; - EDBM_op_init(em, &bmop, op, "extrude_vert_indiv verts=%hv", hflag); + EDBM_op_init( + em, &bmop, op, + "extrude_vert_indiv verts=%hv use_select_history=%b", + hflag, true); /* deselect original verts */ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_in, "verts", BM_VERT, BM_ELEM_SELECT, true); @@ -138,82 +220,32 @@ static short edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char return 'g'; /* g is grab */ } -static short edbm_extrude_edge(Object *obedit, BMEditMesh *em, const char hflag, float nor[3]) +static short edbm_extrude_edge_ex( + Object *obedit, BMEditMesh *em, + const char hflag, float nor[3], + const bool use_mirror, + const bool use_select_history) { BMesh *bm = em->bm; - BMIter iter; BMOIter siter; BMOperator extop; - BMEdge *edge; BMFace *f; - ModifierData *md; BMElem *ele; - BMOpSlot *slot_edges_exclude; BMO_op_init(bm, &extop, BMO_FLAG_DEFAULTS, "extrude_face_region"); + BMO_slot_bool_set(extop.slots_in, "use_select_history", use_select_history); BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", BM_VERT | BM_EDGE | BM_FACE, hflag); - slot_edges_exclude = BMO_slot_get(extop.slots_in, "edges_exclude"); + if (use_mirror) { + BMOpSlot *slot_edges_exclude; + slot_edges_exclude = BMO_slot_get(extop.slots_in, "edges_exclude"); - /* If a mirror modifier with clipping is on, we need to adjust some - * of the cases above to handle edges on the line of symmetry. - */ - md = obedit->modifiers.first; - for (; md; md = md->next) { - if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) { - MirrorModifierData *mmd = (MirrorModifierData *) md; - - if (mmd->flag & MOD_MIR_CLIPPING) { - float mtx[4][4]; - if (mmd->mirror_ob) { - float imtx[4][4]; - invert_m4_m4(imtx, mmd->mirror_ob->obmat); - mul_m4_m4m4(mtx, imtx, obedit->obmat); - } - - BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(edge, hflag) && - BM_edge_is_boundary(edge) && - BM_elem_flag_test(edge->l->f, hflag)) - { - float co1[3], co2[3]; - - copy_v3_v3(co1, edge->v1->co); - copy_v3_v3(co2, edge->v2->co); - - if (mmd->mirror_ob) { - mul_v3_m4v3(co1, mtx, co1); - mul_v3_m4v3(co2, mtx, co2); - } - - if (mmd->flag & MOD_MIR_AXIS_X) { - if ((fabsf(co1[0]) < mmd->tolerance) && - (fabsf(co2[0]) < mmd->tolerance)) - { - BMO_slot_map_empty_insert(&extop, slot_edges_exclude, edge); - } - } - if (mmd->flag & MOD_MIR_AXIS_Y) { - if ((fabsf(co1[1]) < mmd->tolerance) && - (fabsf(co2[1]) < mmd->tolerance)) - { - BMO_slot_map_empty_insert(&extop, slot_edges_exclude, edge); - } - } - if (mmd->flag & MOD_MIR_AXIS_Z) { - if ((fabsf(co1[2]) < mmd->tolerance) && - (fabsf(co2[2]) < mmd->tolerance)) - { - BMO_slot_map_empty_insert(&extop, slot_edges_exclude, edge); - } - } - } - } - } - } + edbm_extrude_edge_exclude_mirror(obedit, em, hflag, &extop, slot_edges_exclude); } + BM_SELECT_HISTORY_BACKUP(bm); EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BM_SELECT_HISTORY_RESTORE(bm); BMO_op_exec(bm, &extop); @@ -236,6 +268,13 @@ static short edbm_extrude_edge(Object *obedit, BMEditMesh *em, const char hflag, return is_zero_v3(nor) ? 'g' : 'n'; } +static short edbm_extrude_edge( + Object *obedit, BMEditMesh *em, + const char hflag, float nor[3]) +{ + return edbm_extrude_edge_ex(obedit, em, hflag, nor, true, true); +} + static short edbm_extrude_vert(Object *obedit, BMEditMesh *em, const char hflag, float nor[3]) { BMIter iter; @@ -288,13 +327,12 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) mul_m3_v3(tmat, dvec); for (a = 0; a < steps; a++) { - edbm_extrude_edge(obedit, em, BM_ELEM_SELECT, nor); - //BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS, "extrude_face_region geom=%hef", BM_ELEM_SELECT); - BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS, - "translate vec=%v verts=%hv", - dvec, BM_ELEM_SELECT); - //extrudeflag(obedit, em, SELECT, nor); - //translateflag(em, SELECT, dvec); + edbm_extrude_edge_ex(obedit, em, BM_ELEM_SELECT, nor, false, false); + + BMO_op_callf( + em->bm, BMO_FLAG_DEFAULTS, + "translate vec=%v verts=%hv", + dvec, BM_ELEM_SELECT); } EDBM_mesh_normals_update(em); diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index dc40330b309..a4942d01671 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -90,7 +90,7 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C) if (sa) { char flts_str[NUM_STR_REP_LEN * 2]; if (hasNumInput(&opdata->num_input)) - outputNumInput(&opdata->num_input, flts_str, sce->unit.scale_length); + outputNumInput(&opdata->num_input, flts_str, &sce->unit); else { BLI_snprintf(flts_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "thickness")); BLI_snprintf(flts_str + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "depth")); @@ -297,25 +297,24 @@ static int edbm_inset_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event) { InsetData *opdata = op->customdata; - - if (event->val == KM_PRESS && hasNumInput(&opdata->num_input)) { - /* Modal numinput active, try to handle numeric inputs first... */ - if (handleNumInput(C, &opdata->num_input, event)) { - float amounts[2] = {RNA_float_get(op->ptr, "thickness"), - RNA_float_get(op->ptr, "depth")}; - applyNumInput(&opdata->num_input, amounts); - amounts[0] = max_ff(amounts[0], 0.0f); - RNA_float_set(op->ptr, "thickness", amounts[0]); - RNA_float_set(op->ptr, "depth", amounts[1]); - - if (edbm_inset_calc(op)) { - edbm_inset_update_header(op, C); - return OPERATOR_RUNNING_MODAL; - } - else { - edbm_inset_cancel(C, op); - return OPERATOR_CANCELLED; - } + const bool has_numinput = hasNumInput(&opdata->num_input); + + /* Modal numinput active, try to handle numeric inputs first... */ + if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input, event)) { + float amounts[2] = {RNA_float_get(op->ptr, "thickness"), + RNA_float_get(op->ptr, "depth")}; + applyNumInput(&opdata->num_input, amounts); + amounts[0] = max_ff(amounts[0], 0.0f); + RNA_float_set(op->ptr, "thickness", amounts[0]); + RNA_float_set(op->ptr, "depth", amounts[1]); + + if (edbm_inset_calc(op)) { + edbm_inset_update_header(op, C); + return OPERATOR_RUNNING_MODAL; + } + else { + edbm_inset_cancel(C, op); + return OPERATOR_CANCELLED; } } else { @@ -327,7 +326,7 @@ static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; case MOUSEMOVE: - if (!hasNumInput(&opdata->num_input)) { + if (!has_numinput) { float mdiff[2]; float amount; @@ -455,24 +454,22 @@ static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } - if (!handled && event->val == KM_PRESS) { - /* Modal numinput inactive, try to handle numeric inputs last... */ - if (handleNumInput(C, &opdata->num_input, event)) { - float amounts[2] = {RNA_float_get(op->ptr, "thickness"), - RNA_float_get(op->ptr, "depth")}; - applyNumInput(&opdata->num_input, amounts); - amounts[0] = max_ff(amounts[0], 0.0f); - RNA_float_set(op->ptr, "thickness", amounts[0]); - RNA_float_set(op->ptr, "depth", amounts[1]); - - if (edbm_inset_calc(op)) { - edbm_inset_update_header(op, C); - return OPERATOR_RUNNING_MODAL; - } - else { - edbm_inset_cancel(C, op); - return OPERATOR_CANCELLED; - } + /* Modal numinput inactive, try to handle numeric inputs last... */ + if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input, event)) { + float amounts[2] = {RNA_float_get(op->ptr, "thickness"), + RNA_float_get(op->ptr, "depth")}; + applyNumInput(&opdata->num_input, amounts); + amounts[0] = max_ff(amounts[0], 0.0f); + RNA_float_set(op->ptr, "thickness", amounts[0]); + RNA_float_set(op->ptr, "depth", amounts[1]); + + if (edbm_inset_calc(op)) { + edbm_inset_update_header(op, C); + return OPERATOR_RUNNING_MODAL; + } + else { + edbm_inset_cancel(C, op); + return OPERATOR_CANCELLED; } } } diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c new file mode 100644 index 00000000000..df6776950d7 --- /dev/null +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -0,0 +1,400 @@ +/* + * ***** 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/editors/mesh/editmesh_intersect.c + * \ingroup edmesh + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_object_types.h" + +#include "BLI_math.h" +#include "BLI_array.h" +#include "BLI_linklist_stack.h" + + +#include "BKE_context.h" +#include "BKE_report.h" +#include "BKE_editmesh.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_screen.h" + +#include "intern/bmesh_private.h" + +#include "mesh_intern.h" /* own include */ + +#include "tools/bmesh_intersect.h" + + +/* -------------------------------------------------------------------- */ +/* Cut intersections into geometry */ + +/** + * Compare selected with its self. + */ +static int bm_face_isect_self(BMFace *f, void *UNUSED(user_data)) +{ + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + return 0; + } + else { + return -1; + } +} + +/** + * Compare selected/unselected. + */ +static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data)) +{ + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + return -1; + } + else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + return 0; + } + else { + return 1; + } +} + +enum { + ISECT_SEL = 0, + ISECT_SEL_UNSEL = 1, +}; + +static EnumPropertyItem isect_mode_items[] = { + {ISECT_SEL, "SELECT", 0, "Self Intersect", + "Self intersect selected faces"}, + {ISECT_SEL_UNSEL, "SELECT_UNSELECT", 0, "Selected/Unselected", + "Intersect selected with unselected faces"}, + {0, NULL, 0, NULL, NULL} +}; + +static int edbm_intersect_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + const int mode = RNA_enum_get(op->ptr, "mode"); + int (*test_fn)(BMFace *, void *); + bool use_separate = RNA_boolean_get(op->ptr, "use_separate"); + const float eps = RNA_float_get(op->ptr, "threshold"); + bool use_self; + bool has_isect; + + switch (mode) { + case ISECT_SEL: + test_fn = bm_face_isect_self; + use_self = true; + break; + default: /* ISECT_SEL_UNSEL */ + test_fn = bm_face_isect_pair; + use_self = false; + break; + } + + + has_isect = BM_mesh_intersect( + bm, + em->looptris, em->tottri, + test_fn, NULL, + use_self, use_separate, + eps); + + + if (has_isect) { + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + + if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { + BMIter iter; + BMEdge *e; + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + BM_edge_select_set(bm, e, true); + } + } + } + + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + } + else { + BKE_report(op->reports, RPT_WARNING, "No intersections found"); + } + + return OPERATOR_FINISHED; +} + +void MESH_OT_intersect(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Intersect"; + ot->description = "Cut an intersection into faces"; + ot->idname = "MESH_OT_intersect"; + + /* api callbacks */ + ot->exec = edbm_intersect_exec; + ot->poll = ED_operator_editmesh; + + /* props */ + RNA_def_enum(ot->srna, "mode", isect_mode_items, ISECT_SEL_UNSEL, "Source", ""); + RNA_def_boolean(ot->srna, "use_separate", true, "Separate", ""); + RNA_def_float(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001); + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + +/* -------------------------------------------------------------------- */ +/* Face Split by Edges */ + + +/** \name Face/Edge Split + * \{ */ + +static void bm_face_split_by_edges(BMesh *bm, BMFace *f, const char hflag) +{ + BMEdge **edge_net = NULL; + BLI_array_declare(edge_net); + + const int f_index = BM_elem_index_get(f); + + BMLoop *l_iter; + BMLoop *l_first; + BMVert *v; + + BMFace **face_arr; + int face_arr_len; + + /* likely this will stay very small + * all verts pushed into this stack _must_ have their previous edges set! */ + BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *); + BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *); + + + /* collect all edges */ + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BMIter iter; + BMEdge *e; + + BM_ITER_ELEM (e, &iter, l_iter->v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e, hflag) && + (BM_elem_index_get(e) == f_index)) + { + v = BM_edge_other_vert(e, l_iter->v); + v->e = e; + + BLI_SMALLSTACK_PUSH(vert_stack, v); + BLI_array_append(edge_net, e); + } + } + } while ((l_iter = l_iter->next) != l_first); + + + + /* now assign all */ + /* pop free values into the next stack */ + while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) { + BMIter eiter; + BMEdge *e_next; + + BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e_next, hflag) && + (BM_elem_index_get(e_next) == -1)) + { + BMVert *v_next; + v_next = BM_edge_other_vert(e_next, v); + BM_elem_index_set(e_next, f_index); + BLI_SMALLSTACK_PUSH(vert_stack_next, v_next); + BLI_array_append(edge_net, e_next); + } + } + + if (BLI_SMALLSTACK_IS_EMPTY(vert_stack)) { + BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next); + } + } + + BM_face_split_edgenet(bm, f, edge_net, BLI_array_count(edge_net), &face_arr, &face_arr_len); + BLI_array_free(edge_net); + + if (face_arr_len) { + int i; + for (i = 0; i < face_arr_len; i++) { + BM_face_select_set(bm, face_arr[i], true); + BM_elem_flag_disable(face_arr[i], hflag); + } + } + + if (face_arr) { + MEM_freeN(face_arr); + } +} + +static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + const char hflag = BM_ELEM_TAG; + + BMVert *v; + BMEdge *e; + BMFace *f; + BMIter iter; + + BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *); + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + BM_elem_flag_disable(v, hflag); + } + + /* edge index is set to -1 then used to assosiate them with faces */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) { + BM_elem_flag_enable(e, hflag); + + BM_elem_flag_enable(e->v1, hflag); + BM_elem_flag_enable(e->v2, hflag); + + } + else { + BM_elem_flag_disable(e, hflag); + } + BM_elem_index_set(e, -1); /* set_dirty */ + } + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_elem_flag_enable(f, hflag); + } + else { + BM_elem_flag_disable(f, hflag); + } + } + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, hflag)) { + BMIter viter; + BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { + BMIter liter; + BMLoop *l; + + unsigned int loop_stack_len; + BMLoop *l_best = NULL; + + BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack)); + loop_stack_len = 0; + + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + if (BM_elem_flag_test(l->f, hflag)) { + BLI_SMALLSTACK_PUSH(loop_stack, l); + loop_stack_len++; + } + } + + if (loop_stack_len == 0) { + /* pass */ + } + else if (loop_stack_len == 1) { + l_best = BLI_SMALLSTACK_POP(loop_stack); + } + else { + /* complicated case, match the edge with a face-loop */ + + BMVert *v_other = BM_edge_other_vert(e, v); + float e_dir[3]; + + /* we wan't closest to zero */ + float dot_best = FLT_MAX; + + sub_v3_v3v3(e_dir, v_other->co, v->co); + normalize_v3(e_dir); + + while ((l = BLI_SMALLSTACK_POP(loop_stack))) { + float dot_test; + + /* Check dot first to save on expensive angle-comparison. + * ideal case is 90d difference == 0.0 dot */ + dot_test = fabsf(dot_v3v3(e_dir, l->f->no)); + if (dot_test < dot_best) { + + /* check we're in the correct corner (works with convex loops too) */ + if (angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, v_other->co, l->f->no) < + angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, l->next->v->co, l->f->no)) + { + dot_best = dot_test; + l_best = l; + } + } + } + } + + if (l_best) { + BM_elem_index_set(e, BM_elem_index_get(l_best->f)); /* set_dirty */ + } + } + } + } + + bm->elem_index_dirty |= BM_EDGE; + + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, hflag)) { + bm_face_split_by_edges(bm, f, hflag); + } + } + + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + + return OPERATOR_FINISHED; +} + + +void MESH_OT_face_split_by_edges(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Split by Edges"; + ot->description = "Split faces by loose edges"; + ot->idname = "MESH_OT_face_split_by_edges"; + + /* api callbacks */ + ot->exec = edbm_face_split_by_edges_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 3dc0c85699a..4828fa02d42 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -27,6 +27,8 @@ /** \file blender/editors/mesh/editmesh_knife.c * \ingroup edmesh + * + * Interactive editmesh knife tool. */ #ifdef _MSC_VER @@ -71,13 +73,12 @@ #include "mesh_intern.h" /* own include */ -/* this code here is kindof messy. . .I might need to eventually rework it - joeedh */ - #define KMAXDIST 10 /* max mouse distance from edge before not detecting it */ #define KNIFE_FLT_EPS 0.00001f #define KNIFE_FLT_EPS_SQUARED (KNIFE_FLT_EPS * KNIFE_FLT_EPS) #define KNIFE_FLT_EPSBIG 0.0005f +#define KNIFE_FLT_EPS_PX 0.2f typedef struct KnifeColors { unsigned char line[3]; @@ -115,7 +116,7 @@ typedef struct KnifeEdge { typedef struct KnifeLineHit { float hit[3], cagehit[3]; - float schit[2]; + float schit[2]; /* screen coordinates for cagehit */ float l; /* lambda along cut line */ float perc; /* lambda along hit line */ float m; /* depth front-to-back */ @@ -343,7 +344,7 @@ static KnifeVert *new_knife_vert(KnifeTool_OpData *kcd, const float co[3], const copy_v3_v3(kfv->co, co); copy_v3_v3(kfv->cageco, cageco); - knife_project_v2(kcd, kfv->co, kfv->sco); + knife_project_v2(kcd, kfv->cageco, kfv->sco); return kfv; } @@ -486,21 +487,14 @@ static void knife_edge_append_face(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMFace knife_append_list(kcd, &kfe->faces, f); } -static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd, KnifeEdge *kfe, float co[3], KnifeEdge **newkfe_out) +static KnifeVert *knife_split_edge( + KnifeTool_OpData *kcd, KnifeEdge *kfe, + const float co[3], const float cageco[3], + KnifeEdge **r_kfe) { KnifeEdge *newkfe = new_knife_edge(kcd); Ref *ref; BMFace *f; - float perc, cageco[3], l12; - - l12 = len_v3v3(kfe->v1->co, kfe->v2->co); - if (l12 < KNIFE_FLT_EPS) { - copy_v3_v3(cageco, kfe->v1->cageco); - } - else { - perc = len_v3v3(co, kfe->v1->co) / l12; - interp_v3_v3v3(cageco, kfe->v1->cageco, kfe->v2->cageco, perc); - } newkfe->v1 = kfe->v1; newkfe->v2 = new_knife_vert(kcd, co, cageco); @@ -532,7 +526,7 @@ static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd, KnifeEdge *kfe, float newkfe->draw = kfe->draw; newkfe->e = kfe->e; - *newkfe_out = newkfe; + *r_kfe = newkfe; return newkfe->v2; } @@ -670,7 +664,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife kfe->v1 = lh1->v; } else if (lh1->kfe) { - kfe->v1 = knife_split_edge(kcd, lh1->kfe, lh1->cagehit, &kfe2); + kfe->v1 = knife_split_edge(kcd, lh1->kfe, lh1->hit, lh1->cagehit, &kfe2); lh1->v = kfe->v1; /* record the KnifeVert for this hit */ } else { @@ -686,7 +680,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife kfe->v2 = lh2->v; } else if (lh2->kfe) { - kfe->v2 = knife_split_edge(kcd, lh2->kfe, lh2->cagehit, &kfe2); + kfe->v2 = knife_split_edge(kcd, lh2->kfe, lh2->hit, lh2->cagehit, &kfe2); lh2->v = kfe->v2; /* future uses of lh2 won't split again */ } else { @@ -1070,21 +1064,22 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) if (v3d->zbuf) glEnable(GL_DEPTH_TEST); } -/* Find intersection of v1-v2 with face f. - * Only take intersections that are at least face_tol (in screen space) away +/** + * Find intersection of v1-v2 with face f. + * Only take intersections that are at least \a face_tol_sq (in screen space) away * from other intersection elements. * If v1-v2 is coplanar with f, call that "no intersection though * it really means "infinite number of intersections". - * In such a case we should have gotten hits on edges or verts of the face. */ -static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, - const float s[2], - const float v1[3], const float v2[3], - BMFace *f, - const float face_tol, - float intersectp[3]) + * In such a case we should have gotten hits on edges or verts of the face. + */ +static bool knife_ray_intersect_face( + KnifeTool_OpData *kcd, + const float s[2], const float v1[3], const float v2[3], + BMFace *f, const float face_tol_sq, + float hit_co[3], float hit_cageco[3]) { int tottri, tri_i; - float lv1[3], lv2[3], lv3[3], raydir[3]; + float raydir[3]; float tri_norm[3], tri_plane[4]; float se1[2], se2[2]; float d, lambda; @@ -1100,12 +1095,14 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, BLI_assert(tri_i >= 0 && tri_i < tottri); for (; tri_i < tottri; tri_i++) { + const float *lv1, *lv2, *lv3; + tri = kcd->em->looptris[tri_i]; if (tri[0]->f != f) break; - copy_v3_v3(lv1, kcd->cagecos[BM_elem_index_get(tri[0]->v)]); - copy_v3_v3(lv2, kcd->cagecos[BM_elem_index_get(tri[1]->v)]); - copy_v3_v3(lv3, kcd->cagecos[BM_elem_index_get(tri[2]->v)]); + lv1 = kcd->cagecos[BM_elem_index_get(tri[0]->v)]; + lv2 = kcd->cagecos[BM_elem_index_get(tri[1]->v)]; + lv3 = kcd->cagecos[BM_elem_index_get(tri[2]->v)]; /* using epsilon test in case ray is directly through an internal * tesselation edge and might not hit either tesselation tri with * an exact test; @@ -1114,24 +1111,29 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, /* check if line coplanar with tri */ normal_tri_v3(tri_norm, lv1, lv2, lv3); plane_from_point_normal_v3(tri_plane, lv1, tri_norm); - if ((fabsf(dist_squared_to_plane_v3(v1, tri_plane)) < KNIFE_FLT_EPS) && - (fabsf(dist_squared_to_plane_v3(v2, tri_plane)) < KNIFE_FLT_EPS)) + if ((dist_squared_to_plane_v3(v1, tri_plane) < KNIFE_FLT_EPS) && + (dist_squared_to_plane_v3(v2, tri_plane) < KNIFE_FLT_EPS)) { return false; } - copy_v3_v3(intersectp, v1); - madd_v3_v3fl(intersectp, raydir, lambda); + copy_v3_v3(hit_cageco, v1); + madd_v3_v3fl(hit_cageco, raydir, lambda); /* Now check that far enough away from verts and edges */ lst = knife_get_face_kedges(kcd, f); for (ref = lst->first; ref; ref = ref->next) { kfe = ref->ref; knife_project_v2(kcd, kfe->v1->cageco, se1); knife_project_v2(kcd, kfe->v2->cageco, se2); - d = dist_to_line_segment_v2(s, se1, se2); - if (d < face_tol) { + d = dist_squared_to_line_segment_v2(s, se1, se2); + if (d < face_tol_sq) { return false; } } + + transform_point_by_tri_v3( + hit_co, hit_cageco, + tri[0]->v->co, tri[1]->v->co, tri[2]->v->co, + lv1, lv2, lv3); return true; } } @@ -1221,16 +1223,7 @@ static void clip_to_ortho_planes(float v1[3], float v2[3], float d) static void set_linehit_depth(KnifeTool_OpData *kcd, KnifeLineHit *lh) { - float vnear[3], vfar[3]; - - ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, lh->schit, vnear, vfar, true); - mul_m4_v3(kcd->ob->imat, vnear); - if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) { - if (kcd->ortho_extent == 0.0f) - calc_ortho_extent(kcd); - clip_to_ortho_planes(vnear, vfar, kcd->ortho_extent + 10.0f); - } - lh->m = len_v3v3(vnear, lh->cagehit); + lh->m = dot_m4_v3_row_z(kcd->vc.rv3d->persmatob, lh->cagehit); } /* Finds visible (or all, if cutting through) edges that intersects the current screen drag line */ @@ -1254,9 +1247,12 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) void *val; float plane_cos[12]; float s[2], se1[2], se2[2], sint[2]; - float p[3], p2[3], r1[3], r2[3]; + float r1[3], r2[3]; float d, d1, d2, lambda; - float vert_tol, vert_tol_sq, line_tol, face_tol; + float vert_tol, vert_tol_sq; + float line_tol, line_tol_sq; + float face_tol, face_tol_sq; + float eps_scale; int isect_kind; unsigned int tot; int i; @@ -1359,10 +1355,22 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) /* Now go through the candidates and find intersections */ /* These tolerances, in screen space, are for intermediate hits, as ends are already snapped to screen */ - vert_tol = KNIFE_FLT_EPS * 2000.0f; - line_tol = KNIFE_FLT_EPS * 2000.0f; - vert_tol_sq = vert_tol * vert_tol; + { + /* Scale the epsilon by the zoom level + * to compensate for projection imprecision, see T41164 */ + float zoom_xy[2] = {kcd->vc.rv3d->winmat[0][0], + kcd->vc.rv3d->winmat[1][1]}; + eps_scale = len_v2(zoom_xy); + } + + vert_tol = KNIFE_FLT_EPS_PX * eps_scale; + line_tol = KNIFE_FLT_EPS_PX * eps_scale; face_tol = max_ff(vert_tol, line_tol); + + vert_tol_sq = vert_tol * vert_tol; + line_tol_sq = line_tol * line_tol; + face_tol_sq = face_tol * face_tol; + /* Assume these tolerances swamp floating point rounding errors in calculations below */ /* first look for vertex hits */ @@ -1375,7 +1383,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) if (point_is_visible(kcd, v->cageco, s, &mats)) { memset(&hit, 0, sizeof(hit)); hit.v = v; - copy_v3_v3(hit.hit, v->cageco); + copy_v3_v3(hit.hit, v->co); copy_v3_v3(hit.cagehit, v->cageco); copy_v2_v2(hit.schit, s); set_linehit_depth(kcd, &hit); @@ -1393,35 +1401,39 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) if (isect_kind == -1) { /* isect_seg_seg_v2 doesn't do tolerance test around ends of s1-s2 */ closest_to_line_segment_v2(sint, s1, se1, se2); - if (len_squared_v2v2(sint, s1) <= vert_tol_sq) + if (len_squared_v2v2(sint, s1) <= line_tol_sq) isect_kind = 1; else { closest_to_line_segment_v2(sint, s2, se1, se2); - if (len_squared_v2v2(sint, s2) <= vert_tol_sq) + if (len_squared_v2v2(sint, s2) <= line_tol_sq) isect_kind = 1; } } if (isect_kind == 1) { d1 = len_v2v2(sint, se1); d2 = len_v2v2(se2, se1); - if (!(d1 <= vert_tol || d2 <= vert_tol || fabsf(d1 - d2) <= vert_tol)) { + if (!(d1 <= line_tol || d2 <= line_tol || fabsf(d1 - d2) <= line_tol)) { + float p_cage[3], p_cage_tmp[3]; lambda = d1 / d2; /* Can't just interpolate between ends of kfe because * that doesn't work with perspective transformation. * Need to find 3d intersection of ray through sint */ knife_input_ray_segment(kcd, sint, 1.0f, r1, r2); - isect_kind = isect_line_line_v3(kfe->v1->cageco, kfe->v2->cageco, r1, r2, p, p2); - if (isect_kind >= 1 && point_is_visible(kcd, p, sint, &mats)) { + isect_kind = isect_line_line_v3(kfe->v1->cageco, kfe->v2->cageco, r1, r2, p_cage, p_cage_tmp); + if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, &mats)) { memset(&hit, 0, sizeof(hit)); if (kcd->snap_midpoints) { /* choose intermediate point snap too */ - mid_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco); + mid_v3_v3v3(p_cage, kfe->v1->cageco, kfe->v2->cageco); mid_v2_v2v2(sint, se1, se2); lambda = 0.5f; } hit.kfe = kfe; - copy_v3_v3(hit.hit, p); - copy_v3_v3(hit.cagehit, p); + transform_point_by_seg_v3( + hit.hit, p_cage, + kfe->v1->co, kfe->v2->co, + kfe->v1->cageco, kfe->v2->cageco); + copy_v3_v3(hit.cagehit, p_cage); copy_v2_v2(hit.schit, sint); hit.perc = lambda; set_linehit_depth(kcd, &hit); @@ -1434,23 +1446,25 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) for (val = BLI_smallhash_iternew(&faces, &hiter, (uintptr_t *)&f); val; val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) { - if (knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol, p)) { - if (point_is_visible(kcd, p, s1, &mats)) { + float p[3], p_cage[3]; + + if (knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol_sq, p, p_cage)) { + if (point_is_visible(kcd, p_cage, s1, &mats)) { memset(&hit, 0, sizeof(hit)); hit.f = f; copy_v3_v3(hit.hit, p); - copy_v3_v3(hit.cagehit, p); + copy_v3_v3(hit.cagehit, p_cage); copy_v2_v2(hit.schit, s1); set_linehit_depth(kcd, &hit); BLI_array_append(linehits, hit); } } - if (knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol, p)) { - if (point_is_visible(kcd, p, s2, &mats)) { + if (knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol_sq, p, p_cage)) { + if (point_is_visible(kcd, p_cage, s2, &mats)) { memset(&hit, 0, sizeof(hit)); hit.f = f; copy_v3_v3(hit.hit, p); - copy_v3_v3(hit.cagehit, p); + copy_v3_v3(hit.cagehit, p_cage); copy_v2_v2(hit.schit, s2); set_linehit_depth(kcd, &hit); BLI_array_append(linehits, hit); @@ -1858,7 +1872,7 @@ static int knife_update_active(KnifeTool_OpData *kcd) copy_v2_v2(kcd->curr.mval, kcd->mval); /* view matrix may have changed, reproject */ - knife_project_v2(kcd, kcd->prev.co, kcd->prev.mval); + knife_project_v2(kcd, kcd->prev.cage, kcd->prev.mval); if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING) { kcd->is_angle_snapping = knife_snap_angle(kcd); @@ -2252,31 +2266,28 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f) { - BMLoop *l1, *l2, *l; - float mid[3]; - BMIter iter; - int v1inside, v2inside; + bool v1_inside, v2_inside; + bool v1_inface, v2_inface; if (!f || !v1 || !v2) return false; - l1 = NULL; - l2 = NULL; - /* find out if v1 and v2, if set, are part of the face */ - BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { - if (v1->v && l->v == v1->v) - l1 = l; - if (v2->v && l->v == v2->v) - l2 = l; - } + v1_inface = v1->v ? BM_vert_in_face(f, v1->v) : false; + v2_inface = v2->v ? BM_vert_in_face(f, v2->v) : false; /* BM_face_point_inside_test uses best-axis projection so this isn't most accurate test... */ - v1inside = l1 ? 0 : BM_face_point_inside_test(f, v1->co); - v2inside = l2 ? 0 : BM_face_point_inside_test(f, v2->co); - if ((l1 && v2inside) || (l2 && v1inside) || (v1inside && v2inside)) + v1_inside = v1_inface ? false : BM_face_point_inside_test(f, v1->co); + v2_inside = v2_inface ? false : BM_face_point_inside_test(f, v2->co); + if ((v1_inface && v2_inside) || + (v2_inface && v1_inside) || + (v1_inside && v2_inside)) + { return true; - if (l1 && l2) { + } + + if (v1_inface && v2_inface) { + float mid[3]; /* Can have case where v1 and v2 are on shared chain between two faces. * BM_face_splits_check_legal does visibility and self-intersection tests, * but it is expensive and maybe a bit buggy, so use a simple @@ -2375,12 +2386,12 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe KnifeEdge *kfe; BMFace *fnew, *fnew2, *fhole; ListBase *chain, *hole, *sidechain; - ListBase *fnew_kfedges, *fnew2_kfedges; Ref *ref, *refnext; int count, oldcount; oldcount = BLI_countlist(kfedges); while ((chain = find_chain(kcd, kfedges)) != NULL) { + ListBase fnew_kfedges; knife_make_chain_cut(kcd, f, chain, &fnew); if (!fnew) { return; @@ -2388,18 +2399,22 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe /* Move kfedges to fnew_kfedges if they are now in fnew. * The chain edges were removed already */ - fnew_kfedges = knife_empty_list(kcd); + BLI_listbase_clear(&fnew_kfedges); for (ref = kfedges->first; ref; ref = refnext) { kfe = ref->ref; refnext = ref->next; if (knife_edge_in_face(kfe, fnew)) { BLI_remlink(kfedges, ref); kfe->basef = fnew; - knife_append_list(kcd, fnew_kfedges, kfe); + BLI_addtail(&fnew_kfedges, ref); + } + else if (!knife_edge_in_face(kfe, f)) { + /* Concave ngon's - this edge might not be in either faces, T41730 */ + BLI_remlink(kfedges, ref); } } - if (fnew_kfedges->first) - knife_make_face_cuts(kcd, fnew, fnew_kfedges); + if (fnew_kfedges.first) + knife_make_face_cuts(kcd, fnew, &fnew_kfedges); /* find_chain should always remove edges if it returns true, * but guard against infinite loop anyway */ @@ -2413,6 +2428,8 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe while ((hole = find_hole(kcd, kfedges)) != NULL) { if (find_hole_chains(kcd, hole, f, &chain, &sidechain)) { + ListBase fnew_kfedges, fnew2_kfedges; + /* chain goes across f and sidechain comes back * from the second last vertex to the second vertex. */ @@ -2443,28 +2460,28 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe BM_face_kill(bm, fhole); /* Move kfedges to either fnew or fnew2 if appropriate. * The hole edges were removed already */ - fnew_kfedges = knife_empty_list(kcd); - fnew2_kfedges = knife_empty_list(kcd); + BLI_listbase_clear(&fnew_kfedges); + BLI_listbase_clear(&fnew2_kfedges); for (ref = kfedges->first; ref; ref = refnext) { kfe = ref->ref; refnext = ref->next; if (knife_edge_in_face(kfe, fnew)) { BLI_remlink(kfedges, ref); kfe->basef = fnew; - knife_append_list(kcd, fnew_kfedges, kfe); + BLI_addtail(&fnew_kfedges, ref); } else if (knife_edge_in_face(kfe, fnew2)) { BLI_remlink(kfedges, ref); kfe->basef = fnew2; - knife_append_list(kcd, fnew2_kfedges, kfe); + BLI_addtail(&fnew2_kfedges, ref); } } /* We'll skip knife edges that are in the newly formed hole. * (Maybe we shouldn't have made a hole in the first place?) */ - if (fnew != fhole && fnew_kfedges->first) - knife_make_face_cuts(kcd, fnew, fnew_kfedges); - if (fnew2 != fhole && fnew2_kfedges->first) - knife_make_face_cuts(kcd, fnew2, fnew2_kfedges); + if (fnew != fhole && fnew_kfedges.first) + knife_make_face_cuts(kcd, fnew, &fnew_kfedges); + if (fnew2 != fhole && fnew2_kfedges.first) + knife_make_face_cuts(kcd, fnew2, &fnew2_kfedges); if (f == fhole) break; /* find_hole should always remove edges if it returns true, diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index cc26d6079a9..553c1faa36a 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -65,7 +65,7 @@ static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); dm_needsFree = false; } - else if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { dm = CDDM_from_curve(ob); dm_needsFree = true; } diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index bb044f39fba..59fbe739d03 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -555,39 +555,27 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) int cuts = RNA_int_get(op->ptr, "number_cuts"); RingSelOpData *lcd = op->customdata; bool show_cuts = false; + const bool has_numinput = hasNumInput(&lcd->num); view3d_operator_needs_opengl(C); /* using the keyboard to input the number of cuts */ - if (event->val == KM_PRESS && hasNumInput(&lcd->num)) { - /* Modal numinput active, try to handle numeric inputs first... */ - if (handleNumInput(C, &lcd->num, event)) { - float values[2] = {(float)cuts, smoothness}; - applyNumInput(&lcd->num, values); - - /* allow zero so you can backspace and type in a value - * otherwise 1 as minimum would make more sense */ - cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX); - smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); - - RNA_int_set(op->ptr, "number_cuts", cuts); - ringsel_find_edge(lcd, cuts); - show_cuts = true; - RNA_float_set(op->ptr, "smoothness", smoothness); - - ED_region_tag_redraw(lcd->ar); - } - else { - switch (event->type) { - case RETKEY: - case PADENTER: - case LEFTMOUSE: /* confirm */ // XXX hardcoded - return loopcut_finish(lcd, C, op); - default: - /* do nothing */; - break; - } - } + /* Modal numinput active, try to handle numeric inputs first... */ + if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &lcd->num, event)) { + float values[2] = {(float)cuts, smoothness}; + applyNumInput(&lcd->num, values); + + /* allow zero so you can backspace and type in a value + * otherwise 1 as minimum would make more sense */ + cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX); + smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); + + RNA_int_set(op->ptr, "number_cuts", cuts); + ringsel_find_edge(lcd, cuts); + show_cuts = true; + RNA_float_set(op->ptr, "smoothness", smoothness); + + ED_region_tag_redraw(lcd->ar); } else { bool handled = false; @@ -663,35 +651,33 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) handled = true; break; case MOUSEMOVE: /* mouse moved somewhere to select another loop */ - { - lcd->vc.mval[0] = event->mval[0]; - lcd->vc.mval[1] = event->mval[1]; - loopcut_mouse_move(lcd, cuts); + if (!has_numinput) { + lcd->vc.mval[0] = event->mval[0]; + lcd->vc.mval[1] = event->mval[1]; + loopcut_mouse_move(lcd, cuts); - ED_region_tag_redraw(lcd->ar); - handled = true; + ED_region_tag_redraw(lcd->ar); + handled = true; + } break; - } } - if (!handled && event->val == KM_PRESS) { - /* Modal numinput inactive, try to handle numeric inputs last... */ - if (handleNumInput(C, &lcd->num, event)) { - float values[2] = {(float)cuts, smoothness}; - applyNumInput(&lcd->num, values); - - /* allow zero so you can backspace and type in a value - * otherwise 1 as minimum would make more sense */ - cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX); - smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); - - RNA_int_set(op->ptr, "number_cuts", cuts); - ringsel_find_edge(lcd, cuts); - show_cuts = true; - RNA_float_set(op->ptr, "smoothness", smoothness); - - ED_region_tag_redraw(lcd->ar); - } + /* Modal numinput inactive, try to handle numeric inputs last... */ + if (!handled && event->val == KM_PRESS && handleNumInput(C, &lcd->num, event)) { + float values[2] = {(float)cuts, smoothness}; + applyNumInput(&lcd->num, values); + + /* allow zero so you can backspace and type in a value + * otherwise 1 as minimum would make more sense */ + cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX); + smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX); + + RNA_int_set(op->ptr, "number_cuts", cuts); + ringsel_find_edge(lcd, cuts); + show_cuts = true; + RNA_float_set(op->ptr, "smoothness", smoothness); + + ED_region_tag_redraw(lcd->ar); } } @@ -700,7 +686,7 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) char buf[64 + NUM_STR_REP_LEN * 2]; char str_rep[NUM_STR_REP_LEN * 2]; if (hasNumInput(&lcd->num)) { - outputNumInput(&lcd->num, str_rep, sce->unit.scale_length); + outputNumInput(&lcd->num, str_rep, &sce->unit); } else { BLI_snprintf(str_rep, NUM_STR_REP_LEN, "%d", cuts); diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 3d3e41d31cc..3b993332db0 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -993,6 +993,12 @@ static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } + /* we could support this, but not for now */ + if ((bm->totvertsel > 1) && (bm->totedgesel == 0)) { + BKE_report(op->reports, RPT_ERROR, "Cannot rip multiple disconnected vertices"); + return OPERATOR_CANCELLED; + } + /* note on selection: * When calling edge split we operate on tagged edges rather then selected * this is important because the edges to operate on are extended by one, diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 23828098940..9cdfb43ae15 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -2807,6 +2807,13 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) BMEdge *e; BMIter iter; + const bool use_wire = RNA_boolean_get(op->ptr, "use_wire"); + const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary"); + const bool use_multi_face = RNA_boolean_get(op->ptr, "use_multi_face"); + const bool use_non_contiguous = RNA_boolean_get(op->ptr, "use_non_contiguous"); + const bool use_verts = RNA_boolean_get(op->ptr, "use_verts"); + + if (!RNA_boolean_get(op->ptr, "extend")) EDBM_flag_disable_all(em, BM_ELEM_SELECT); @@ -2819,15 +2826,30 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN) && !BM_vert_is_manifold(v)) { - BM_vert_select_set(em->bm, v, true); + if (use_verts) { + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { + if (!BM_vert_is_manifold(v)) { + BM_vert_select_set(em->bm, v, true); + } + } } } - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && !BM_edge_is_manifold(e)) { - BM_edge_select_set(em->bm, e, true); + if (use_wire || use_boundary || use_multi_face || use_non_contiguous) { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + if ((use_wire && BM_edge_is_wire(e)) || + (use_boundary && BM_edge_is_boundary(e)) || + (use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) || + (use_multi_face && (BM_edge_face_count(e) > 2))) + { + /* check we never select perfect edge (in test above) */ + BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e))); + + BM_edge_select_set(em->bm, e, true); + } + } } } @@ -2854,6 +2876,18 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot) /* props */ RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection"); + /* edges */ + RNA_def_boolean(ot->srna, "use_wire", true, "Wire", + "Wire edges"); + RNA_def_boolean(ot->srna, "use_boundary", true, "Boundaries", + "Boundary edges"); + RNA_def_boolean(ot->srna, "use_multi_face", true, + "Multiple Faces", "Edges shared by 3+ faces"); + RNA_def_boolean(ot->srna, "use_non_contiguous", true, "Non Contiguous", + "Edges between faces pointing in alternate directions"); + /* verts */ + RNA_def_boolean(ot->srna, "use_verts", true, "Vertices", + "Vertices connecting multiple face regions"); } static int edbm_select_random_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 55ad303d0e1..3f1023b7fb4 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -881,12 +881,18 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op) int len; if (is_pair) { - if (!EDBM_op_init(em, &bmop, op, "connect_vert_pair verts=%hv", BM_ELEM_SELECT)) { + if (!EDBM_op_init(em, &bmop, op, + "connect_vert_pair verts=%hv verts_exclude=%hv faces_exclude=%hf", + BM_ELEM_SELECT, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN)) + { return OPERATOR_CANCELLED; } } else { - if (!EDBM_op_init(em, &bmop, op, "connect_verts verts=%hv check_degenerate=%b", BM_ELEM_SELECT, true)) { + if (!EDBM_op_init(em, &bmop, op, + "connect_verts verts=%hv faces_exclude=%hf check_degenerate=%b", + BM_ELEM_SELECT, BM_ELEM_HIDDEN, true)) + { return OPERATOR_CANCELLED; } } @@ -1019,28 +1025,23 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op) 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 use_select_history=%b", + BM_ELEM_SELECT, true); - EDBM_op_init(em, &bmop, op, "duplicate geom=%hvef", BM_ELEM_SELECT); - BMO_op_exec(bm, &bmop); + + /* de-select all would clear otherwise */ + BM_SELECT_HISTORY_BACKUP(bm); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); 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); - } + BM_SELECT_HISTORY_RESTORE(bm); if (!EDBM_op_finish(em, &bmop, op, true)) { return OPERATOR_CANCELLED; @@ -2424,7 +2425,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) float (*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2]; /* edit-object needed for matrix, and ar->regiondata for projections to work */ - if (ELEM3(NULL, obedit, ar, ar->regiondata)) + if (ELEM(NULL, obedit, ar, ar->regiondata)) return OPERATOR_CANCELLED; if (bm->totvertsel < 2) { @@ -3047,7 +3048,7 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span } /* set this vertex first */ - BLI_rotatelist_first(verts, v_act_link); + BLI_listbase_rotate_first(verts, v_act_link); BM_edgeloop_edges_get(el_store, edges); @@ -3479,6 +3480,11 @@ static void edbm_dissolve_prop__use_face_split(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_face_split", 0, "Face Split", "Split off face corners to maintain surrounding geometry"); } +static void edbm_dissolve_prop__use_boundary_tear(wmOperatorType *ot) +{ + RNA_def_boolean(ot->srna, "use_boundary_tear", 0, "Tear Boundary", + "Split off face corners instead of merging faces"); +} static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op) { @@ -3486,9 +3492,14 @@ static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split"); + const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear"); - if (!EDBM_op_callf(em, op, "dissolve_verts verts=%hv use_face_split=%b", BM_ELEM_SELECT, use_face_split)) + if (!EDBM_op_callf(em, op, + "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b", + BM_ELEM_SELECT, use_face_split, use_boundary_tear)) + { return OPERATOR_CANCELLED; + } EDBM_update_generic(em, true, true); @@ -3510,6 +3521,7 @@ void MESH_OT_dissolve_verts(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; edbm_dissolve_prop__use_face_split(ot); + edbm_dissolve_prop__use_boundary_tear(ot); } static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op) @@ -3621,6 +3633,7 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot) edbm_dissolve_prop__use_verts(ot); edbm_dissolve_prop__use_face_split(ot); + edbm_dissolve_prop__use_boundary_tear(ot); } static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 8adaae5fe42..c7d1d883537 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1328,6 +1328,15 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d /* don't keep stale derivedMesh data around, see: [#38872] */ BKE_editmesh_free_derivedmesh(em); + +#ifdef DEBUG + { + BMEditSelection *ese; + for (ese = em->bm->selected.first; ese; ese = ese->next) { + BLI_assert(BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)); + } + } +#endif } /* poll call for mesh operators requiring a view3d context */ diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 83947534d06..bf8559add6f 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -880,17 +880,6 @@ static void mesh_add_verts(Mesh *mesh, int len) mesh->totvert = totvert; } -void ED_mesh_transform(Mesh *me, float mat[4][4]) -{ - int i; - MVert *mvert = me->mvert; - - for (i = 0; i < me->totvert; i++, mvert++) - mul_m4_v3(mat, mvert->co); - - /* don't update normals, caller can do this explicitly */ -} - static void mesh_add_edges(Mesh *mesh, int len) { CustomData edata; diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 655d96ae6e5..76f6cb5ebb8 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -112,6 +112,10 @@ void MESH_OT_screw(struct wmOperatorType *ot); /* *** editmesh_inset.c *** */ void MESH_OT_inset(struct wmOperatorType *ot); +/* *** editmesh_intersect.c *** */ +void MESH_OT_intersect(struct wmOperatorType *ot); +void MESH_OT_face_split_by_edges(struct wmOperatorType *ot); + /* *** editmesh_knife.c *** */ void MESH_OT_knife_tool(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index 433fd176217..440ab14dacd 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -407,7 +407,7 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, BM_vert_at_index(em->bm, face[0]), BM_vert_at_index(em->bm, face[2]), BM_vert_at_index(em->bm, face[1]), NULL, - NULL, false); + NULL, BM_CREATE_NOP); /* set navigation polygon idx to the custom layer */ polygonIdx = (int *)CustomData_bmesh_get(&em->bm->pdata, newFace->head.data, CD_RECAST); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 0f65ed2c4ad..31653efa735 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -170,6 +170,8 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_bridge_edge_loops); WM_operatortype_append(MESH_OT_inset); + WM_operatortype_append(MESH_OT_intersect); + WM_operatortype_append(MESH_OT_face_split_by_edges); WM_operatortype_append(MESH_OT_poke); WM_operatortype_append(MESH_OT_wireframe); WM_operatortype_append(MESH_OT_edge_split); diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 36c7bb404da..f6a54beb8c8 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -594,7 +594,7 @@ bool mouse_mball(bContext *C, const int mval[2], bool extend, bool deselect, boo rect.ymin = mval[1] - 12; rect.ymax = mval[1] + 12; - hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true); /* does startelem exist? */ ml = mb->editelems->first; @@ -743,28 +743,3 @@ void undo_push_mball(bContext *C, const char *name) { undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL); } - -void ED_mball_transform(MetaBall *mb, float mat[4][4]) -{ - MetaElem *me; - float quat[4]; - const float scale = mat4_to_scale(mat); - const float scale_sqrt = sqrtf(scale); - - mat4_to_quat(quat, mat); - - for (me = mb->elems.first; me; me = me->next) { - mul_m4_v3(mat, &me->x); - mul_qt_qtqt(me->quat, quat, me->quat); - me->rad *= scale; - /* hrmf, probably elems shouldn't be - * treating scale differently - campbell */ - if (!MB_TYPE_SIZE_SQUARED(me->type)) { - mul_v3_fl(&me->expx, scale); - } - else { - mul_v3_fl(&me->expx, scale_sqrt); - } - } - DAG_id_tag_update(&mb->id, 0); -} diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 99dd8b75609..8972dd7cf08 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -34,6 +34,7 @@ #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" +#include "DNA_camera_types.h" #include "DNA_curve_types.h" #include "DNA_group_types.h" #include "DNA_lamp_types.h" @@ -83,6 +84,7 @@ #include "BKE_report.h" #include "BKE_sca.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "BKE_speaker.h" #include "BKE_texture.h" @@ -95,6 +97,7 @@ #include "ED_armature.h" #include "ED_curve.h" +#include "ED_lattice.h" #include "ED_mball.h" #include "ED_mesh.h" #include "ED_node.h" @@ -336,10 +339,7 @@ bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view } else { Scene *scene = CTX_data_scene(C); - if (v3d) - *layer = (v3d->scenelock && !v3d->localvd) ? scene->layact : v3d->layact; - else - *layer = scene->layact; + *layer = BKE_screen_view3d_layer_active_ex(v3d, scene, false); for (a = 0; a < 20; a++) { layer_values[a] = *layer & (1 << a); } @@ -446,14 +446,17 @@ Object *ED_object_add_type(bContext *C, int type, const float loc[3], const floa /* for object add operator */ static int object_add_exec(bContext *C, wmOperator *op) { + Object *ob; bool enter_editmode; unsigned int layer; float loc[3], rot[3]; + WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; - ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), loc, rot, enter_editmode, layer); + ob = ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), loc, rot, enter_editmode, layer); + BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius")); return OPERATOR_FINISHED; } @@ -472,6 +475,8 @@ void OBJECT_OT_add(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* properties */ + ED_object_add_unit_props(ot); RNA_def_enum(ot->srna, "type", object_type_items, 0, "Type", ""); ED_object_add_generic_props(ot, true); @@ -488,32 +493,31 @@ static int effector_add_exec(bContext *C, wmOperator *op) unsigned int layer; float loc[3], rot[3]; float mat[4][4]; + float dia; + WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; type = RNA_enum_get(op->ptr, "type"); + dia = RNA_float_get(op->ptr, "radius"); if (type == PFIELD_GUIDE) { Curve *cu; ob = ED_object_add_type(C, OB_CURVE, loc, rot, false, layer); - if (!ob) - return OPERATOR_CANCELLED; rename_id(&ob->id, CTX_DATA_(BLF_I18NCONTEXT_ID_OBJECT, "CurveGuide")); cu = ob->data; cu->flag |= CU_PATH | CU_3D; ED_object_editmode_enter(C, 0); ED_object_new_primitive_matrix(C, ob, loc, rot, mat, false); - BLI_addtail(&cu->editnurb->nurbs, add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, 1)); + BLI_addtail(&cu->editnurb->nurbs, add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, dia)); if (!enter_editmode) ED_object_editmode_exit(C, EM_FREEDATA); } else { ob = ED_object_add_type(C, OB_EMPTY, loc, rot, false, layer); - if (!ob) - return OPERATOR_CANCELLED; - + BKE_object_obdata_size_init(ob, dia); rename_id(&ob->id, CTX_DATA_(BLF_I18NCONTEXT_ID_OBJECT, "Field")); if (ELEM(type, PFIELD_WIND, PFIELD_VORTEX)) ob->empty_drawtype = OB_SINGLE_ARROW; @@ -540,8 +544,10 @@ void OBJECT_OT_effector_add(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", field_type_items, 0, "Type", ""); + ED_object_add_unit_props(ot); ED_object_add_generic_props(ot, true); } @@ -552,6 +558,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op) View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); Object *ob; + Camera *cam; bool enter_editmode; unsigned int layer; float loc[3], rot[3]; @@ -572,6 +579,9 @@ static int object_camera_add_exec(bContext *C, wmOperator *op) } } + cam = ob->data; + cam->drawsize = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) : ED_scene_grid_scale(scene, NULL); + return OPERATOR_FINISHED; } @@ -668,6 +678,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op) unsigned int layer; float loc[3], rot[3]; + WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; @@ -675,6 +686,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; obedit = ED_object_add_type(C, OB_FONT, loc, rot, enter_editmode, layer); + BKE_object_obdata_size_init(obedit, RNA_float_get(op->ptr, "radius")); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit); @@ -694,6 +706,9 @@ void OBJECT_OT_text_add(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ED_object_add_unit_props(ot); ED_object_add_generic_props(ot, true); } @@ -706,9 +721,10 @@ static int object_armature_add_exec(bContext *C, wmOperator *op) bool newob = false; bool enter_editmode; unsigned int layer; - float loc[3], rot[3]; + float loc[3], rot[3], dia; bool view_aligned = rv3d && (U.flag & USER_ADD_VIEWALIGNED); + WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; @@ -726,7 +742,8 @@ static int object_armature_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - add_primitive_bone(obedit, view_aligned); + dia = RNA_float_get(op->ptr, "radius"); + ED_armature_edit_bone_add_primitive(obedit, dia, view_aligned); /* userdef */ if (newob && !enter_editmode) @@ -750,6 +767,9 @@ void OBJECT_OT_armature_add(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ED_object_add_unit_props(ot); ED_object_add_generic_props(ot, true); } @@ -762,12 +782,14 @@ static int object_empty_add_exec(bContext *C, wmOperator *op) unsigned int layer; float loc[3], rot[3]; + WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL)) return OPERATOR_CANCELLED; ob = ED_object_add_type(C, OB_EMPTY, loc, rot, false, layer); BKE_object_empty_draw_type_set(ob, type); + BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius")); return OPERATOR_FINISHED; } @@ -790,6 +812,7 @@ void OBJECT_OT_empty_add(wmOperatorType *ot) /* properties */ ot->prop = RNA_def_enum(ot->srna, "type", object_empty_drawtype_items, 0, "Type", ""); + ED_object_add_unit_props(ot); ED_object_add_generic_props(ot, false); } @@ -899,12 +922,14 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op) unsigned int layer; float loc[3], rot[3]; + WM_operator_view3d_unit_defaults(C, op); if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL)) return OPERATOR_CANCELLED; ob = ED_object_add_type(C, OB_LAMP, loc, rot, false, layer); - la = (Lamp *)ob->data; + BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius")); + la = (Lamp *)ob->data; la->type = type; rename_id(&ob->id, get_lamp_defname(type)); rename_id(&la->id, get_lamp_defname(type)); @@ -936,6 +961,7 @@ void OBJECT_OT_lamp_add(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", lamp_type_items, 0, "Type", ""); RNA_def_property_translation_context(ot->prop, BLF_I18NCONTEXT_ID_LAMP); + ED_object_add_unit_props(ot); ED_object_add_generic_props(ot, false); } @@ -1470,7 +1496,7 @@ static void convert_ensure_curve_cache(Main *bmain, Scene *scene, Object *ob) /* Force creation. This is normally not needed but on operator * redo we might end up with an object which isn't evaluated yet. */ - if (ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { + if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { BKE_displist_make_curveTypes(scene, ob, false); } else if (ob->type == OB_MBALL) { @@ -2191,6 +2217,7 @@ static int add_named_exec(bContext *C, wmOperator *op) wmWindow *win = CTX_wm_window(C); const wmEvent *event = win ? win->eventstate : NULL; Main *bmain = CTX_data_main(C); + View3D *v3d = CTX_wm_view3d(C); /* may be NULL */ Scene *scene = CTX_data_scene(C); Base *basen, *base; Object *ob; @@ -2223,7 +2250,7 @@ static int add_named_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - basen->lay = basen->object->lay = scene->lay; + basen->lay = basen->object->lay = BKE_screen_view3d_layer_active(v3d, scene); basen->object->restrictflag &= ~OB_RESTRICT_VIEW; if (event) { @@ -2274,7 +2301,7 @@ static int join_poll(bContext *C) if (!ob || ob->id.lib) return 0; - if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE)) + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE)) return ED_operator_screenactive(C); else return 0; diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 94574e81b81..2402ecb498d 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -770,7 +770,7 @@ static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), const static bool is_multires_bake(Scene *scene) { - if (ELEM4(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_AO)) + if (ELEM(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_AO)) return scene->r.bake_flag & R_BAKE_MULTIRES; return 0; diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index b45ac124b43..372ca33fa4b 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -51,6 +51,7 @@ #include "BKE_image.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_node.h" #include "BKE_report.h" #include "BKE_modifier.h" #include "BKE_mesh.h" @@ -74,6 +75,63 @@ #include "object_intern.h" + +typedef struct BakeAPIRender { + Object *ob; + Main *main; + Scene *scene; + ReportList *reports; + ListBase selected_objects; + + ScenePassType pass_type; + int margin; + + int save_mode; + + bool is_clear; + bool is_split_materials; + bool is_automatic_name; + bool is_selected_to_active; + bool is_cage; + + float cage_extrusion; + int normal_space; + BakeNormalSwizzle normal_swizzle[3]; + + char uv_layer[MAX_CUSTOMDATA_LAYER_NAME]; + char custom_cage[MAX_NAME]; + char filepath[FILE_MAX]; + + int width; + int height; + const char *identifier; + + int result; + bool ready; + + /* callbacks */ + Render *render; + float *progress; + short *do_update; + + /* for redrawing */ + ScrArea *sa; +} BakeAPIRender; + +/* callbacks */ + +static void bake_progress_update(void *bjv, float progress) +{ + BakeAPIRender *bj = bjv; + + if (bj->progress && *bj->progress != progress) { + *bj->progress = progress; + + /* make jobs timer to send notifier */ + *(bj->do_update) = true; + } +} + /* catch esc */ static int bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { @@ -120,7 +178,7 @@ static bool write_internal_bake_pixels( void *lock; bool is_float; char *mask_buffer = NULL; - const int num_pixels = width * height; + const size_t num_pixels = (size_t)width * (size_t)height; ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); @@ -156,7 +214,7 @@ static bool write_internal_bake_pixels( IMB_buffer_float_from_float( ibuf->rect_float, buffer, ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false, - ibuf->x, ibuf->y, ibuf->x, ibuf->y); + ibuf->x, ibuf->y, ibuf->x, ibuf->x); } else { IMB_buffer_byte_from_float( @@ -169,7 +227,7 @@ static bool write_internal_bake_pixels( if (is_float) { IMB_buffer_float_from_float_mask( ibuf->rect_float, buffer, ibuf->channels, - ibuf->x, ibuf->y, ibuf->x, ibuf->y, mask_buffer); + ibuf->x, ibuf->y, ibuf->x, ibuf->x, mask_buffer); } else { IMB_buffer_byte_from_float_mask( @@ -235,7 +293,7 @@ static bool write_external_bake_pixels( IMB_buffer_float_from_float( ibuf->rect_float, buffer, ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false, - ibuf->x, ibuf->y, ibuf->x, ibuf->y); + ibuf->x, ibuf->y, ibuf->x, ibuf->x); } else { if (!is_noncolor) { @@ -253,7 +311,7 @@ static bool write_external_bake_pixels( /* margins */ if (margin > 0) { char *mask_buffer = NULL; - const int num_pixels = width * height; + const size_t num_pixels = (size_t)width * (size_t)height; mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask"); RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer); @@ -278,14 +336,14 @@ static bool write_external_bake_pixels( static bool is_noncolor_pass(ScenePassType pass_type) { - return ELEM7(pass_type, - SCE_PASS_Z, - SCE_PASS_NORMAL, - SCE_PASS_VECTOR, - SCE_PASS_INDEXOB, - SCE_PASS_UV, - SCE_PASS_RAYHITS, - SCE_PASS_INDEXMA); + return ELEM(pass_type, + SCE_PASS_Z, + SCE_PASS_NORMAL, + SCE_PASS_VECTOR, + SCE_PASS_INDEXOB, + SCE_PASS_UV, + SCE_PASS_RAYHITS, + SCE_PASS_INDEXMA); } /* if all is good tag image and return true */ @@ -310,10 +368,22 @@ static bool bake_object_check(Object *ob, ReportList *reports) } for (i = 0; i < ob->totcol; i++) { - ED_object_get_active_image(ob, i + 1, &image, NULL, NULL); + bNodeTree *ntree = NULL; + bNode *node = NULL; + ED_object_get_active_image(ob, i + 1, &image, NULL, &node, &ntree); if (image) { - ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); + ImBuf *ibuf; + + if (node) { + if (BKE_node_is_connected_to_output(ntree, node)) { + BKE_reportf(reports, RPT_ERROR, + "Circular dependency for image \"%s\" from object \"%s\"", + image->id.name + 2, ob->id.name + 2); + } + } + + ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); if (ibuf) { BKE_image_release_ibuf(image, ibuf, lock); @@ -372,7 +442,7 @@ static bool bake_objects_check(Main *bmain, Object *ob, ListBase *selected_objec if (ob_iter == ob) continue; - if (ELEM5(ob_iter->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL) == false) { + if (ELEM(ob_iter->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL) == false) { BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh or can't be converted to a mesh (Curve, Text, Surface or Metaball)", ob_iter->id.name + 2); return false; } @@ -420,7 +490,7 @@ static void build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images) for (i = 0; i < tot_mat; i++) { Image *image; - ED_object_get_active_image(ob, i + 1, &image, NULL, NULL); + ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL); if ((image->id.flag & LIB_DOIT)) { for (j = 0; j < i; j++) { @@ -444,10 +514,10 @@ static void build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images) /* * returns the total number of pixels */ -static int initialize_internal_images(BakeImages *bake_images, ReportList *reports) +static size_t initialize_internal_images(BakeImages *bake_images, ReportList *reports) { int i; - int tot_size = 0; + size_t tot_size = 0; for (i = 0; i < bake_images->size; i++) { ImBuf *ibuf; @@ -461,7 +531,7 @@ static int initialize_internal_images(BakeImages *bake_images, ReportList *repor bk_image->height = ibuf->y; bk_image->offset = tot_size; - tot_size += ibuf->x * ibuf->y; + tot_size += (size_t)ibuf->x * (size_t)ibuf->y; } else { BKE_image_release_ibuf(bk_image->image, ibuf, lock); @@ -473,45 +543,8 @@ static int initialize_internal_images(BakeImages *bake_images, ReportList *repor return tot_size; } -typedef struct BakeAPIRender { - Object *ob; - Main *main; - Scene *scene; - ReportList *reports; - ListBase selected_objects; - - ScenePassType pass_type; - int margin; - - int save_mode; - - bool is_clear; - bool is_split_materials; - bool is_automatic_name; - bool is_selected_to_active; - bool is_cage; - - float cage_extrusion; - int normal_space; - BakeNormalSwizzle normal_swizzle[3]; - - char uv_layer[MAX_CUSTOMDATA_LAYER_NAME]; - char custom_cage[MAX_NAME]; - char filepath[FILE_MAX]; - - int width; - int height; - const char *identifier; - - int result; - bool ready; - - /* for redrawing */ - ScrArea *sa; -} BakeAPIRender; - static int bake( - Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports, + Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports, const ScenePassType pass_type, const int margin, const BakeSaveMode save_mode, const bool is_clear, const bool is_split_materials, const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage, @@ -528,11 +561,10 @@ static int bake( int tot_highpoly; char restrict_flag_low = ob_low->restrictflag; - char restrict_flag_cage; + char restrict_flag_cage = 0; Mesh *me_low = NULL; Mesh *me_cage = NULL; - Render *re; float *result = NULL; @@ -544,13 +576,10 @@ static int bake( BakeImages bake_images = {NULL}; - int num_pixels; + size_t num_pixels; int tot_materials; int i; - re = RE_NewRender(scene->id.name); - RE_SetReports(re, NULL); - RE_bake_engine_set_engine_parameters(re, bmain, scene); if (!RE_bake_has_engine(re)) { @@ -589,8 +618,8 @@ static int bake( } /* we overallocate in case there is more materials than images */ - bake_images.data = MEM_callocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)"); - bake_images.lookup = MEM_callocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)"); + bake_images.data = MEM_mallocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)"); + bake_images.lookup = MEM_mallocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)"); build_image_lookup(bmain, ob_low, &bake_images); @@ -604,7 +633,7 @@ static int bake( else { /* when saving extenally always use the size specified in the UI */ - num_pixels = width * height * bake_images.size; + num_pixels = (size_t)width * (size_t)height * bake_images.size; for (i = 0; i < bake_images.size; i++) { bake_images.data[i].width = width; @@ -647,12 +676,7 @@ static int bake( } } - /* blender_test_break uses this global */ - G.is_break = false; - - RE_test_break_cb(re, NULL, bake_break); - - pixel_array_low = MEM_callocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly"); + pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly"); result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels"); /* get the mesh as it arrives in the renderer */ @@ -719,10 +743,8 @@ static int bake( /* initialize highpoly_data */ highpoly[i].ob = ob_iter; - highpoly[i].me = NULL; - highpoly[i].tri_mod = NULL; highpoly[i].restrict_flag = ob_iter->restrictflag; - highpoly[i].pixel_array = MEM_callocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly"); + highpoly[i].pixel_array = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly"); /* triangulating so BVH returns the primitive_id that will be used for rendering */ @@ -1038,6 +1060,8 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr) bkr->result = OPERATOR_CANCELLED; + bkr->render = RE_NewRender(bkr->scene->id.name); + /* XXX hack to force saving to always be internal. Whether (and how) to support * external saving will be addressed later */ bkr->save_mode = R_BAKE_SAVE_INTERNAL; @@ -1045,10 +1069,15 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr) static int bake_exec(bContext *C, wmOperator *op) { + Render *re; int result = OPERATOR_CANCELLED; BakeAPIRender bkr = {NULL}; bake_init_api_data(op, C, &bkr); + re = bkr.render; + + /* setup new render */ + RE_test_break_cb(re, NULL, bake_break); if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) return OPERATOR_CANCELLED; @@ -1058,9 +1087,11 @@ static int bake_exec(bContext *C, wmOperator *op) bake_images_clear(bkr.main, is_tangent); } + RE_SetReports(re, bkr.reports); + if (bkr.is_selected_to_active) { result = bake( - bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports, + bkr.render, bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.pass_type, bkr.margin, bkr.save_mode, bkr.is_clear, bkr.is_split_materials, bkr.is_automatic_name, true, bkr.is_cage, bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle, @@ -1073,7 +1104,7 @@ static int bake_exec(bContext *C, wmOperator *op) for (link = bkr.selected_objects.first; link; link = link->next) { Object *ob_iter = link->ptr.data; result = bake( - bkr.main, bkr.scene, ob_iter, NULL, bkr.reports, + bkr.render, bkr.main, bkr.scene, ob_iter, NULL, bkr.reports, bkr.pass_type, bkr.margin, bkr.save_mode, is_clear, bkr.is_split_materials, bkr.is_automatic_name, false, bkr.is_cage, bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle, @@ -1082,14 +1113,22 @@ static int bake_exec(bContext *C, wmOperator *op) } } + RE_SetReports(re, NULL); + BLI_freelistN(&bkr.selected_objects); return result; } -static void bake_startjob(void *bkv, short *UNUSED(stop), short *UNUSED(do_update), float *UNUSED(progress)) +static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, float *progress) { BakeAPIRender *bkr = (BakeAPIRender *)bkv; + /* setup new render */ + bkr->do_update = do_update; + bkr->progress = progress; + + RE_SetReports(bkr->render, bkr->reports); + if (!bake_objects_check(bkr->main, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) { bkr->result = OPERATOR_CANCELLED; return; @@ -1102,7 +1141,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *UNUSED(do_updat if (bkr->is_selected_to_active) { bkr->result = bake( - bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports, + bkr->render, bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->pass_type, bkr->margin, bkr->save_mode, bkr->is_clear, bkr->is_split_materials, bkr->is_automatic_name, true, bkr->is_cage, bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle, @@ -1115,7 +1154,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *UNUSED(do_updat for (link = bkr->selected_objects.first; link; link = link->next) { Object *ob_iter = link->ptr.data; bkr->result = bake( - bkr->main, bkr->scene, ob_iter, NULL, bkr->reports, + bkr->render, bkr->main, bkr->scene, ob_iter, NULL, bkr->reports, bkr->pass_type, bkr->margin, bkr->save_mode, is_clear, bkr->is_split_materials, bkr->is_automatic_name, false, bkr->is_cage, bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle, @@ -1126,6 +1165,8 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *UNUSED(do_updat return; } } + + RE_SetReports(bkr->render, NULL); } static void bake_freejob(void *bkv) @@ -1228,6 +1269,7 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event) { wmJob *wm_job; BakeAPIRender *bkr; + Render *re; Scene *scene = CTX_data_scene(C); bake_set_props(op, scene); @@ -1236,10 +1278,15 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event) if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_OBJECT_BAKE)) return OPERATOR_CANCELLED; - bkr = MEM_callocN(sizeof(BakeAPIRender), "render bake"); + bkr = MEM_mallocN(sizeof(BakeAPIRender), "render bake"); /* init bake render */ bake_init_api_data(op, C, bkr); + re = bkr->render; + + /* setup new render */ + RE_test_break_cb(re, NULL, bake_break); + RE_progress_cb(re, bkr, bake_progress_update); /* setup job */ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Texture Bake", diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 85e4bbce8dc..92ed84b7f5e 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -485,7 +485,7 @@ static void test_constraints(Object *owner, bPoseChannel *pchan) } /* target checks for specific constraints */ - if (ELEM3(curcon->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) { + if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) { if (ct->tar) { if (ct->tar->type != OB_CURVE) { ct->tar = NULL; diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index aba792413af..93956128b84 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -139,7 +139,9 @@ static int object_hide_view_clear_exec(bContext *C, wmOperator *UNUSED(op)) /* XXX need a context loop to handle such cases */ for (base = FIRSTBASE; base; base = base->next) { if ((base->lay & v3d->lay) && base->object->restrictflag & OB_RESTRICT_VIEW) { - base->flag |= SELECT; + if (!(base->object->restrictflag & OB_RESTRICT_SELECT)) { + base->flag |= SELECT; + } base->object->flag = base->flag; base->object->restrictflag &= ~OB_RESTRICT_VIEW; changed = true; @@ -361,6 +363,11 @@ static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata) if (freedata) free_editMball(obedit); } + /* Tag update so no access to freed data referenced from + * derived cache will happen. + */ + DAG_id_tag_update((ID *)obedit->data, 0); + return true; } @@ -447,7 +454,7 @@ void ED_object_editmode_enter(bContext *C, int flag) base = scene->basact; } - if (ELEM3(NULL, base, base->object, base->object->data)) return; + if (ELEM(NULL, base, base->object, base->object->data)) return; ob = base->object; @@ -589,7 +596,7 @@ static int editmode_toggle_poll(bContext *C) if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)) return 0; - return (ELEM7(ob->type, OB_MESH, OB_ARMATURE, OB_FONT, OB_MBALL, OB_LATTICE, OB_SURF, OB_CURVE)); + return OB_TYPE_SUPPORT_EDITMODE(ob->type); } void OBJECT_OT_editmode_toggle(wmOperatorType *ot) @@ -760,7 +767,7 @@ static void copy_texture_space(Object *to, Object *ob) texflag = ((Mesh *)ob->data)->texflag; poin2 = ((Mesh *)ob->data)->loc; } - else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { texflag = ((Curve *)ob->data)->texflag; poin2 = ((Curve *)ob->data)->loc; } @@ -775,7 +782,7 @@ static void copy_texture_space(Object *to, Object *ob) ((Mesh *)to->data)->texflag = texflag; poin1 = ((Mesh *)to->data)->loc; } - else if (ELEM3(to->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(to->type, OB_CURVE, OB_SURF, OB_FONT)) { ((Curve *)to->data)->texflag = texflag; poin1 = ((Curve *)to->data)->loc; } @@ -1112,7 +1119,7 @@ void ED_object_check_force_modifiers(Main *bmain, Scene *scene, Object *object) /* add/remove modifier as needed */ if (!md) { if (pd && (pd->shape == PFIELD_SHAPE_SURFACE) && ELEM(pd->forcefield, PFIELD_GUIDE, PFIELD_TEXTURE) == 0) - if (ELEM4(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE)) + if (ELEM(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE)) ED_object_modifier_add(NULL, bmain, scene, object, NULL, eModifierType_Surface); } else { @@ -1453,7 +1460,7 @@ static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d) BKE_mesh_texspace_get(ob->data, NULL, NULL, size); space = size[0] / size[1]; } - else if (ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { + else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { float size[3]; BKE_curve_texspace_get(ob->data, NULL, NULL, size); space = size[0] / size[1]; @@ -1500,7 +1507,7 @@ static EnumPropertyItem *object_mode_set_itemsf(bContext *C, PointerRNA *UNUSED( 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 && use_mode_particle_edit) || - (ELEM4(input->value, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, + (ELEM(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)) { diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index 47b5f1605e7..20e2e22cdf8 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -563,3 +563,67 @@ void OBJECT_OT_group_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data; + + if (!group) + return OPERATOR_CANCELLED; + + BKE_group_unlink(group); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_group_unlink(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Unlink Group"; + ot->idname = "OBJECT_OT_group_unlink"; + ot->description = "Unlink the group from all objects"; + + /* api callbacks */ + ot->exec = group_unlink_exec; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) /* Select objects in the same group as the active */ +{ + Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data; + + if (!group) + return OPERATOR_CANCELLED; + + CTX_DATA_BEGIN (C, Base *, base, visible_bases) + { + if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object)) { + ED_base_object_select(base, BA_SELECT); + } + } + CTX_DATA_END; + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_grouped_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Grouped"; + ot->idname = "OBJECT_OT_grouped_select"; + ot->description = "Select all objects in group"; + + /* api callbacks */ + ot->exec = select_grouped_exec; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index afff367b939..9f9a647c9f1 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -528,8 +528,7 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob invert_m4_m4(ob->imat, ob->obmat); /* apparently this call goes from right to left... */ - mul_serie_m4(hmd->parentinv, pose_mat, ob->imat, obedit->obmat, - NULL, NULL, NULL, NULL, NULL); + mul_m4_series(hmd->parentinv, pose_mat, ob->imat, obedit->obmat); DAG_relations_tag_update(bmain); diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index fd6b9a1bad0..6fa3caa6172 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -72,6 +72,7 @@ void OBJECT_OT_make_links_scene(struct wmOperatorType *ot); void OBJECT_OT_make_links_data(struct wmOperatorType *ot); void OBJECT_OT_move_to_layer(struct wmOperatorType *ot); void OBJECT_OT_drop_named_material(struct wmOperatorType *ot); +void OBJECT_OT_unlink_data(struct wmOperatorType *ot); /* object_edit.c */ void OBJECT_OT_mode_set(struct wmOperatorType *ot); @@ -251,6 +252,8 @@ void OBJECT_OT_shape_key_move(struct wmOperatorType *ot); void OBJECT_OT_group_add(struct wmOperatorType *ot); void OBJECT_OT_group_link(struct wmOperatorType *ot); void OBJECT_OT_group_remove(struct wmOperatorType *ot); +void OBJECT_OT_group_unlink(struct wmOperatorType *ot); +void OBJECT_OT_grouped_select(struct wmOperatorType *ot); /* object_bake.c */ void OBJECT_OT_bake_image(wmOperatorType *ot); diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c index 3897e452d0d..c24a127ed8b 100644 --- a/source/blender/editors/object/object_lattice.c +++ b/source/blender/editors/object/object_lattice.c @@ -174,21 +174,6 @@ void load_editLatt(Object *obedit) } } -/*************************** Transform Operator ************************/ - -void ED_lattice_transform(Lattice *lt, float mat[4][4]) -{ - BPoint *bp = lt->def; - int a = lt->pntsu * lt->pntsv * lt->pntsw; - - while (a--) { - mul_m4_v3(mat, bp->vec); - bp++; - } - - DAG_id_tag_update(<->id, 0); -} - static void bpoint_select_set(BPoint *bp, bool select) { if (select) { diff --git a/source/blender/editors/object/object_lod.c b/source/blender/editors/object/object_lod.c index 8bcbba6be96..48e980015a7 100644 --- a/source/blender/editors/object/object_lod.c +++ b/source/blender/editors/object/object_lod.c @@ -29,15 +29,11 @@ * \ingroup edobj */ - #include "DNA_object_types.h" #include "BKE_context.h" #include "BKE_object.h" -#include "ED_screen.h" -#include "ED_object.h" - #include "WM_api.h" #include "WM_types.h" @@ -45,6 +41,9 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "ED_screen.h" +#include "ED_object.h" + #include "object_intern.h" static int object_lod_add_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 1249beb4517..b05840b5823 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -98,7 +98,7 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc ModifierTypeInfo *mti = modifierType_getInfo(type); /* only geometry objects should be able to get modifiers [#25291] */ - if (!ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { + if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2); return NULL; } @@ -1876,7 +1876,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op) else if (ob->type == OB_MBALL) { BKE_displist_make_mball(CTX_data_main(C)->eval_ctx, scene, ob); } - else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { BKE_displist_make_curveTypes(scene, ob, 0); } diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index a8f07747d3a..7cf661de52c 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -229,6 +229,8 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_group_add); WM_operatortype_append(OBJECT_OT_group_link); WM_operatortype_append(OBJECT_OT_group_remove); + WM_operatortype_append(OBJECT_OT_group_unlink); + WM_operatortype_append(OBJECT_OT_grouped_select); WM_operatortype_append(OBJECT_OT_hook_add_selob); WM_operatortype_append(OBJECT_OT_hook_add_newob); @@ -241,6 +243,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_bake_image); WM_operatortype_append(OBJECT_OT_bake); WM_operatortype_append(OBJECT_OT_drop_named_material); + WM_operatortype_append(OBJECT_OT_unlink_data); WM_operatortype_append(OBJECT_OT_laplaciandeform_bind); WM_operatortype_append(OBJECT_OT_lod_add); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 3059d84a085..0d58eaee5fa 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -444,7 +444,7 @@ EnumPropertyItem prop_clear_parent_types[] = { /* Helper for ED_object_parent_clear() - Remove deform-modifiers associated with parent */ static void object_remove_parent_deform_modifiers(Object *ob, const Object *par) { - if (ELEM3(par->type, OB_ARMATURE, OB_LATTICE, OB_CURVE)) { + if (ELEM(par->type, OB_ARMATURE, OB_LATTICE, OB_CURVE)) { ModifierData *md, *mdn; /* assume that we only need to remove the first instance of matching deform modifier here */ @@ -593,7 +593,7 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object 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); + int pararm = ELEM(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO); DAG_id_tag_update(&par->id, OB_RECALC_OB); @@ -678,7 +678,7 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object * assuming that the parent is selected too... */ // XXX currently this should only happen for meshes, curves, surfaces, and lattices - this stuff isn't available for metas yet - if (ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { ModifierData *md; switch (partype) { @@ -1128,7 +1128,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op) /* also remove all tracking constraints */ for (con = ob->constraints.last; con; con = pcon) { pcon = con->prev; - if (ELEM3(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK)) + if (ELEM(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK)) BKE_constraint_remove(&ob->constraints, con); } @@ -1192,7 +1192,7 @@ static int track_set_exec(bContext *C, wmOperator *op) DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* Lamp, Camera and Speaker track differently by default */ - if (ELEM3(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { data->trackflag = TRACK_nZ; } } @@ -1213,7 +1213,7 @@ static int track_set_exec(bContext *C, wmOperator *op) DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* Lamp, Camera and Speaker track differently by default */ - if (ELEM3(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { data->reserved1 = TRACK_nZ; data->reserved2 = UP_Y; } @@ -1235,7 +1235,7 @@ static int track_set_exec(bContext *C, wmOperator *op) DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* Lamp, Camera and Speaker track differently by default */ - if (ELEM3(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { data->trackflag = TRACK_nZ; data->lockflag = LOCK_Y; } @@ -2143,9 +2143,40 @@ static void tag_localizable_objects(bContext *C, int mode) /* TODO(sergey): Drivers targets? */ } +/** + * Instance indirectly referenced zero user objects, + * otherwise they're lost on reload, see T40595. + */ +static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene) +{ + Object *ob; + bool changed = false; + + for (ob = bmain->object.first; ob; ob = ob->id.next) { + if (ob->id.lib && (ob->id.us == 0)) { + Base *base; + + ob->id.us = 1; + + /* not essential, but for correctness */ + id_lib_extern(&ob->id); + + base = BKE_scene_base_add(scene, ob); + base->flag |= SELECT; + base->object->flag = base->flag; + DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + + changed = true; + } + } + + return changed; +} + static int make_local_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); AnimData *adt; ParticleSystem *psys; Material *ma, ***matarar; @@ -2154,6 +2185,14 @@ static int make_local_exec(bContext *C, wmOperator *op) int a, b, mode = RNA_enum_get(op->ptr, "type"); if (mode == MAKE_LOCAL_ALL) { + /* de-select so the user can differentiate newly instanced from existing objects */ + BKE_scene_base_deselect_all(scene); + + if (make_local_all__instance_indirect_unused(bmain, scene)) { + BKE_report(op->reports, RPT_INFO, + "Orphan library objects added to the current scene to avoid loss"); + } + BKE_library_make_local(bmain, NULL, false); /* NULL is all libs */ WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; @@ -2399,3 +2438,55 @@ void OBJECT_OT_drop_named_material(wmOperatorType *ot) /* properties */ RNA_def_string(ot->srna, "name", "Material", MAX_ID_NAME - 2, "Name", "Material name to assign"); } + +static int object_unlink_data_exec(bContext *C, wmOperator *op) +{ + ID *id; + PropertyPointerRNA pprop; + + uiIDContextProperty(C, &pprop.ptr, &pprop.prop); + + if (pprop.prop == NULL) { + BKE_report(op->reports, RPT_ERROR, "Incorrect context for running object data unlink"); + return OPERATOR_CANCELLED; + } + + id = pprop.ptr.id.data; + + if (GS(id->name) == ID_OB) { + Object *ob = (Object *)id; + if (ob->data) { + ID *id_data = ob->data; + + if (GS(id_data->name) == ID_IM) { + id_us_min(id_data); + ob->data = NULL; + } + else { + BKE_report(op->reports, RPT_ERROR, "Can't unlink this object data"); + return OPERATOR_CANCELLED; + } + } + } + + RNA_property_update(C, &pprop.ptr, pprop.prop); + + return OPERATOR_FINISHED; +} + +/** + * \note Only for empty-image objects, this operator is needed + */ +void OBJECT_OT_unlink_data(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Unlink"; + ot->idname = "OBJECT_OT_unlink_data"; + ot->description = ""; + + /* api callbacks */ + ot->exec = object_unlink_data_exec; + + /* flags */ + ot->flag = OPTYPE_INTERNAL; +} diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 9b1aa054f84..e295a63848a 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -753,11 +753,11 @@ static bool select_grouped_color(bContext *C, Object *ob) static bool objects_share_gameprop(Object *a, Object *b) { bProperty *prop; - /*make a copy of all its properties*/ for (prop = a->prop.first; prop; prop = prop->next) { - if (BKE_bproperty_object_get(b, prop->name) ) + if (BKE_bproperty_object_get(b, prop->name)) { return 1; + } } return 0; } diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c index cfd1c4d3b0a..85104c14395 100644 --- a/source/blender/editors/object/object_shapekey.c +++ b/source/blender/editors/object/object_shapekey.c @@ -485,27 +485,22 @@ void OBJECT_OT_shape_key_mirror(wmOperatorType *ot) static int shape_key_move_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); - - int type = RNA_enum_get(op->ptr, "type"); Key *key = BKE_key_from_object(ob); - if (key) { - KeyBlock *kb, *kb_other; - int shapenr_act = ob->shapenr - 1; - int shapenr_swap = shapenr_act + type; - kb = BLI_findlink(&key->block, shapenr_act); + if (!key) { + return OPERATOR_CANCELLED; + } - if ((type == -1 && kb->prev == NULL) || (type == 1 && kb->next == NULL)) { - return OPERATOR_CANCELLED; - } + { + KeyBlock *kb, *kb_other, *kb_iter; + const int type = RNA_enum_get(op->ptr, "type"); + const int shape_tot = key->totkey; + const int shapenr_act = ob->shapenr - 1; + const int shapenr_swap = (shape_tot + shapenr_act + type) % shape_tot; - for (kb_other = key->block.first; kb_other; kb_other = kb_other->next) { - if (kb_other->relative == shapenr_act) { - kb_other->relative += type; - } - else if (kb_other->relative == shapenr_swap) { - kb_other->relative -= type; - } + kb = BLI_findlink(&key->block, shapenr_act); + if (!kb || shape_tot == 1) { + return OPERATOR_CANCELLED; } if (type == -1) { @@ -513,17 +508,57 @@ static int shape_key_move_exec(bContext *C, wmOperator *op) kb_other = kb->prev; BLI_remlink(&key->block, kb); BLI_insertlinkbefore(&key->block, kb_other, kb); - ob->shapenr--; } else { /* move next */ kb_other = kb->next; BLI_remlink(&key->block, kb); BLI_insertlinkafter(&key->block, kb_other, kb); - ob->shapenr++; } - SWAP(float, kb_other->pos, kb->pos); /* for absolute shape keys */ + ob->shapenr = shapenr_swap + 1; + + /* for relative shape keys */ + if (kb_other) { + for (kb_iter = key->block.first; kb_iter; kb_iter = kb_iter->next) { + if (kb_iter->relative == shapenr_act) { + kb_iter->relative = shapenr_swap; + } + else if (kb_iter->relative == shapenr_swap) { + kb_iter->relative = shapenr_act; + } + } + } + /* First key became last, or vice-versa, we have to change all keys' relative value. */ + else { + for (kb_iter = key->block.first; kb_iter; kb_iter = kb_iter->next) { + if (kb_iter->relative == shapenr_act) { + kb_iter->relative = shapenr_swap; + } + else { + kb_iter->relative += type; + } + } + } + + /* for absolute shape keys */ + if (kb_other) { + SWAP(float, kb_other->pos, kb->pos); + } + /* First key became last, or vice-versa, we have to change all keys' pos value. */ + else { + float pos = kb->pos; + if (type == -1) { + for (kb_iter = key->block.first; kb_iter; kb_iter = kb_iter->next) { + SWAP(float, kb_iter->pos, pos); + } + } + else { + for (kb_iter = key->block.last; kb_iter; kb_iter = kb_iter->prev) { + SWAP(float, kb_iter->pos, pos); + } + } + } /* First key is refkey, matches interface and BKE_key_sort */ key->refkey = key->block.first; diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 6e59f9f4aea..a1b8478a0e1 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -385,7 +385,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l /* first check if we can execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - if (ELEM6(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) { + if (ELEM(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, @@ -472,27 +472,12 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l /* apply to object data */ if (ob->type == OB_MESH) { Mesh *me = ob->data; - MVert *mvert; - int a; if (apply_scale) multiresModifier_scale_disp(scene, ob); /* adjust data */ - mvert = me->mvert; - for (a = 0; a < me->totvert; a++, mvert++) - mul_m4_v3(mat, mvert->co); - - if (me->key) { - KeyBlock *kb; - - for (kb = me->key->block.first; kb; kb = kb->next) { - float *fp = kb->data; - - for (a = 0; a < kb->totelem; a++, fp += 3) - mul_m4_v3(mat, fp); - } - } + BKE_mesh_transform(me, mat, true); /* update normals */ BKE_mesh_calc_normals(me); @@ -502,45 +487,17 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; - BPoint *bp = lt->def; - int a = lt->pntsu * lt->pntsv * lt->pntsw; - - while (a--) { - mul_m4_v3(mat, bp->vec); - bp++; - } + + BKE_lattice_transform(lt, mat, true); } else if (ob->type == OB_MBALL) { MetaBall *mb = ob->data; - ED_mball_transform(mb, mat); + BKE_mball_transform(mb, mat); } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; - - Nurb *nu; - BPoint *bp; - BezTriple *bezt; - int a; - scale = mat3_to_scale(rsmat); - - for (nu = cu->nurb.first; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - a = nu->pntsu; - for (bezt = nu->bezt; a--; bezt++) { - mul_m4_v3(mat, bezt->vec[0]); - mul_m4_v3(mat, bezt->vec[1]); - mul_m4_v3(mat, bezt->vec[2]); - bezt->radius *= scale; - } - BKE_nurb_handles_calc(nu); - } - else { - a = nu->pntsu * nu->pntsv; - for (bp = nu->bp; a--; bp++) - mul_m4_v3(mat, bp->vec); - } - } + BKE_curve_transform_ex(cu, mat, true, scale); } else if (ob->type == OB_CAMERA) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); @@ -784,7 +741,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) } if (ctx_ob_act) { - BLI_rotatelist_first(&ctx_data_list, (LinkData *)ctx_ob_act); + BLI_listbase_rotate_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 ccc3e2e8278..6897861c81c 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -62,6 +62,7 @@ #include "BKE_depsgraph.h" #include "BKE_mesh_mapping.h" #include "BKE_editmesh.h" +#include "BKE_modifier.h" #include "BKE_report.h" #include "BKE_DerivedMesh.h" #include "BKE_object_deform.h" @@ -2301,7 +2302,6 @@ static void vgroup_blend_subset(Object *ob, const bool *vgroup_validmap, const i 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) { @@ -4324,7 +4324,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) return OPERATOR_FINISHED; } -static int vgroup_sort(void *def_a_ptr, void *def_b_ptr) +static int vgroup_sort_name(void *def_a_ptr, void *def_b_ptr) { bDeformGroup *def_a = (bDeformGroup *)def_a_ptr; bDeformGroup *def_b = (bDeformGroup *)def_b_ptr; @@ -4332,18 +4332,59 @@ static int vgroup_sort(void *def_a_ptr, void *def_b_ptr) return BLI_natstrcmp(def_a->name, def_b->name); } +/* Sorts the weight groups according to the bone hierarchy of the + associated armature (similar to how bones are ordered in the Outliner) */ +static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase) +{ + if (bonebase == NULL) { + Object *armobj = modifiers_isDeformedByArmature(ob); + if (armobj != NULL) { + bArmature *armature = armobj->data; + bonebase = &armature->bonebase; + } + } + + if (bonebase != NULL) { + Bone *bone; + for (bone = bonebase->last; bone; bone = bone->prev) { + bDeformGroup *dg = defgroup_find_name(ob, bone->name); + vgroup_sort_bone_hierarchy(ob, &bone->childbase); + + if (dg != NULL) { + BLI_remlink(&ob->defbase, dg); + BLI_addhead(&ob->defbase, dg); + } + } + } + + return; +} + +enum { + SORT_TYPE_NAME = 0, + SORT_TYPE_BONEHIERARCHY = 1 +}; + static int vertex_group_sort_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); char *name_array; int ret; + int sort_type = RNA_enum_get(op->ptr, "sort_type"); /*init remapping*/ name_array = vgroup_init_remap(ob); /*sort vgroup names*/ - BLI_sortlist(&ob->defbase, vgroup_sort); - + switch (sort_type) { + case SORT_TYPE_NAME: + BLI_sortlist(&ob->defbase, vgroup_sort_name); + break; + case SORT_TYPE_BONEHIERARCHY: + vgroup_sort_bone_hierarchy(ob, NULL); + break; + } + /*remap vgroup data to map to correct names*/ ret = vgroup_do_remap(ob, name_array, op); @@ -4359,9 +4400,15 @@ static int vertex_group_sort_exec(bContext *C, wmOperator *op) void OBJECT_OT_vertex_group_sort(wmOperatorType *ot) { + static EnumPropertyItem vgroup_sort_type[] = { + {SORT_TYPE_NAME, "NAME", 0, "Name", ""}, + {SORT_TYPE_BONEHIERARCHY, "BONE_HIERARCHY", 0, "Bone Hierarchy", ""}, + {0, NULL, 0, NULL, NULL} + }; + ot->name = "Sort Vertex Groups"; ot->idname = "OBJECT_OT_vertex_group_sort"; - ot->description = "Sort vertex groups alphabetically"; + ot->description = "Sort vertex groups"; /* api callbacks */ ot->poll = vertex_group_poll; @@ -4369,6 +4416,8 @@ void OBJECT_OT_vertex_group_sort(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "sort_type", vgroup_sort_type, SORT_TYPE_NAME, "Sort type", "Sort type"); } static int vgroup_move_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c index b46d79fc82e..13a3d7a523f 100644 --- a/source/blender/editors/physics/rigidbody_object.c +++ b/source/blender/editors/physics/rigidbody_object.c @@ -485,78 +485,6 @@ static EnumPropertyItem *rigidbody_materials_itemf(bContext *UNUSED(C), PointerR /* ------------------------------------------ */ -/* helper function to calculate volume of rigidbody object */ -// TODO: allow a parameter to specify method used to calculate this? -static float rigidbody_object_calc_volume(Object *ob) -{ - RigidBodyOb *rbo = ob->rigidbody_object; - - float size[3] = {1.0f, 1.0f, 1.0f}; - float radius = 1.0f; - float height = 1.0f; - - float volume = 0.0f; - - /* if automatically determining dimensions, use the Object's boundbox - * - assume that all quadrics are standing upright on local z-axis - * - assume even distribution of mass around the Object's pivot - * (i.e. Object pivot is centralised in boundbox) - * - boundbox gives full width - */ - // XXX: all dimensions are auto-determined now... later can add stored settings for this - BKE_object_dimensions_get(ob, size); - - if (ELEM3(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { - /* take radius as largest x/y dimension, and height as z-dimension */ - radius = MAX2(size[0], size[1]) * 0.5f; - height = size[2]; - } - else if (rbo->shape == RB_SHAPE_SPHERE) { - /* take radius to the the largest dimension to try and encompass everything */ - radius = max_fff(size[0], size[1], size[2]) * 0.5f; - } - - /* calculate volume as appropriate */ - switch (rbo->shape) { - case RB_SHAPE_BOX: - volume = size[0] * size[1] * size[2]; - break; - - case RB_SHAPE_SPHERE: - volume = 4.0f / 3.0f * (float)M_PI * radius * radius * radius; - break; - - /* for now, assume that capsule is close enough to a cylinder... */ - case RB_SHAPE_CAPSULE: - case RB_SHAPE_CYLINDER: - volume = (float)M_PI * radius * radius * height; - break; - - case RB_SHAPE_CONE: - volume = (float)M_PI / 3.0f * radius * radius * height; - break; - - /* for now, all mesh shapes are just treated as boxes... - * NOTE: this may overestimate the volume, but other methods are overkill - */ - case RB_SHAPE_CONVEXH: - case RB_SHAPE_TRIMESH: - volume = size[0] * size[1] * size[2]; - break; - -#if 0 // XXX: not defined yet - case RB_SHAPE_COMPOUND: - volume = 0.0f; - break; -#endif - } - - /* return the volume calculated */ - return volume; -} - -/* ------------------------------------------ */ - static int rigidbody_objects_calc_mass_exec(bContext *C, wmOperator *op) { int material = RNA_enum_get(op->ptr, "material"); @@ -589,7 +517,7 @@ static int rigidbody_objects_calc_mass_exec(bContext *C, wmOperator *op) /* mass is calculated from the approximate volume of the object, * and the density of the material we're simulating */ - volume = rigidbody_object_calc_volume(ob); + BKE_rigidbody_calc_volume(ob, &volume); mass = volume * density; /* use RNA-system to change the property and perform all necessary changes */ diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h index 8f8cc542821..f9377d576bf 100644 --- a/source/blender/editors/render/render_intern.h +++ b/source/blender/editors/render/render_intern.h @@ -72,6 +72,7 @@ void SCENE_OT_freestyle_geometry_modifier_add(struct wmOperatorType *ot); void SCENE_OT_freestyle_modifier_remove(struct wmOperatorType *ot); void SCENE_OT_freestyle_modifier_move(struct wmOperatorType *ot); void SCENE_OT_freestyle_modifier_copy(struct wmOperatorType *ot); +void SCENE_OT_freestyle_stroke_material_create(struct wmOperatorType *ot); #endif diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index fd67115808f..baf25a49f7c 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -1032,6 +1032,7 @@ typedef struct RenderPreview { int start_resolution_divider; int resolution_divider; + bool has_freestyle; } RenderPreview; static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, rcti *disprect) @@ -1150,6 +1151,15 @@ static void render_update_resolution(Render *re, const RenderPreview *rp, else { RE_ChangeResolution(re, winx, winy, NULL); } + + if (rp->has_freestyle) { + if (rp->resolution_divider == 1) { + RE_ChangeModeFlag(re, R_EDGE_FRS, false); + } + else { + RE_ChangeModeFlag(re, R_EDGE_FRS, true); + } + } } static void render_view3d_startjob(void *customdata, short *stop, short *do_update, float *UNUSED(progress)) @@ -1163,7 +1173,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda bool orth, restore = 0; char name[32]; int update_flag; - bool use_border = false; + bool use_border; update_flag = rp->engine->job_update_flag; rp->engine->job_update_flag = 0; @@ -1192,7 +1202,17 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda rstats = RE_GetStats(re); if (update_flag & PR_UPDATE_VIEW) { + Object *object; rp->resolution_divider = rp->start_resolution_divider; + + /* Same as database_init_objects(), loop over all objects. + * We might consider de-duplicating the code between this two cases. + */ + for (object = rp->bmain->object.first; object; object = object->id.next) { + float mat[4][4]; + mul_m4_m4m4(mat, rp->viewmat, object->obmat); + invert_m4_m4(object->imat_ren, mat); + } } use_border = render_view3d_disprect(rp->scene, rp->ar, rp->v3d, @@ -1419,6 +1439,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) rp->bmain = CTX_data_main(C); rp->resolution_divider = divider; rp->start_resolution_divider = divider; + rp->has_freestyle = scene->r.mode & R_EDGE_FRS; copy_m4_m4(rp->viewmat, rp->rv3d->viewmat); /* clear info text */ diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c index 3401577ee55..0d334082a2b 100644 --- a/source/blender/editors/render/render_ops.c +++ b/source/blender/editors/render/render_ops.c @@ -75,6 +75,7 @@ void ED_operatortypes_render(void) WM_operatortype_append(SCENE_OT_freestyle_modifier_remove); WM_operatortype_append(SCENE_OT_freestyle_modifier_move); WM_operatortype_append(SCENE_OT_freestyle_modifier_copy); + WM_operatortype_append(SCENE_OT_freestyle_stroke_material_create); #endif WM_operatortype_append(TEXTURE_OT_slot_copy); diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 9cc672fe8ae..72b4da64c3e 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -891,10 +891,10 @@ static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op) } if (lineset->linestyle) { lineset->linestyle->id.us--; - lineset->linestyle = BKE_copy_linestyle(lineset->linestyle); + lineset->linestyle = BKE_linestyle_copy(lineset->linestyle); } else { - lineset->linestyle = BKE_new_linestyle("LineStyle", NULL); + lineset->linestyle = BKE_linestyle_new("LineStyle", NULL); } DAG_id_tag_update(&lineset->linestyle->id, 0); WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle); @@ -928,7 +928,7 @@ static int freestyle_color_modifier_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (BKE_add_linestyle_color_modifier(lineset->linestyle, NULL, type) == NULL) { + if (BKE_linestyle_color_modifier_add(lineset->linestyle, NULL, type) == NULL) { BKE_report(op->reports, RPT_ERROR, "Unknown line color modifier type"); return OPERATOR_CANCELLED; } @@ -968,7 +968,7 @@ static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (BKE_add_linestyle_alpha_modifier(lineset->linestyle, NULL, type) == NULL) { + if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, NULL, type) == NULL) { BKE_report(op->reports, RPT_ERROR, "Unknown alpha transparency modifier type"); return OPERATOR_CANCELLED; } @@ -1008,7 +1008,7 @@ static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (BKE_add_linestyle_thickness_modifier(lineset->linestyle, NULL, type) == NULL) { + if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, NULL, type) == NULL) { BKE_report(op->reports, RPT_ERROR, "Unknown line thickness modifier type"); return OPERATOR_CANCELLED; } @@ -1048,7 +1048,7 @@ static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (BKE_add_linestyle_geometry_modifier(lineset->linestyle, NULL, type) == NULL) { + if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, NULL, type) == NULL) { BKE_report(op->reports, RPT_ERROR, "Unknown stroke geometry modifier type"); return OPERATOR_CANCELLED; } @@ -1104,16 +1104,16 @@ static int freestyle_modifier_remove_exec(bContext *C, wmOperator *op) switch (freestyle_get_modifier_type(&ptr)) { case LS_MODIFIER_TYPE_COLOR: - BKE_remove_linestyle_color_modifier(lineset->linestyle, modifier); + BKE_linestyle_color_modifier_remove(lineset->linestyle, modifier); break; case LS_MODIFIER_TYPE_ALPHA: - BKE_remove_linestyle_alpha_modifier(lineset->linestyle, modifier); + BKE_linestyle_alpha_modifier_remove(lineset->linestyle, modifier); break; case LS_MODIFIER_TYPE_THICKNESS: - BKE_remove_linestyle_thickness_modifier(lineset->linestyle, modifier); + BKE_linestyle_thickness_modifier_remove(lineset->linestyle, modifier); break; case LS_MODIFIER_TYPE_GEOMETRY: - BKE_remove_linestyle_geometry_modifier(lineset->linestyle, modifier); + BKE_linestyle_geometry_modifier_remove(lineset->linestyle, modifier); break; default: BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier"); @@ -1154,16 +1154,16 @@ static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op) switch (freestyle_get_modifier_type(&ptr)) { case LS_MODIFIER_TYPE_COLOR: - BKE_copy_linestyle_color_modifier(lineset->linestyle, modifier); + BKE_linestyle_color_modifier_copy(lineset->linestyle, modifier); break; case LS_MODIFIER_TYPE_ALPHA: - BKE_copy_linestyle_alpha_modifier(lineset->linestyle, modifier); + BKE_linestyle_alpha_modifier_copy(lineset->linestyle, modifier); break; case LS_MODIFIER_TYPE_THICKNESS: - BKE_copy_linestyle_thickness_modifier(lineset->linestyle, modifier); + BKE_linestyle_thickness_modifier_copy(lineset->linestyle, modifier); break; case LS_MODIFIER_TYPE_GEOMETRY: - BKE_copy_linestyle_geometry_modifier(lineset->linestyle, modifier); + BKE_linestyle_geometry_modifier_copy(lineset->linestyle, modifier); break; default: BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier"); @@ -1205,16 +1205,16 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op) switch (freestyle_get_modifier_type(&ptr)) { case LS_MODIFIER_TYPE_COLOR: - BKE_move_linestyle_color_modifier(lineset->linestyle, modifier, dir); + BKE_linestyle_color_modifier_move(lineset->linestyle, modifier, dir); break; case LS_MODIFIER_TYPE_ALPHA: - BKE_move_linestyle_alpha_modifier(lineset->linestyle, modifier, dir); + BKE_linestyle_alpha_modifier_move(lineset->linestyle, modifier, dir); break; case LS_MODIFIER_TYPE_THICKNESS: - BKE_move_linestyle_thickness_modifier(lineset->linestyle, modifier, dir); + BKE_linestyle_thickness_modifier_move(lineset->linestyle, modifier, dir); break; case LS_MODIFIER_TYPE_GEOMETRY: - BKE_move_linestyle_geometry_modifier(lineset->linestyle, modifier, dir); + BKE_linestyle_geometry_modifier_move(lineset->linestyle, modifier, dir); break; default: BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier"); @@ -1250,6 +1250,36 @@ void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot) RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move, UP or DOWN"); } +static int freestyle_stroke_material_create_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + FreestyleLineStyle *linestyle = BKE_linestyle_active_from_scene(scene); + + if (!linestyle) { + BKE_report(op->reports, RPT_ERROR, "No active line style in the current scene"); + return OPERATOR_CANCELLED; + } + + FRS_create_stroke_material(bmain, linestyle); + + return OPERATOR_FINISHED; +} + +void SCENE_OT_freestyle_stroke_material_create(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Create Freestyle Stroke Material"; + ot->idname = "SCENE_OT_freestyle_stroke_material_create"; + ot->description = "Create Freestyle stroke material for testing"; + + /* api callbacks */ + ot->exec = freestyle_stroke_material_create_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + #endif /* WITH_FREESTYLE */ static int texture_slot_move_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 94d8d78de1a..6b58d3d55aa 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -45,6 +45,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_icons.h" #include "BKE_main.h" @@ -165,6 +166,7 @@ void ED_render_engine_changed(Main *bmain) bScreen *sc; ScrArea *sa; Scene *scene; + Material *ma; for (sc = bmain->screen.first; sc; sc = sc->id.next) for (sa = sc->areabase.first; sa; sa = sa->next) @@ -174,6 +176,13 @@ void ED_render_engine_changed(Main *bmain) for (scene = bmain->scene.first; scene; scene = scene->id.next) ED_render_id_flush_update(bmain, &scene->id); + + /* reset texture painting. Sending one dependency graph signal for any material should + * refresh any texture slots */ + ma = bmain->mat.first; + if (ma) { + DAG_id_tag_update(&ma->id, 0); + } } /***************************** Updates *********************************** diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index f42dae6530a..aa0ae22a003 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -470,8 +470,8 @@ void ED_region_tag_redraw(ARegion *ar) * but python scripts can cause this to happen indirectly */ if (ar && !(ar->do_draw & RGN_DRAWING)) { /* zero region means full region redraw */ - ar->do_draw &= ~RGN_DRAW_PARTIAL; /* just incase */ - ar->do_draw = RGN_DRAW; + ar->do_draw &= ~RGN_DRAW_PARTIAL; + ar->do_draw |= RGN_DRAW; memset(&ar->drawrct, 0, sizeof(ar->drawrct)); } } @@ -492,9 +492,9 @@ void ED_region_tag_refresh_ui(ARegion *ar) void ED_region_tag_redraw_partial(ARegion *ar, rcti *rct) { if (ar && !(ar->do_draw & RGN_DRAWING)) { - if (!ar->do_draw) { + if (!(ar->do_draw & RGN_DRAW)) { /* no redraw set yet, set partial region */ - ar->do_draw = RGN_DRAW_PARTIAL; + ar->do_draw |= RGN_DRAW_PARTIAL; ar->drawrct = *rct; } else if (ar->drawrct.xmin != ar->drawrct.xmax) { @@ -889,38 +889,59 @@ static int rct_fits(rcti *rect, char dir, int size) /* function checks if some overlapping region was defined before - on same place */ static void region_overlap_fix(ScrArea *sa, ARegion *ar) { - ARegion *ar1 = ar->prev; - + ARegion *ar1; + const int align = ar->alignment & ~RGN_SPLIT_PREV; + int align1 = 0; + /* find overlapping previous region on same place */ - while (ar1) { - if (ar1->overlap) { - if ((ar1->alignment & RGN_SPLIT_PREV) == 0) - if (BLI_rcti_isect(&ar1->winrct, &ar->winrct, NULL)) - break; + for (ar1 = ar->prev; ar1; ar1 = ar1->prev) { + if (ar1->overlap && ((ar1->alignment & RGN_SPLIT_PREV) == 0)) { + align1 = ar1->alignment; + if (BLI_rcti_isect(&ar1->winrct, &ar->winrct, NULL)) { + if (align1 != align) { + /* Left overlapping right or vice-versa, forbid this! */ + ar->flag |= RGN_FLAG_TOO_SMALL; + return; + } + /* Else, we have our previous region on same side. */ + break; + } } - ar1 = ar1->prev; } - + /* translate or close */ if (ar1) { - int align1 = ar1->alignment & ~RGN_SPLIT_PREV; - if (align1 == RGN_ALIGN_LEFT) { - if (ar->winrct.xmax + ar1->winx > sa->winx - U.widget_unit) + if (ar->winrct.xmax + ar1->winx > sa->winx - U.widget_unit) { ar->flag |= RGN_FLAG_TOO_SMALL; - else + return; + } + else { BLI_rcti_translate(&ar->winrct, ar1->winx, 0); + } } else if (align1 == RGN_ALIGN_RIGHT) { - if (ar->winrct.xmin - ar1->winx < U.widget_unit) + if (ar->winrct.xmin - ar1->winx < U.widget_unit) { ar->flag |= RGN_FLAG_TOO_SMALL; - else + return; + } + else { BLI_rcti_translate(&ar->winrct, -ar1->winx, 0); + } } } - - + /* At this point, 'ar' is in its final position and still open. + * Make a final check it does not overlap any previous 'other side' region. */ + for (ar1 = ar->prev; ar1; ar1 = ar1->prev) { + if (ar1->overlap && (ar1->alignment & RGN_SPLIT_PREV) == 0) { + if ((ar1->alignment != align) && BLI_rcti_isect(&ar1->winrct, &ar->winrct, NULL)) { + /* Left overlapping right or vice-versa, forbid this! */ + ar->flag |= RGN_FLAG_TOO_SMALL; + return; + } + } + } } /* overlapping regions only in the following restricted cases */ @@ -929,11 +950,11 @@ static bool region_is_overlap(wmWindow *win, ScrArea *sa, ARegion *ar) if (U.uiflag2 & USER_REGION_OVERLAP) { if (WM_is_draw_triple(win)) { if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ)) { - if (ELEM3(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS)) + if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS)) return 1; } else if (sa->spacetype == SPACE_IMAGE) { - if (ELEM4(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_PREVIEW)) + if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_PREVIEW)) return 1; } } @@ -1232,7 +1253,9 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand /* time space only has this keymap, the others get a boundbox restricted map */ if (sa->spacetype != SPACE_TIME) { ARegion *ar; - static rcti rect = {0, 10000, 0, 30}; /* same local check for all areas */ + /* same local check for all areas */ + static rcti rect = {0, 10000, 0, -1}; + rect.ymax = (30 * UI_DPI_FAC); ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); if (ar) { WM_event_add_keymap_handler_bb(handlers, keymap, &rect, &ar->winrct); @@ -1764,9 +1787,7 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char * break; } } - - BLI_SMALLSTACK_FREE(pt_stack); - + /* clear */ if (ar->overlap) { /* view should be in pixelspace */ diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 5d65bdfa11b..290923b2331 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -378,7 +378,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge) if (split == 0) return NULL; /* note regarding (fac > 0.5f) checks below. - * notmally it shouldn't matter which is used since the copy should match the original + * normally it shouldn't matter which is used since the copy should match the original * however with viewport rendering and python console this isn't the case. - campbell */ if (dir == 'h') { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 2ddda19fb28..7c7574b3af3 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -201,7 +201,7 @@ int ED_operator_animview_active(bContext *C) { if (ED_operator_areaactive(C)) { SpaceLink *sl = (SpaceLink *)CTX_wm_space_data(C); - if (sl && (ELEM5(sl->spacetype, SPACE_SEQ, SPACE_ACTION, SPACE_NLA, SPACE_IPO, SPACE_TIME))) + if (sl && (ELEM(sl->spacetype, SPACE_SEQ, SPACE_ACTION, SPACE_NLA, SPACE_IPO, SPACE_TIME))) return true; } @@ -3220,6 +3220,16 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws) } } + else if (regiontype == RGN_TYPE_CHANNELS) { + switch (spacetype) { + case SPACE_IPO: + case SPACE_ACTION: + case SPACE_NLA: + if (redraws & TIME_ALL_ANIM_WIN) + return 1; + break; + } + } else if (regiontype == RGN_TYPE_UI) { if (spacetype == SPACE_CLIP) { /* Track Preview button is on Properties Editor in SpaceClip, @@ -4154,7 +4164,8 @@ void ED_keymap_screen(wmKeyConfig *keyconf) /* dropbox for entire window */ lb = WM_dropboxmap_find("Window", 0, 0); WM_dropbox_add(lb, "WM_OT_open_mainfile", open_file_drop_poll, open_file_drop_copy); - + WM_dropbox_add(lb, "UI_OT_drop_color", UI_drop_color_poll, UI_drop_color_copy); + keymap_modal_set(keyconf); } diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 180f7d14c25..0fa5f2d9837 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -41,6 +41,7 @@ set(INC_SYS set(SRC paint_cursor.c + paint_curve.c paint_hide.c paint_image.c paint_image_2d.c diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index b1e4696cd02..7b9ede38b39 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -44,6 +44,7 @@ #include "BKE_brush.h" #include "BKE_context.h" +#include "BKE_curve.h" #include "BKE_image.h" #include "BKE_node.h" #include "BKE_paint.h" @@ -58,6 +59,8 @@ #include "ED_view3d.h" +#include "UI_resources.h" + #include "paint_intern.h" /* still needed for sculpt_stroke_get_location, should be * removed eventually (TODO) */ @@ -756,7 +759,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, int x, int y, float zoom, PaintMode mode) { /* color means that primary brush texture is colured and secondary is used for alpha/mask control */ - bool col = ELEM3(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX) ? true : false; + bool col = ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX) ? true : false; OverlayControlFlags flags = BKE_paint_get_overlay_flags(); /* save lots of GL state * TODO: check on whether all of these are needed? */ @@ -791,6 +794,138 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, glPopAttrib(); } + +BLI_INLINE void draw_tri_point(float *co, float width, bool selected) +{ + float w = width / 2.0f; + if (selected) + UI_ThemeColor4(TH_VERTEX_SELECT); + else + UI_ThemeColor4(TH_PAINT_CURVE_PIVOT); + + glLineWidth(3.0); + + glBegin(GL_LINE_LOOP); + glVertex2f(co[0], co[1] + w); + glVertex2f(co[0] - w, co[1] - w); + glVertex2f(co[0] + w, co[1] - w); + glEnd(); + + glColor4f(1.0, 1.0, 1.0, 0.5); + glLineWidth(1.0); + + glBegin(GL_LINE_LOOP); + glVertex2f(co[0], co[1] + w); + glVertex2f(co[0] - w, co[1] - w); + glVertex2f(co[0] + w, co[1] - w); + glEnd(); +} + +BLI_INLINE void draw_rect_point(float *co, float width, bool selected) +{ + float w = width / 2.0f; + if (selected) + UI_ThemeColor4(TH_VERTEX_SELECT); + else + UI_ThemeColor4(TH_PAINT_CURVE_HANDLE); + glLineWidth(3.0); + + glBegin(GL_LINE_LOOP); + glVertex2f(co[0] + w, co[1] + w); + glVertex2f(co[0] - w, co[1] + w); + glVertex2f(co[0] - w, co[1] - w); + glVertex2f(co[0] + w, co[1] - w); + glEnd(); + + glColor4f(1.0, 1.0, 1.0, 0.5); + glLineWidth(1.0); + + glBegin(GL_LINE_LOOP); + glVertex2f(co[0] + w, co[1] + w); + glVertex2f(co[0] - w, co[1] + w); + glVertex2f(co[0] - w, co[1] - w); + glVertex2f(co[0] + w, co[1] - w); + glEnd(); +} + + +BLI_INLINE void draw_bezier_handle_lines(BezTriple *bez) +{ + short line1[] = {0, 1}; + short line2[] = {1, 2}; + + glVertexPointer(2, GL_FLOAT, 3 * sizeof(float), bez->vec); + glColor4f(0.0, 0.0, 0.0, 0.5); + glLineWidth(3.0); + glDrawArrays(GL_LINE_STRIP, 0, 3); + + glLineWidth(1.0); + if (bez->f1 || bez->f2) + UI_ThemeColor4(TH_VERTEX_SELECT); + else + glColor4f(1.0, 1.0, 1.0, 0.5); + glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line1); + if (bez->f3 || bez->f2) + UI_ThemeColor4(TH_VERTEX_SELECT); + else + glColor4f(1.0, 1.0, 1.0, 0.5); + glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line2); +} + +static void paint_draw_curve_cursor(Brush *brush) +{ + if (brush->paint_curve && brush->paint_curve->points) { + int i; + PaintCurve *pc = brush->paint_curve; + PaintCurvePoint *cp = pc->points; + + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glEnableClientState(GL_VERTEX_ARRAY); + + /* draw the bezier handles and the curve segment between the current and next point */ + for (i = 0; i < pc->tot_points - 1; i++, cp++) { + int j; + PaintCurvePoint *cp_next = cp + 1; + float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2]; + /* use color coding to distinguish handles vs curve segments */ + draw_bezier_handle_lines(&cp->bez); + draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2); + draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2); + draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2); + + for (j = 0; j < 2; j++) + BKE_curve_forward_diff_bezier( + cp->bez.vec[1][j], + cp->bez.vec[2][j], + cp_next->bez.vec[0][j], + cp_next->bez.vec[1][j], + data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2])); + + glVertexPointer(2, GL_FLOAT, 0, data); + glLineWidth(3.0); + glColor4f(0.0, 0.0, 0.0, 0.5); + glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1); + + glLineWidth(1.0); + glColor4f(0.9, 0.9, 1.0, 0.5); + glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1); + } + + /* draw last line segment */ + draw_bezier_handle_lines(&cp->bez); + draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2); + draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2); + draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2); + + glLineWidth(1.0); + + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); + glDisableClientState(GL_VERTEX_ARRAY); + } +} + /* Special actions taken when paint cursor goes over mesh */ /* TODO: sculpt only for now */ static void paint_cursor_on_hit(UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, @@ -848,6 +983,12 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) zoomx = max_ff(zoomx, zoomy); mode = BKE_paintmode_get_active_from_context(C); + /* skip everything and draw brush here */ + if (brush->flag & BRUSH_CURVE) { + paint_draw_curve_cursor(brush); + return; + } + /* set various defaults */ translation[0] = x; translation[1] = y; @@ -857,8 +998,11 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* don't calculate rake angles while a stroke is active because the rake variables are global and * we may get interference with the stroke itself. For line strokes, such interference is visible */ - if (!ups->stroke_active && (brush->flag & BRUSH_RAKE)) - paint_calculate_rake_rotation(ups, translation); + if (!ups->stroke_active) { + if (brush->flag & BRUSH_RAKE) + /* here, translation contains the mouse coordinates. */ + paint_calculate_rake_rotation(ups, translation); + } /* draw overlay */ paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode); @@ -878,9 +1022,9 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* check if brush is subtracting, use different color then */ /* TODO: no way currently to know state of pen flip or * invert key modifier without starting a stroke */ - if ((!(brush->flag & BRUSH_INVERTED) ^ + if ((!(ups->draw_inverted) ^ !(brush->flag & BRUSH_DIR_IN)) && - ELEM5(brush->sculpt_tool, SCULPT_TOOL_DRAW, + ELEM(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE)) { @@ -890,12 +1034,12 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* only do if brush is over the mesh */ if (hit) paint_cursor_on_hit(ups, brush, &vc, location); + } - if (ups->draw_anchored) { - final_radius = ups->anchored_size; - translation[0] = ups->anchored_initial_mouse[0]; - translation[1] = ups->anchored_initial_mouse[1]; - } + if (ups->draw_anchored) { + final_radius = ups->anchored_size; + translation[0] = ups->anchored_initial_mouse[0]; + translation[1] = ups->anchored_initial_mouse[1]; } /* make lines pretty */ diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c new file mode 100644 index 00000000000..8c7c3b102e3 --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_curve.c @@ -0,0 +1,787 @@ +/* + * ***** 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/editors/sculpt_paint/paint_curve.c + * \ingroup edsculpt + */ + +#include <string.h> +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_paint.h" + +#include "BLI_math_vector.h" +#include "BLI_string.h" + +#include "ED_paint.h" +#include "ED_view3d.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_view2d.h" + +#include "paint_intern.h" + +#define PAINT_CURVE_SELECT_THRESHOLD 40.0f +#define PAINT_CURVE_POINT_SELECT(pcp, i) (*(&pcp->bez.f1 + i) = SELECT) + + +int paint_curve_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + Paint *p; + RegionView3D *rv3d = CTX_wm_region_view3d(C); + SpaceImage *sima; + + if (rv3d && !(ob && ((ob->mode & OB_MODE_ALL_PAINT) != 0))) + return false; + + sima = CTX_wm_space_image(C); + + if (sima && sima->mode != SI_MODE_PAINT) + return false; + + p = BKE_paint_get_active_from_context(C); + + if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) { + return true; + } + + return false; +} + +/* Paint Curve Undo*/ + +typedef struct UndoCurve { + struct UndoImageTile *next, *prev; + + PaintCurvePoint *points; /* points of curve */ + int tot_points; + int active_point; + + char idname[MAX_ID_NAME]; /* name instead of pointer*/ +} UndoCurve; + +static void paintcurve_undo_restore(bContext *C, ListBase *lb) +{ + Paint *p = BKE_paint_get_active_from_context(C); + UndoCurve *uc; + PaintCurve *pc = NULL; + + if (p->brush) { + pc = p->brush->paint_curve; + } + + if (!pc) + return; + + uc = (UndoCurve *)lb->first; + + if (strncmp(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname))) == 0) { + SWAP(PaintCurvePoint *, pc->points, uc->points); + SWAP(int, pc->tot_points, uc->tot_points); + SWAP(int, pc->add_index, uc->active_point); + } +} + +static void paintcurve_undo_delete(ListBase *lb) +{ + UndoCurve *uc; + uc = (UndoCurve *)lb->first; + + if (uc->points) + MEM_freeN(uc->points); + uc->points = NULL; +} + + +static void paintcurve_undo_begin(bContext *C, wmOperator *op, PaintCurve *pc) +{ + PaintMode mode = BKE_paintmode_get_active_from_context(C); + ListBase *lb = NULL; + int undo_stack_id; + UndoCurve *uc; + + switch (mode) { + case PAINT_TEXTURE_2D: + case PAINT_TEXTURE_PROJECTIVE: + undo_stack_id = UNDO_PAINT_IMAGE; + break; + + case PAINT_SCULPT: + undo_stack_id = UNDO_PAINT_MESH; + break; + + default: + /* do nothing, undo is handled by global */ + return; + } + + + ED_undo_paint_push_begin(undo_stack_id, op->type->name, + paintcurve_undo_restore, paintcurve_undo_delete, NULL); + lb = undo_paint_push_get_list(undo_stack_id); + + uc = MEM_callocN(sizeof(*uc), "Undo_curve"); + + lb->first = uc; + + BLI_strncpy(uc->idname, pc->id.name, sizeof(uc->idname)); + uc->tot_points = pc->tot_points; + uc->active_point = pc->add_index; + uc->points = MEM_dupallocN(pc->points); + + undo_paint_push_count_alloc(undo_stack_id, sizeof(*uc) + sizeof(*pc->points) * pc->tot_points); + + ED_undo_paint_push_end(undo_stack_id); +} +#define SEL_F1 (1 << 0) +#define SEL_F2 (1 << 1) +#define SEL_F3 (1 << 2) + +/* returns 0, 1, or 2 in point according to handle 1, pivot or handle 2 */ +static PaintCurvePoint *paintcurve_point_get_closest(PaintCurve *pc, const float pos[2], bool ignore_pivot, const float threshold, char *point) +{ + PaintCurvePoint *pcp, *closest = NULL; + int i; + float dist, closest_dist = FLT_MAX; + + for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) { + dist = len_manhattan_v2v2(pos, pcp->bez.vec[0]); + if (dist < threshold) { + if (dist < closest_dist) { + closest = pcp; + closest_dist = dist; + if (point) + *point = SEL_F1; + } + } + if (!ignore_pivot) { + dist = len_manhattan_v2v2(pos, pcp->bez.vec[1]); + if (dist < threshold) { + if (dist < closest_dist) { + closest = pcp; + closest_dist = dist; + if (point) + *point = SEL_F2; + } + } + } + dist = len_manhattan_v2v2(pos, pcp->bez.vec[2]); + if (dist < threshold) { + if (dist < closest_dist) { + closest = pcp; + closest_dist = dist; + if (point) + *point = SEL_F3; + } + } + } + + return closest; +} + +static int paintcurve_point_co_index(char sel) +{ + char i = 0; + while (sel != 1) { + sel >>= 1; + i++; + } + return i; +} + +/******************* Operators *********************************/ + +static int paintcurve_new_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Paint *p = BKE_paint_get_active_from_context(C); + Main *bmain = CTX_data_main(C); + + if (p && p->brush) { + p->brush->paint_curve = BKE_paint_curve_add(bmain, "PaintCurve"); + } + + return OPERATOR_FINISHED; +} + +void PAINTCURVE_OT_new(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add New Paint Curve"; + ot->description = "Add new paint curve"; + ot->idname = "PAINTCURVE_OT_new"; + + /* api callbacks */ + ot->exec = paintcurve_new_exec; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2]) +{ + Paint *p = BKE_paint_get_active_from_context(C); + Brush *br = p->brush; + Main *bmain = CTX_data_main(C); + PaintCurve *pc; + PaintCurvePoint *pcp; + wmWindow *window = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + float vec[3] = {loc[0], loc[1], 0.0}; + int add_index; + int i; + + pc = br->paint_curve; + if (!pc) { + br->paint_curve = pc = BKE_paint_curve_add(bmain, "PaintCurve"); + } + + paintcurve_undo_begin(C, op, pc); + + pcp = MEM_mallocN((pc->tot_points + 1) * sizeof(PaintCurvePoint), "PaintCurvePoint"); + add_index = pc->add_index; + + if (pc->points) { + if (add_index > 0) + memcpy(pcp, pc->points, add_index * sizeof(PaintCurvePoint)); + if (add_index < pc->tot_points) + memcpy(pcp + add_index + 1, pc->points + add_index, (pc->tot_points - add_index) * sizeof(PaintCurvePoint)); + + MEM_freeN(pc->points); + } + pc->points = pcp; + pc->tot_points++; + + /* initialize new point */ + memset(&pcp[add_index], 0, sizeof(PaintCurvePoint)); + copy_v3_v3(pcp[add_index].bez.vec[0], vec); + copy_v3_v3(pcp[add_index].bez.vec[1], vec); + copy_v3_v3(pcp[add_index].bez.vec[2], vec); + + /* last step, clear selection from all bezier handles expect the next */ + for (i = 0; i < pc->tot_points; i++) { + pcp[i].bez.f1 = pcp[i].bez.f2 = pcp[i].bez.f3 = 0; + } + pcp[add_index].bez.f3 = SELECT; + pcp[add_index].bez.h2 = HD_ALIGN; + + pc->add_index = add_index + 1; + + WM_paint_cursor_tag_redraw(window, ar); +} + + +static int paintcurve_add_point_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int loc[2] = {event->mval[0], event->mval[1]}; + paintcurve_point_add(C, op, loc); + RNA_int_set_array(op->ptr, "location", loc); + return OPERATOR_FINISHED; +} + +static int paintcurve_add_point_exec(bContext *C, wmOperator *op) +{ + int loc[2]; + + if (RNA_struct_property_is_set(op->ptr, "location")) { + RNA_int_get_array(op->ptr, "location", loc); + paintcurve_point_add(C, op, loc); + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +void PAINTCURVE_OT_add_point(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add New Paint Curve Point"; + ot->description = "Add new paint curve point"; + ot->idname = "PAINTCURVE_OT_add_point"; + + /* api callbacks */ + ot->invoke = paintcurve_add_point_invoke; + ot->exec = paintcurve_add_point_exec; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; + + /* properties */ + RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX, + "Location", "Location of vertex in area space", 0, SHRT_MAX); +} + +static int paintcurve_delete_point_exec(bContext *C, wmOperator *op) +{ + Paint *p = BKE_paint_get_active_from_context(C); + Brush *br = p->brush; + PaintCurve *pc; + PaintCurvePoint *pcp; + wmWindow *window = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + int i; + int tot_del = 0; + pc = br->paint_curve; + + if (!pc || pc->tot_points == 0) { + return OPERATOR_CANCELLED; + } + + paintcurve_undo_begin(C, op, pc); + +#define DELETE_TAG 2 + + for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) { + if ((pcp->bez.f1 & SELECT) || (pcp->bez.f2 & SELECT) || (pcp->bez.f3 & SELECT)) { + pcp->bez.f2 |= DELETE_TAG; + tot_del++; + } + } + + if (tot_del > 0) { + int j = 0; + int new_tot = pc->tot_points - tot_del; + PaintCurvePoint *points_new = NULL; + if (new_tot > 0) + points_new = MEM_mallocN(new_tot * sizeof(PaintCurvePoint), "PaintCurvePoint"); + + for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) { + if (!(pcp->bez.f2 & DELETE_TAG)) { + points_new[j] = pc->points[i]; + + if ((i + 1) == pc->add_index) { + pc->add_index = j + 1; + } + j++; + } + else if ((i + 1) == pc->add_index) { + /* prefer previous point */ + pc->add_index = j; + } + } + MEM_freeN(pc->points); + + pc->points = points_new; + pc->tot_points = new_tot; + } + +#undef DELETE_TAG + + WM_paint_cursor_tag_redraw(window, ar); + + return OPERATOR_FINISHED; +} + + +void PAINTCURVE_OT_delete_point(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add New Paint Curve Point"; + ot->description = "Add new paint curve point"; + ot->idname = "PAINTCURVE_OT_delete_point"; + + /* api callbacks */ + ot->exec = paintcurve_delete_point_exec; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; +} + + +static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2], bool toggle, bool extend) +{ + wmWindow *window = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + Paint *p = BKE_paint_get_active_from_context(C); + Brush *br = p->brush; + PaintCurve *pc; + PaintCurvePoint *pcp; + int i; + const float loc_fl[2] = {UNPACK2(loc)}; + + pc = br->paint_curve; + + if (!pc) + return false; + + paintcurve_undo_begin(C, op, pc); + + pcp = pc->points; + + if (toggle) { + char select = 0; + bool selected = false; + + for (i = 0; i < pc->tot_points; i++) { + if (pcp[i].bez.f1 || pcp[i].bez.f2 || pcp[i].bez.f3) { + selected = true; + break; + } + } + + if (!selected) { + select = SELECT; + } + + for (i = 0; i < pc->tot_points; i++) { + pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = select; + } + } + else { + PaintCurvePoint *pcp; + char selflag; + + pcp = paintcurve_point_get_closest(pc, loc_fl, false, PAINT_CURVE_SELECT_THRESHOLD, &selflag); + + if (pcp) { + pc->add_index = (pcp - pc->points) + 1; + + if (selflag == SEL_F2) { + if (extend) + pcp->bez.f2 ^= SELECT; + else + pcp->bez.f2 |= SELECT; + } + else if (selflag == SEL_F1) { + if (extend) + pcp->bez.f1 ^= SELECT; + else + pcp->bez.f1 |= SELECT; + } + else if (selflag == SEL_F3) { + if (extend) + pcp->bez.f3 ^= SELECT; + else + pcp->bez.f3 |= SELECT; + } + } + + /* clear selection for unselected points if not extending and if a point has been selected */ + if (!extend && pcp) { + for (i = 0; i < pc->tot_points; i++) { + pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = 0; + + if ((pc->points + i) == pcp) { + char index = paintcurve_point_co_index(selflag); + PAINT_CURVE_POINT_SELECT(pcp, index); + } + } + } + + if (!pcp) + return false; + } + + WM_paint_cursor_tag_redraw(window, ar); + + return true; +} + + +static int paintcurve_select_point_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int loc[2] = {UNPACK2(event->mval)}; + bool toggle = RNA_boolean_get(op->ptr, "toggle"); + bool extend = RNA_boolean_get(op->ptr, "extend"); + if (paintcurve_point_select(C, op, loc, toggle, extend)) { + RNA_int_set_array(op->ptr, "location", loc); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int paintcurve_select_point_exec(bContext *C, wmOperator *op) +{ + int loc[2]; + + if (RNA_struct_property_is_set(op->ptr, "location")) { + bool toggle = RNA_boolean_get(op->ptr, "toggle"); + bool extend = RNA_boolean_get(op->ptr, "extend"); + RNA_int_get_array(op->ptr, "location", loc); + if (paintcurve_point_select(C, op, loc, toggle, extend)) + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +void PAINTCURVE_OT_select(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Select Paint Curve Point"; + ot->description = "Select a paint curve point"; + ot->idname = "PAINTCURVE_OT_select"; + + /* api callbacks */ + ot->invoke = paintcurve_select_point_invoke; + ot->exec = paintcurve_select_point_exec; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; + + /* properties */ + RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX, + "Location", "Location of vertex in area space", 0, SHRT_MAX); + prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle", "(De)select all"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +typedef struct PointSlideData { + PaintCurvePoint *pcp; + char select; + int initial_loc[2]; + float point_initial_loc[3][2]; + int event; + bool align; +} PointSlideData; + +static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Paint *p = BKE_paint_get_active_from_context(C); + const float loc_fl[2] = {UNPACK2(event->mval)}; + char select; + int i; + bool do_select = RNA_boolean_get(op->ptr, "select"); + bool align = RNA_boolean_get(op->ptr, "align"); + Brush *br = p->brush; + PaintCurve *pc = br->paint_curve; + PaintCurvePoint *pcp; + + if (!pc) + return OPERATOR_PASS_THROUGH; + + if (do_select) { + pcp = paintcurve_point_get_closest(pc, loc_fl, align, PAINT_CURVE_SELECT_THRESHOLD, &select); + } + else { + pcp = NULL; + /* just find first selected point */ + for (i = 0; i < pc->tot_points; i++) { + if (pc->points[i].bez.f1 || pc->points[i].bez.f2 || pc->points[i].bez.f3) { + pcp = &pc->points[i]; + select = SEL_F3; + break; + } + } + } + + + if (pcp) { + ARegion *ar = CTX_wm_region(C); + wmWindow *window = CTX_wm_window(C); + PointSlideData *psd = MEM_mallocN(sizeof(PointSlideData), "PointSlideData"); + copy_v2_v2_int(psd->initial_loc, event->mval); + psd->event = event->type; + psd->pcp = pcp; + psd->select = paintcurve_point_co_index(select); + for (i = 0; i < 3; i++) { + copy_v2_v2(psd->point_initial_loc[i], pcp->bez.vec[i]); + } + psd->align = align; + op->customdata = psd; + + if (do_select) + paintcurve_undo_begin(C, op, pc); + + /* first, clear all selection from points */ + for (i = 0; i < pc->tot_points; i++) + pc->points[i].bez.f1 = pc->points[i].bez.f3 = pc->points[i].bez.f2 = 0; + + /* only select the active point */ + PAINT_CURVE_POINT_SELECT(pcp, psd->select); + pc->add_index = (pcp - pc->points) + 1; + + WM_event_add_modal_handler(C, op); + WM_paint_cursor_tag_redraw(window, ar); + return OPERATOR_RUNNING_MODAL; + } + + return OPERATOR_PASS_THROUGH; +} + +static int paintcurve_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + PointSlideData *psd = op->customdata; + + if (event->type == psd->event && event->val == KM_RELEASE) { + MEM_freeN(psd); + return OPERATOR_FINISHED; + } + + switch (event->type) { + case MOUSEMOVE: + { + ARegion *ar = CTX_wm_region(C); + wmWindow *window = CTX_wm_window(C); + float diff[2] = {event->mval[0] - psd->initial_loc[0], + event->mval[1] - psd->initial_loc[1]}; + if (psd->select == 1) { + int i; + for (i = 0; i < 3; i++) + add_v2_v2v2(psd->pcp->bez.vec[i], diff, psd->point_initial_loc[i]); + } + else { + add_v2_v2(diff, psd->point_initial_loc[psd->select]); + copy_v2_v2(psd->pcp->bez.vec[psd->select], diff); + + if (psd->align) { + char opposite = (psd->select == 0) ? 2 : 0; + sub_v2_v2v2(diff, psd->pcp->bez.vec[1], psd->pcp->bez.vec[psd->select]); + add_v2_v2v2(psd->pcp->bez.vec[opposite], psd->pcp->bez.vec[1], diff); + } + } + WM_paint_cursor_tag_redraw(window, ar); + break; + } + default: + break; + } + + return OPERATOR_RUNNING_MODAL; +} + + +void PAINTCURVE_OT_slide(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Slide Paint Curve Point"; + ot->description = "Select and slide paint curve point"; + ot->idname = "PAINTCURVE_OT_slide"; + + /* api callbacks */ + ot->invoke = paintcurve_slide_invoke; + ot->modal = paintcurve_slide_modal; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "align", false, "Align Handles", "Aligns opposite point handle during transform"); + RNA_def_boolean(ot->srna, "select", true, "Select", "Attempt to select a point handle before transform"); +} + +static int paintcurve_draw_exec(bContext *C, wmOperator *UNUSED(op)) +{ + PaintMode mode = BKE_paintmode_get_active_from_context(C); + const char *name; + + switch (mode) { + case PAINT_TEXTURE_2D: + case PAINT_TEXTURE_PROJECTIVE: + name = "PAINT_OT_image_paint"; + break; + case PAINT_WEIGHT: + name = "PAINT_OT_weight_paint"; + break; + case PAINT_VERTEX: + name = "PAINT_OT_vertex_paint"; + break; + case PAINT_SCULPT: + name = "SCULPT_OT_brush_stroke"; + break; + default: + return OPERATOR_PASS_THROUGH; + } + + return WM_operator_name_call(C, name, WM_OP_INVOKE_DEFAULT, NULL); +} + +void PAINTCURVE_OT_draw(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Draw Curve"; + ot->description = "Draw curve"; + ot->idname = "PAINTCURVE_OT_draw"; + + /* api callbacks */ + ot->exec = paintcurve_draw_exec; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; +} + +static int paintcurve_cursor_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + PaintMode mode = BKE_paintmode_get_active_from_context(C); + + switch (mode) { + case PAINT_TEXTURE_2D: + { + ARegion *ar = CTX_wm_region(C); + SpaceImage *sima = CTX_wm_space_image(C); + float location[2]; + + if (!sima) + return OPERATOR_CANCELLED; + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]); + copy_v2_v2(sima->cursor, location); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL); + break; + } + default: + ED_view3d_cursor3d_update(C, event->mval); + break; + } + + return OPERATOR_FINISHED; +} + +void PAINTCURVE_OT_cursor(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Place Cursor"; + ot->description = "Place cursor"; + ot->idname = "PAINTCURVE_OT_cursor"; + + /* api callbacks */ + ot->invoke = paintcurve_cursor_invoke; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = 0; +} diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 34232c51ff7..ebfb17d25ef 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -43,6 +43,7 @@ #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_threads.h" #include "PIL_time.h" @@ -59,9 +60,14 @@ #include "BKE_brush.h" #include "BKE_image.h" #include "BKE_main.h" +#include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_node.h" #include "BKE_paint.h" +#include "BKE_report.h" +#include "BKE_scene.h" +#include "BKE_texture.h" +#include "BKE_colortools.h" #include "BKE_editmesh.h" @@ -82,6 +88,9 @@ #include "GPU_draw.h" +#include "BIF_gl.h" +#include "BIF_glutil.h" + #include "IMB_colormanagement.h" #include "paint_intern.h" @@ -102,14 +111,27 @@ typedef struct UndoImageTile { int x, y; + Image *ima; short source, use_float; char gen_type; + bool valid; } UndoImageTile; /* this is a static resource for non-globality, * Maybe it should be exposed as part of the * paint operation, but for now just give a public interface */ static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0}; +static SpinLock undolock; + +void image_undo_init_locks(void) +{ + BLI_spin_init(&undolock); +} + +void image_undo_end_locks(void) +{ + BLI_spin_end(&undolock); +} ImagePaintPartialRedraw *get_imapaintpartial(void) { @@ -122,26 +144,53 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr) } /* UNDO */ +typedef enum { + COPY = 0, + RESTORE = 1, + RESTORE_COPY = 2 +} CopyMode; -static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore) +static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode) { - /* copy or swap contents of tile->rect and region in ibuf->rect */ - IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE, - tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); + if (mode == COPY) { + /* copy or swap contents of tile->rect and region in ibuf->rect */ + IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE, + tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); - if (ibuf->rect_float) { - SWAP(float *, tmpibuf->rect_float, tile->rect.fp); + if (ibuf->rect_float) { + SWAP(float *, tmpibuf->rect_float, tile->rect.fp); + } + else { + SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); + } } else { - SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); - } - - if (restore) + if (mode == RESTORE_COPY) + IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE, + tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); + /* swap to the tmpbuf for easy copying */ + if (ibuf->rect_float) { + SWAP(float *, tmpibuf->rect_float, tile->rect.fp); + } + else { + SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); + } + IMB_rectcpy(ibuf, tmpibuf, tile->x * IMAPAINT_TILE_SIZE, tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); + + if (mode == RESTORE) { + if (ibuf->rect_float) { + SWAP(float *, tmpibuf->rect_float, tile->rect.fp); + } + else { + SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); + } + } + } } -void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask) +void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate) { ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); UndoImageTile *tile; @@ -160,6 +209,8 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi *mask = tile->mask; } + if (validate) + tile->valid = true; return tile->rect.pt; } @@ -170,7 +221,7 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi return NULL; } -void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile) +void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj) { ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); UndoImageTile *tile; @@ -179,10 +230,14 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, void *data; /* check if tile is already pushed */ - data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, NULL); - if (data) - return data; - + + /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */ + if (!proj) { + data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true); + if (data) + return data; + } + if (*tmpibuf == NULL) *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect); @@ -191,6 +246,11 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, tile->x = x_tile; tile->y = y_tile; + /* add mask explicitly here */ + if (mask) + *mask = tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, + "UndoImageTile.mask"); + allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char); tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect"); @@ -200,12 +260,23 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, tile->gen_type = ima->gen_type; tile->source = ima->source; tile->use_float = use_float; + tile->valid = true; + tile->ima = ima; - undo_copy_tile(tile, *tmpibuf, ibuf, 0); - undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize); + if (valid) + *valid = &tile->valid; + undo_copy_tile(tile, *tmpibuf, ibuf, COPY); + + if (proj) + BLI_spin_lock(&undolock); + + undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize); BLI_addtail(lb, tile); - + + if (proj) + BLI_spin_unlock(&undolock); + return tile->rect.pt; } @@ -222,6 +293,33 @@ void image_undo_remove_masks(void) } } +static void image_undo_restore_runtime(ListBase *lb) +{ + ImBuf *ibuf, *tmpibuf; + UndoImageTile *tile; + + tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, + IB_rectfloat | IB_rect); + + for (tile = lb->first; tile; tile = tile->next) { + Image *ima = tile->ima; + ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + + undo_copy_tile(tile, tmpibuf, ibuf, RESTORE); + + GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */ + if (ibuf->rect_float) + ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ + if (ibuf->mipmap[0]) + ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */ + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + + BKE_image_release_ibuf(ima, ibuf, NULL); + } + + IMB_freeImBuf(tmpibuf); +} + void ED_image_undo_restore(bContext *C, ListBase *lb) { Main *bmain = CTX_data_main(C); @@ -247,7 +345,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb) if (ima && ibuf && strcmp(tile->ibufname, ibuf->name) != 0) { /* current ImBuf filename was changed, probably current frame - * was changed when paiting on image sequence, rather than storing + * was changed when painting on image sequence, rather than storing * full image user (which isn't so obvious, btw) try to find ImBuf with * matched file name in list of already loaded images */ @@ -273,7 +371,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb) continue; } - undo_copy_tile(tile, tmpibuf, ibuf, 1); + undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY); GPU_free_image(ima); /* force OpenGL reload */ if (ibuf->rect_float) @@ -282,6 +380,8 @@ void ED_image_undo_restore(bContext *C, ListBase *lb) ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + DAG_id_tag_update(&ima->id, 0); + BKE_image_release_ibuf(ima, ibuf, NULL); } @@ -296,6 +396,42 @@ void ED_image_undo_free(ListBase *lb) MEM_freeN(tile->rect.pt); } +static void image_undo_end(void) +{ + ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); + UndoImageTile *tile; + int deallocsize = 0; + int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; + + /* first dispose of invalid tiles (may happen due to drag dot for instance) */ + for (tile = lb->first; tile;) { + if (!tile->valid) { + UndoImageTile *tmp_tile = tile->next; + deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char)); + MEM_freeN(tile->rect.pt); + BLI_freelinkN (lb, tile); + tile = tmp_tile; + } + else { + tile = tile->next; + } + } + + /* don't forget to remove the size of deallocated tiles */ + undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, -deallocsize); + + ED_undo_paint_push_end(UNDO_PAINT_IMAGE); +} + +static void image_undo_invalidate(void) +{ + UndoImageTile *tile; + ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); + + for (tile = lb->first; tile; tile = tile->next) + tile->valid = false; +} + /* Imagepaint Partial Redraw & Dirty Region */ void ED_imapaint_clear_partial_redraw(void) @@ -344,7 +480,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int for (ty = tiley; ty <= tileh; ty++) for (tx = tilex; tx <= tilew; tx++) - image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty); + image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false); ibuf->userflags |= IB_BITMAPDIRTY; @@ -373,6 +509,76 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te } } +/* paint blur kernels. Projective painting enforces use of a 2x2 kernel due to lagging */ +BlurKernel *paint_new_blur_kernel(Brush *br, bool proj) +{ + int i, j; + BlurKernel *kernel = MEM_mallocN(sizeof(BlurKernel), "blur kernel"); + float radius; + int side; + BlurKernelType type = br->blur_mode; + + if (proj) { + radius = 0.5f; + + side = kernel->side = 2; + kernel->side_squared = kernel->side * kernel->side; + kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data"); + kernel->pixel_len = radius; + } + else { + radius = br->blur_kernel_radius; + + side = kernel->side = radius * 2 + 1; + kernel->side_squared = kernel->side * kernel->side; + kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data"); + kernel->pixel_len = br->blur_kernel_radius; + } + + switch (type) { + case KERNEL_BOX: + for (i = 0; i < kernel->side_squared; i++) + kernel->wdata[i] = 1.0; + break; + + case KERNEL_GAUSSIAN: + { + /* at standard deviation of 3.0 kernel is at about zero */ + float standard_dev = radius / 3.0f; + + /* make the necessary adjustment to the value for use in the normal distribution formula */ + standard_dev = standard_dev * standard_dev * 2; + + for (i = 0; i < side; i++) { + for (j = 0; j < side; j++) { + float idist = radius - i; + float jdist = radius - j; + float value = exp((idist * idist + jdist * jdist) / standard_dev); + + kernel->wdata[i + j * side] = value; + } + } + + break; + } + + default: + printf("unidentified kernel type, aborting\n"); + MEM_freeN(kernel->wdata); + MEM_freeN(kernel); + return NULL; + break; + } + + return kernel; +} + +void paint_delete_blur_kernel(BlurKernel *kernel) +{ + if (kernel->wdata) + MEM_freeN(kernel->wdata); +} + /************************ image paint poll ************************/ static Brush *image_paint_brush(bContext *C) @@ -432,11 +638,57 @@ typedef struct PaintOperation { void *custom_paint; float prevmouse[2]; + float startmouse[2]; double starttime; + void *cursor; ViewContext vc; } PaintOperation; +bool paint_use_opacity_masking(Brush *brush) +{ + return (brush->flag & BRUSH_AIRBRUSH) || + (brush->flag & BRUSH_DRAG_DOT) || + (brush->flag & BRUSH_ANCHORED) || + (brush->imagepaint_tool == PAINT_TOOL_SMEAR) || + (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) || + (brush->imagepaint_tool == PAINT_TOOL_FILL) || + (brush->flag & BRUSH_USE_GRADIENT) || + (brush->mtex.tex && !ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)) ? + false : true; +} + +void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, + float pressure, float color[3], struct ColorManagedDisplay *display) +{ + if (invert) + copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br)); + else { + if (br->flag & BRUSH_USE_GRADIENT) { + switch (br->gradient_stroke_mode) { + case BRUSH_GRADIENT_PRESSURE: + do_colorband(br->gradient, pressure, color); + break; + case BRUSH_GRADIENT_SPACING_REPEAT: + { + float coord = fmod(distance / br->gradient_spacing, 1.0); + do_colorband(br->gradient, coord, color); + break; + } + case BRUSH_GRADIENT_SPACING_CLAMP: + { + do_colorband(br->gradient, distance / br->gradient_spacing, color); + break; + } + } + } + else + copy_v3_v3(color, BKE_brush_color_get(scene, br)); + } + if (color_correction) + IMB_colormanagement_display_to_scene_linear_v3(color, display); +} + void paint_brush_init_tex(Brush *brush) { /* init mtex nodes */ @@ -462,26 +714,54 @@ void paint_brush_exit_tex(Brush *brush) } } +static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customdata) +{ + PaintOperation *pop = (PaintOperation *)customdata; + + if (pop) { + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + + glLineWidth(4.0); + glColor4ub(0, 0, 0, 255); + sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]); + glLineWidth(2.0); + glColor4ub(255, 255, 255, 255); + sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]); + glLineWidth(1.0); + + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); + } +} -static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, float mouse[2]) + +static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const float mouse[2]) { Scene *scene = CTX_data_scene(C); ToolSettings *settings = scene->toolsettings; PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */ + Brush *brush = BKE_paint_brush(&settings->imapaint.paint); int mode = RNA_enum_get(op->ptr, "mode"); view3d_set_viewcontext(C, &pop->vc); - pop->prevmouse[0] = mouse[0]; - pop->prevmouse[1] = mouse[1]; + copy_v2_v2(pop->prevmouse, mouse); + copy_v2_v2(pop->startmouse, mouse); + + if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) { + pop->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), image_paint_poll, gradient_draw_line, pop); + } /* initialize from context */ if (CTX_wm_region_view3d(C)) { + Object *ob = OBACT; + paint_proj_mesh_data_ensure(C, ob, op); pop->mode = PAINT_MODE_3D_PROJECT; - pop->custom_paint = paint_proj_new_stroke(C, OBACT, pop->prevmouse, mode); + pop->custom_paint = paint_proj_new_stroke(C, ob, mouse, mode); } else { pop->mode = PAINT_MODE_2D; - pop->custom_paint = paint_2d_new_stroke(C, op); + pop->custom_paint = paint_2d_new_stroke(C, op, mode); } if (!pop->custom_paint) { @@ -491,52 +771,69 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, float mou settings->imapaint.flag |= IMAGEPAINT_DRAWING; ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, - ED_image_undo_restore, ED_image_undo_free); - - { - UnifiedPaintSettings *ups = &settings->unified_paint_settings; - ups->stroke_active = true; - } + ED_image_undo_restore, ED_image_undo_free, NULL); return pop; } +/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/ +static void paint_stroke_restore(void) +{ + ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); + image_undo_restore_runtime(lb); + image_undo_invalidate(); +} + static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) { PaintOperation *pop = paint_stroke_mode_data(stroke); Scene *scene = CTX_data_scene(C); - Brush *brush = BKE_paint_brush(&scene->toolsettings->imapaint.paint); + ToolSettings *toolsettings = CTX_data_tool_settings(C); + UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings; + Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint); + + float alphafac = (brush->flag & BRUSH_ACCUMULATE) ? ups->overlap_factor : 1.0f; /* initial brush values. Maybe it should be considered moving these to stroke system */ - float startsize = (float)BKE_brush_size_get(scene, brush); float startalpha = BKE_brush_alpha_get(scene, brush); float mouse[2]; float pressure; + float size; + float distance = paint_stroke_distance_get(stroke); int eraser; RNA_float_get_array(itemptr, "mouse", mouse); pressure = RNA_float_get(itemptr, "pressure"); eraser = RNA_boolean_get(itemptr, "pen_flip"); + size = max_ff(1.0f, RNA_float_get(itemptr, "size")); + + /* stroking with fill tool only acts on stroke end */ + if (brush->imagepaint_tool == PAINT_TOOL_FILL) { + copy_v2_v2(pop->prevmouse, mouse); + return; + } if (BKE_brush_use_alpha_pressure(scene, brush)) - BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure)); - if (BKE_brush_use_size_pressure(scene, brush)) - BKE_brush_size_set(scene, brush, (int)max_ff(1.0f, startsize * pressure)); + BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure * alphafac)); + else + BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * alphafac)); + + if ((brush->flag & BRUSH_DRAG_DOT) || (brush->flag & BRUSH_ANCHORED)) { + paint_stroke_restore(); + } if (pop->mode == PAINT_MODE_3D_PROJECT) { - paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse); + paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse, eraser, pressure, distance, size); } else { - paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser); + paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser, pressure, distance, size); } - pop->prevmouse[0] = mouse[0]; - pop->prevmouse[1] = mouse[1]; + copy_v2_v2(pop->prevmouse, mouse); /* restore brush values */ BKE_brush_alpha_set(scene, brush, startalpha); - BKE_brush_size_set(scene, brush, startsize); } static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, bool final) @@ -554,11 +851,41 @@ static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, b static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke) { Scene *scene = CTX_data_scene(C); - ToolSettings *settings = scene->toolsettings; + ToolSettings *toolsettings = scene->toolsettings; PaintOperation *pop = paint_stroke_mode_data(stroke); + Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint); - settings->imapaint.flag &= ~IMAGEPAINT_DRAWING; + toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING; + + if (brush->imagepaint_tool == PAINT_TOOL_FILL) { + if (brush->flag & BRUSH_USE_GRADIENT) { + if (pop->mode == PAINT_MODE_2D) { + paint_2d_gradient_fill(C, brush, pop->startmouse, pop->prevmouse, pop->custom_paint); + } + else { + paint_proj_stroke(C, pop->custom_paint, pop->startmouse, pop->prevmouse, paint_stroke_flipped(stroke), + 1.0, 0.0, BKE_brush_size_get(scene, brush)); + /* two redraws, one for GPU update, one for notification */ + paint_proj_redraw(C, pop->custom_paint, false); + paint_proj_redraw(C, pop->custom_paint, true); + } + } + else { + if (pop->mode == PAINT_MODE_2D) { + float color[3]; + srgb_to_linearrgb_v3_v3(color, BKE_brush_color_get(scene, brush)); + paint_2d_bucket_fill(C, color, brush, pop->prevmouse, pop->custom_paint); + } + else { + paint_proj_stroke(C, pop->custom_paint, pop->startmouse, pop->prevmouse, paint_stroke_flipped(stroke), + 1.0, 0.0, BKE_brush_size_get(scene, brush)); + /* two redraws, one for GPU update, one for notification */ + paint_proj_redraw(C, pop->custom_paint, false); + paint_proj_redraw(C, pop->custom_paint, true); + } + } + } if (pop->mode == PAINT_MODE_3D_PROJECT) { paint_proj_stroke_done(pop->custom_paint); } @@ -566,7 +893,11 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke) paint_2d_stroke_done(pop->custom_paint); } - ED_undo_paint_push_end(UNDO_PAINT_IMAGE); + if (pop->cursor) { + WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor); + } + + image_undo_end(); /* duplicate warning, see texpaint_init */ #if 0 @@ -576,43 +907,41 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke) BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted: %s", pop->s.warnpackedfile); #endif MEM_freeN(pop); - - { - UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; - ups->stroke_active = false; - } } -static bool paint_stroke_test_start(bContext *UNUSED(C), wmOperator *UNUSED(op), const float UNUSED(mouse[2])) -{ - return true; -} - - -static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static bool paint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2]) { PaintOperation *pop; - float mouse[2]; - int retval; /* TODO Should avoid putting this here. Instead, last position should be requested * from stroke system. */ - mouse[0] = event->mval[0]; - mouse[1] = event->mval[1]; if (!(pop = texture_paint_init(C, op, mouse))) { - return OPERATOR_CANCELLED; + return false; } - op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start, + paint_stroke_set_mode_data(op->customdata, pop); + + return true; +} + + +static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int retval; + + op->customdata = paint_stroke_new(C, op, NULL, paint_stroke_test_start, paint_stroke_update_step, paint_stroke_redraw, paint_stroke_done, event->type); - paint_stroke_set_mode_data(op->customdata, pop); + + if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { + paint_stroke_data_free(op); + return OPERATOR_FINISHED; + } /* add modal handler */ WM_event_add_modal_handler(C, op); - retval = op->type->modal(C, op, event); OPERATOR_RETVAL_CHECK(retval); BLI_assert(retval == OPERATOR_RUNNING_MODAL); @@ -637,12 +966,10 @@ static int paint_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, NULL, paint_stroke_test_start, paint_stroke_update_step, paint_stroke_redraw, paint_stroke_done, 0); - paint_stroke_set_mode_data(op->customdata, pop); - /* frees op->customdata */ paint_stroke_exec(C, op); @@ -651,12 +978,6 @@ static int paint_exec(bContext *C, wmOperator *op) void PAINT_OT_image_paint(wmOperatorType *ot) { - static EnumPropertyItem stroke_mode_items[] = { - {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally"}, - {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"}, - {0} - }; - /* identifiers */ ot->name = "Image Paint"; ot->idname = "PAINT_OT_image_paint"; @@ -672,11 +993,7 @@ void PAINT_OT_image_paint(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING; - RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, - "Paint Stroke Mode", - "Action taken when a paint stroke is made"); - - RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); + paint_stroke_operator_properties(ot); } @@ -686,9 +1003,9 @@ int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy) if (!rv3d) { SpaceImage *sima = CTX_wm_space_image(C); - ARegion *ar = CTX_wm_region(C); if (sima->mode == SI_MODE_PAINT) { + ARegion *ar = CTX_wm_region(C); ED_space_image_get_zoom(sima, ar, zoomx, zoomy); return 1; @@ -847,17 +1164,39 @@ void PAINT_OT_grab_clone(wmOperatorType *ot) typedef struct { bool show_cursor; short event_type; -} SampleColorData; + float initcolor[3]; + bool sample_palette; +} SampleColorData; + + +static void sample_color_update_header(SampleColorData *data, bContext *C) +{ +#define HEADER_LENGTH 150 + char msg[HEADER_LENGTH]; + ScrArea *sa = CTX_wm_area(C); + + if (sa) { + BLI_snprintf(msg, HEADER_LENGTH, + "Sample color for %s", + !data->sample_palette ? + "Brush. Use Left Click to sample for palette instead" : + "Palette. Use Left Click to sample more colors"); + ED_area_headerprint(sa, msg); + } + +#undef HEADER_LENGTH +} static int sample_color_exec(bContext *C, wmOperator *op) { Paint *paint = BKE_paint_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); + PaintMode mode = BKE_paintmode_get_active_from_context(C); ARegion *ar = CTX_wm_region(C); wmWindow *win = CTX_wm_window(C); bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0); int location[2]; - + bool use_palette; paint->flags &= ~PAINT_SHOW_BRUSH; /* force redraw without cursor */ @@ -865,7 +1204,9 @@ static int sample_color_exec(bContext *C, wmOperator *op) WM_redraw_windows(C); RNA_int_get_array(op->ptr, "location", location); - paint_sample_color(C, ar, location[0], location[1]); + use_palette = RNA_boolean_get(op->ptr, "palette"); + + paint_sample_color(C, ar, location[0], location[1], mode == PAINT_TEXTURE_PROJECTIVE, use_palette); if (show_cursor) { paint->flags |= PAINT_SHOW_BRUSH; @@ -878,7 +1219,9 @@ static int sample_color_exec(bContext *C, wmOperator *op) static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + Scene *scene = CTX_data_scene(C); Paint *paint = BKE_paint_get_active_from_context(C); + PaintMode mode = BKE_paintmode_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); SampleColorData *data = MEM_mallocN(sizeof(SampleColorData), "sample color custom data"); ARegion *ar = CTX_wm_region(C); @@ -886,18 +1229,24 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event data->event_type = event->type; data->show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0); + copy_v3_v3(data->initcolor, BKE_brush_color_get(scene, brush)); + data->sample_palette = false; op->customdata = data; paint->flags &= ~PAINT_SHOW_BRUSH; + sample_color_update_header(data, C); + + WM_event_add_modal_handler(C, op); + /* force redraw without cursor */ WM_paint_cursor_tag_redraw(win, ar); WM_redraw_windows(C); RNA_int_set_array(op->ptr, "location", event->mval); - paint_sample_color(C, ar, event->mval[0], event->mval[1]); + + paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false); WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR); - WM_event_add_modal_handler(C, op); WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); return OPERATOR_RUNNING_MODAL; @@ -905,17 +1254,27 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event) { + Scene *scene = CTX_data_scene(C); SampleColorData *data = op->customdata; Paint *paint = BKE_paint_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); + PaintMode mode = BKE_paintmode_get_active_from_context(C); if ((event->type == data->event_type) && (event->val == KM_RELEASE)) { + ScrArea *sa = CTX_wm_area(C); + if (data->show_cursor) { paint->flags |= PAINT_SHOW_BRUSH; } + if (data->sample_palette) { + BKE_brush_color_set(scene, brush, data->initcolor); + RNA_boolean_set(op->ptr, "palette", true); + } WM_cursor_modal_restore(CTX_wm_window(C)); MEM_freeN(data); + ED_area_headerprint(sa, NULL); + return OPERATOR_FINISHED; } @@ -924,10 +1283,22 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); RNA_int_set_array(op->ptr, "location", event->mval); - paint_sample_color(C, ar, event->mval[0], event->mval[1]); + paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false); WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); break; } + + case LEFTMOUSE: + if (event->val == KM_PRESS) { + ARegion *ar = CTX_wm_region(C); + RNA_int_set_array(op->ptr, "location", event->mval); + paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, true); + if (!data->sample_palette) { + data->sample_palette = true; + sample_color_update_header(data, C); + } + } + break; } return OPERATOR_RUNNING_MODAL; @@ -956,6 +1327,7 @@ void PAINT_OT_sample_color(wmOperatorType *ot) /* properties */ RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "Cursor location in region coordinates", 0, 16384); + RNA_def_boolean(ot->srna, "palette", 0, "Palette", "Add color to palette"); } /******************** texture paint toggle operator ********************/ @@ -979,7 +1351,6 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) Object *ob = CTX_data_active_object(C); 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)) { @@ -987,8 +1358,6 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) } } - me = BKE_mesh_from_object(ob); - if (ob->mode & mode_flag) { ob->mode &= ~mode_flag; @@ -999,11 +1368,43 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) toggle_paint_cursor(C, 0); } else { - ob->mode |= mode_flag; + bScreen *sc; + Main *bmain = CTX_data_main(C); + Image *ima = NULL; + ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; + + /* This has to stay here to regenerate the texture paint + * cache in case we are loading a file */ + BKE_texpaint_slots_refresh_object(scene, ob); - if (me->mtface == NULL) - me->mtface = CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT, - NULL, me->totface); + paint_proj_mesh_data_ensure(C, ob, op); + + /* entering paint mode also sets image to editors */ + if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) { + Material *ma = give_current_material(ob, ob->actcol); /* set the current material active paint slot on image editor */ + + if (ma->texpaintslot) + ima = ma->texpaintslot[ma->paint_active_slot].ima; + } + else if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) { + ima = imapaint->canvas; + } + + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + ScrArea *sa; + for (sa = sc->areabase.first; sa; sa = sa->next) { + SpaceLink *sl; + for (sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_IMAGE) { + SpaceImage *sima = (SpaceImage *)sl; + + ED_space_image_set(sima, scene, scene->obedit, ima); + } + } + } + } + + ob->mode |= mode_flag; BKE_paint_init(&scene->toolsettings->imapaint.paint, PAINT_CURSOR_TEXTURE_PAINT); @@ -1035,6 +1436,60 @@ void PAINT_OT_texture_paint_toggle(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op)) +{ + UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; + Brush *br = image_paint_brush(C); + if (ups->flag & UNIFIED_PAINT_COLOR) { + swap_v3_v3(ups->rgb, ups->secondary_rgb); + } + else if (br) { + swap_v3_v3(br->rgb, br->secondary_rgb); + } + WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, br); + + return OPERATOR_FINISHED; +} + +static int brush_colors_flip_poll(bContext *C) +{ + if (image_paint_poll(C)) { + Brush *br = image_paint_brush(C); + if (br->imagepaint_tool == PAINT_TOOL_DRAW) + return 1; + } + + return 0; +} + +void PAINT_OT_brush_colors_flip(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Brush Colors Flip"; + ot->idname = "PAINT_OT_brush_colors_flip"; + ot->description = "Toggle foreground and background brush colors"; + + /* api callbacks */ + ot->exec = brush_colors_flip_exec; + ot->poll = brush_colors_flip_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + +void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op) +{ + ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, + ED_image_undo_restore, ED_image_undo_free, NULL); + + paint_2d_bucket_fill(C, color, NULL, NULL, NULL); + + ED_undo_paint_push_end(UNDO_PAINT_IMAGE); +} + + static int texture_paint_poll(bContext *C) { if (texture_paint_toggle_poll(C)) diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 4f67fc9cc87..165888b3c09 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -40,11 +40,18 @@ #include "BLI_math.h" +#include "BLI_rect.h" +#include "BLI_math_color_blend.h" +#include "BLI_stack.h" +#include "BLI_bitmap.h" + #include "BKE_context.h" +#include "BKE_depsgraph.h" #include "BKE_brush.h" #include "BKE_image.h" #include "BKE_paint.h" #include "BKE_report.h" +#include "BKE_texture.h" #include "ED_paint.h" #include "ED_screen.h" @@ -69,24 +76,25 @@ /* Defines and Structs */ typedef struct BrushPainterCache { - int size; /* size override, if 0 uses 2*BKE_brush_size_get(brush) */ - bool use_float; /* need float imbuf? */ bool use_color_correction; /* use color correction for float */ - bool use_masking; /* use masking? */ + bool invert; bool is_texbrush; bool is_maskbrush; - int lastsize; - float lastalpha; - float lastjitter; + int lastdiameter; float last_tex_rotation; float last_mask_rotation; + float last_pressure; ImBuf *ibuf; ImBuf *texibuf; - unsigned short *mask; + unsigned short *curve_mask; + unsigned short *tex_mask; + unsigned short *tex_mask_old; + unsigned int tex_mask_old_w; + unsigned int tex_mask_old_h; } BrushPainterCache; typedef struct BrushPainter { @@ -136,43 +144,42 @@ typedef struct ImagePaintState { int do_facesel; bool need_redraw; + + BlurKernel *blurkernel; } ImagePaintState; -static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush) +static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush, bool invert) { BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter"); painter->brush = brush; painter->scene = scene; painter->firsttouch = 1; - painter->cache.lastsize = -1; /* force ibuf create in refresh */ + painter->cache.lastdiameter = -1; /* force ibuf create in refresh */ + painter->cache.invert = invert; return painter; } -static void brush_painter_2d_require_imbuf(BrushPainter *painter, bool use_float, bool use_color_correction, bool use_masking) +static void brush_painter_2d_require_imbuf(BrushPainter *painter, bool use_float, bool use_color_correction) { Brush *brush = painter->brush; if ((painter->cache.use_float != use_float)) { if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); - if (painter->cache.mask) MEM_freeN(painter->cache.mask); + if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask); + if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask); + if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old); painter->cache.ibuf = NULL; - painter->cache.mask = NULL; - painter->cache.lastsize = -1; /* force ibuf create in refresh */ - } - - if (painter->cache.use_float != use_float) { - if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); - painter->cache.texibuf = NULL; - painter->cache.lastsize = -1; /* force ibuf create in refresh */ + painter->cache.curve_mask = NULL; + painter->cache.tex_mask = NULL; + painter->cache.lastdiameter = -1; /* force ibuf create in refresh */ } painter->cache.use_float = use_float; painter->cache.use_color_correction = use_float && use_color_correction; - painter->cache.use_masking = use_masking; painter->cache.is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false; painter->cache.is_maskbrush = (brush->mask_mtex.tex) ? true : false; } @@ -181,7 +188,9 @@ static void brush_painter_2d_free(BrushPainter *painter) { if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); - if (painter->cache.mask) MEM_freeN(painter->cache.mask); + if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask); + if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask); + if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old); MEM_freeN(painter); } @@ -192,41 +201,177 @@ static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3]) texco[2] = 0.0f; } -/* create a mask with the falloff strength and optionally brush alpha */ -static unsigned short *brush_painter_mask_new(BrushPainter *painter, int size) +/* create a mask with the mask texture */ +static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, int size) { Scene *scene = painter->scene; Brush *brush = painter->brush; - bool use_masking = painter->cache.use_masking; - - float alpha = (use_masking) ? 1.0f : BKE_brush_alpha_get(scene, brush); - int radius = BKE_brush_size_get(scene, brush); - int xoff = -size * 0.5f + 0.5f; - int yoff = -size * 0.5f + 0.5f; + rctf mask_mapping = painter->mask_mapping; + struct ImagePool *pool = painter->pool; + float texco[3]; unsigned short *mask, *m; - int x, y; + int x, y, thread = 0; - mask = MEM_callocN(sizeof(unsigned short) * size * size, "brush_painter_mask"); + mask = MEM_mallocN(sizeof(unsigned short) * size * size, "brush_painter_mask"); m = mask; for (y = 0; y < size; y++) { for (x = 0; x < size; x++, m++) { + float res; + brush_imbuf_tex_co(&mask_mapping, x, y, texco); + res = BKE_brush_sample_masktex(scene, brush, texco, thread, pool); + *m = (unsigned short)(65535.0f * res); + } + } + + return mask; +} + +/* update rectangular section of the brush image */ +static void brush_painter_mask_imbuf_update( + BrushPainter *painter, unsigned short *tex_mask_old, + int origx, int origy, int w, int h, int xt, int yt, int diameter) +{ + Scene *scene = painter->scene; + Brush *brush = painter->brush; + rctf tex_mapping = painter->mask_mapping; + struct ImagePool *pool = painter->pool; + unsigned short res; + + bool use_texture_old = (tex_mask_old != NULL); + + int x, y, thread = 0; + + unsigned short *tex_mask = painter->cache.tex_mask; + unsigned short *tex_mask_cur = painter->cache.tex_mask_old; + + /* fill pixels */ + for (y = origy; y < h; y++) { + for (x = origx; x < w; x++) { + /* sample texture */ + float texco[3]; + + /* handle byte pixel */ + unsigned short *b = tex_mask + (y * diameter + x); + unsigned short *t = tex_mask_cur + (y * diameter + x); + + if (!use_texture_old) { + brush_imbuf_tex_co(&tex_mapping, x, y, texco); + res = (unsigned short)(65535.0f * BKE_brush_sample_masktex(scene, brush, texco, thread, pool)); + } + + /* read from old texture buffer */ + if (use_texture_old) { + res = *(tex_mask_old + ((y - origy + yt) * painter->cache.tex_mask_old_w + (x - origx + xt))); + } + + /* write to new texture mask */ + *t = res; + /* write to mask image buffer */ + *b = res; + } + } +} + + +/** + * Update the brush mask image by trying to reuse the cached texture result. + * This can be considerably faster for brushes that change size due to pressure or + * textures that stick to the surface where only part of the pixels are new + */ +static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter) +{ + BrushPainterCache *cache = &painter->cache; + unsigned short *tex_mask_old; + int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2; + + /* create brush image buffer if it didn't exist yet */ + if (!cache->tex_mask) + cache->tex_mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask"); + + /* create new texture image buffer with coordinates relative to old */ + tex_mask_old = cache->tex_mask_old; + cache->tex_mask_old = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask"); + + if (tex_mask_old) { + ImBuf maskibuf; + ImBuf maskibuf_old; + maskibuf.x = maskibuf.y = diameter; + maskibuf_old.x = cache->tex_mask_old_w; + maskibuf_old.y = cache->tex_mask_old_h; + + srcx = srcy = 0; + w = cache->tex_mask_old_w; + h = cache->tex_mask_old_h; + destx = (int)painter->lastpaintpos[0] - (int)pos[0] + (diameter / 2 - w / 2); + desty = (int)painter->lastpaintpos[1] - (int)pos[1] + (diameter / 2 - h / 2); + + /* hack, use temporary rects so that clipping works */ + IMB_rectclip(&maskibuf, &maskibuf_old, &destx, &desty, &srcx, &srcy, &w, &h); + } + else { + srcx = srcy = 0; + destx = desty = 0; + w = h = 0; + } + + x1 = min_ii(destx, diameter); + y1 = min_ii(desty, diameter); + x2 = min_ii(destx + w, diameter); + y2 = min_ii(desty + h, diameter); + + /* blend existing texture in new position */ + if ((x1 < x2) && (y1 < y2)) + brush_painter_mask_imbuf_update(painter, tex_mask_old, x1, y1, x2, y2, srcx, srcy, diameter); + + if (tex_mask_old) + MEM_freeN(tex_mask_old); + + /* sample texture in new areas */ + if ((0 < x1) && (0 < diameter)) + brush_painter_mask_imbuf_update(painter, NULL, 0, 0, x1, diameter, 0, 0, diameter); + if ((x2 < diameter) && (0 < diameter)) + brush_painter_mask_imbuf_update(painter, NULL, x2, 0, diameter, diameter, 0, 0, diameter); + if ((x1 < x2) && (0 < y1)) + brush_painter_mask_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0, diameter); + if ((x1 < x2) && (y2 < diameter)) + brush_painter_mask_imbuf_update(painter, NULL, x1, y2, x2, diameter, 0, 0, diameter); + + /* through with sampling, now update sizes */ + cache->tex_mask_old_w = diameter; + cache->tex_mask_old_h = diameter; +} + +/* create a mask with the falloff strength */ +static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int diameter, float radius) +{ + Brush *brush = painter->brush; + + int xoff = -diameter * 0.5f + 0.5f; + int yoff = -diameter * 0.5f + 0.5f; + + unsigned short *mask, *m; + int x, y; + + mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask"); + m = mask; + + for (y = 0; y < diameter; y++) { + for (x = 0; x < diameter; x++, m++) { float xy[2] = {x + xoff, y + yoff}; float len = len_v2(xy); - float strength = alpha; - - strength *= BKE_brush_curve_strength_clamp(brush, len, radius); - *m = (unsigned short)(65535.0f * strength); + *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamp(brush, len, radius)); } } return mask; } + /* create imbuf with brush color */ -static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size) +static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size, float pressure, float distance) { Scene *scene = painter->scene; Brush *brush = painter->brush; @@ -235,19 +380,11 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size) struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); rctf tex_mapping = painter->tex_mapping; - rctf mask_mapping = painter->mask_mapping; struct ImagePool *pool = painter->pool; - bool use_masking = painter->cache.use_masking; bool use_color_correction = painter->cache.use_color_correction; bool use_float = painter->cache.use_float; bool is_texbrush = painter->cache.is_texbrush; - bool is_maskbrush = painter->cache.is_maskbrush; - - float alpha = (use_masking) ? 1.0f : BKE_brush_alpha_get(scene, brush); - int radius = BKE_brush_size_get(scene, brush); - int xoff = -size * 0.5f + 0.5f; - int yoff = -size * 0.5f + 0.5f; int x, y, thread = 0; float brush_rgb[3]; @@ -257,11 +394,7 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size) /* get brush color */ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { - copy_v3_v3(brush_rgb, brush->rgb); - - if (use_color_correction) { - IMB_colormanagement_display_to_scene_linear_v3(brush_rgb, display); - } + paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, distance, pressure, brush_rgb, display); } else { brush_rgb[0] = 1.0f; @@ -278,30 +411,17 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size) if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool); + mul_v3_v3(rgba, brush_rgb); /* TODO(sergey): Support texture paint color space. */ if (!use_float) { IMB_colormanagement_scene_linear_to_display_v3(rgba, display); } - mul_v3_v3(rgba, brush_rgb); } else { copy_v3_v3(rgba, brush_rgb); rgba[3] = 1.0f; } - if (is_maskbrush) { - brush_imbuf_tex_co(&mask_mapping, x, y, texco); - rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool); - } - - /* when not using masking, multiply in falloff and strength */ - if (!use_masking) { - float xy[2] = {x + xoff, y + yoff}; - float len = len_v2(xy); - - rgba[3] *= alpha * BKE_brush_curve_strength_clamp(brush, len, radius); - } - if (use_float) { /* write to float pixel */ float *dstf = ibuf->rect_float + (y * size + x) * 4; @@ -332,14 +452,11 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); rctf tex_mapping = painter->tex_mapping; - rctf mask_mapping = painter->mask_mapping; struct ImagePool *pool = painter->pool; - bool use_masking = painter->cache.use_masking; bool use_color_correction = painter->cache.use_color_correction; bool use_float = painter->cache.use_float; bool is_texbrush = painter->cache.is_texbrush; - bool is_maskbrush = painter->cache.is_maskbrush; bool use_texture_old = (oldtexibuf != NULL); int x, y, thread = 0; @@ -347,15 +464,10 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, ImBuf *ibuf = painter->cache.ibuf; ImBuf *texibuf = painter->cache.texibuf; - unsigned short *mask = painter->cache.mask; /* get brush color */ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { - copy_v3_v3(brush_rgb, brush->rgb); - - if (use_color_correction) { - IMB_colormanagement_display_to_scene_linear_v3(brush_rgb, display); - } + paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, 0.0, 1.0, brush_rgb, display); } else { brush_rgb[0] = 1.0f; @@ -363,7 +475,7 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, brush_rgb[2] = 1.0f; } - /* fill pixes */ + /* fill pixels */ for (y = origy; y < h; y++) { for (x = origx; x < w; x++) { /* sample texture and multiply with brush color */ @@ -373,21 +485,16 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, if (is_texbrush) { brush_imbuf_tex_co(&tex_mapping, x, y, texco); BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool); + mul_v3_v3(rgba, brush_rgb); /* TODO(sergey): Support texture paint color space. */ if (!use_float) { IMB_colormanagement_scene_linear_to_display_v3(rgba, display); } - mul_v3_v3(rgba, brush_rgb); } else { copy_v3_v3(rgba, brush_rgb); rgba[3] = 1.0f; } - - if (is_maskbrush) { - brush_imbuf_tex_co(&mask_mapping, x, y, texco); - rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool); - } } if (use_float) { @@ -404,12 +511,6 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, /* write to new texture buffer */ copy_v4_v4(tf, rgba); - /* if not using masking, multiply in the mask now */ - if (!use_masking) { - unsigned short *m = mask + (y * ibuf->x + x); - rgba[3] *= *m * (1.0f / 65535.0f); - } - /* output premultiplied float image, mf was already premultiplied */ mul_v3_v3fl(bf, rgba, rgba[3]); bf[3] = rgba[3]; @@ -438,12 +539,6 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, t[2] = crgba[2]; t[3] = crgba[3]; - /* if not using masking, multiply in the mask now */ - if (!use_masking) { - unsigned short *m = mask + (y * ibuf->x + x); - crgba[3] = (crgba[3] * (*m)) / 65535; - } - /* write to brush image buffer */ b[0] = crgba[0]; b[1] = crgba[1]; @@ -457,14 +552,11 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, /* update the brush image by trying to reuse the cached texture result. this * can be considerably faster for brushes that change size due to pressure or * textures that stick to the surface where only part of the pixels are new */ -static void brush_painter_imbuf_partial_update(BrushPainter *painter, const float pos[2]) +static void brush_painter_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter) { - const Scene *scene = painter->scene; - Brush *brush = painter->brush; BrushPainterCache *cache = &painter->cache; ImBuf *oldtexibuf, *ibuf; int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2; - int diameter = 2 * BKE_brush_size_get(scene, brush); /* create brush image buffer if it didn't exist yet */ imbflag = (cache->use_float) ? IB_rectfloat : IB_rect; @@ -478,10 +570,10 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter, const floa if (oldtexibuf) { srcx = srcy = 0; - destx = (int)painter->lastpaintpos[0] - (int)pos[0]; - desty = (int)painter->lastpaintpos[1] - (int)pos[1]; w = oldtexibuf->x; h = oldtexibuf->y; + destx = (int)painter->lastpaintpos[0] - (int)pos[0] + (diameter / 2 - w / 2); + desty = (int)painter->lastpaintpos[1] - (int)pos[1] + (diameter / 2 - h / 2); IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h); } @@ -514,7 +606,7 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter, const floa brush_painter_imbuf_update(painter, NULL, x1, y2, x2, ibuf->y, 0, 0); } -static void brush_painter_2d_tex_mapping(ImagePaintState *s, int size, const float startpos[2], const float pos[2], const float mouse[2], int mapmode, rctf *mapping) +static void brush_painter_2d_tex_mapping(ImagePaintState *s, int diameter, const float startpos[2], const float pos[2], const float mouse[2], int mapmode, rctf *mapping) { float invw = 1.0f / (float)s->canvas->x; float invh = 1.0f / (float)s->canvas->y; @@ -522,19 +614,19 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s, int size, const flo int ipos[2]; /* find start coordinate of brush in canvas */ - ipos[0] = (int)floorf((pos[0] - size / 2) + 1.0f); - ipos[1] = (int)floorf((pos[1] - size / 2) + 1.0f); + ipos[0] = (int)floorf((pos[0] - diameter / 2) + 1.0f); + ipos[1] = (int)floorf((pos[1] - diameter / 2) + 1.0f); if (mapmode == MTEX_MAP_MODE_STENCIL) { /* map from view coordinates of brush to region coordinates */ UI_view2d_view_to_region(s->v2d, ipos[0] * invw, ipos[1] * invh, &xmin, &ymin); - UI_view2d_view_to_region(s->v2d, (ipos[0] + size) * invw, (ipos[1] + size) * invh, &xmax, &ymax); + UI_view2d_view_to_region(s->v2d, (ipos[0] + diameter) * invw, (ipos[1] + diameter) * invh, &xmax, &ymax); /* output mapping from brush ibuf x/y to region coordinates */ mapping->xmin = xmin; mapping->ymin = ymin; - mapping->xmax = (xmax - xmin) / (float)size; - mapping->ymax = (ymax - ymin) / (float)size; + mapping->xmax = (xmax - xmin) / (float)diameter; + mapping->ymax = (ymax - ymin) / (float)diameter; } else if (mapmode == MTEX_MAP_MODE_3D) { /* 3D mapping, just mapping to canvas 0..1 */ @@ -545,104 +637,126 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s, int size, const flo } else if (ELEM(mapmode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_RANDOM)) { /* view mapping */ - mapping->xmin = mouse[0] - size * 0.5f + 0.5f; - mapping->ymin = mouse[1] - size * 0.5f + 0.5f; + mapping->xmin = mouse[0] - diameter * 0.5f + 0.5f; + mapping->ymin = mouse[1] - diameter * 0.5f + 0.5f; mapping->xmax = 1.0f; mapping->ymax = 1.0f; } else /* if (mapmode == MTEX_MAP_MODE_TILED) */ { - mapping->xmin = -size * 0.5f + 0.5f + (int)pos[0] - (int)startpos[0]; - mapping->ymin = -size * 0.5f + 0.5f + (int)pos[1] - (int)startpos[1]; + mapping->xmin = (int)(-diameter * 0.5) + (int)pos[0] - (int)startpos[0]; + mapping->ymin = (int)(-diameter * 0.5) + (int)pos[1] - (int)startpos[1]; mapping->xmax = 1.0f; mapping->ymax = 1.0f; } } -static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2], const float mouse[2]) +static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2], const float mouse[2], float pressure, float distance, float size) { const Scene *scene = painter->scene; UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; Brush *brush = painter->brush; BrushPainterCache *cache = &painter->cache; - const int diameter = 2 * BKE_brush_size_get(scene, brush); - const int size = (cache->size) ? cache->size : diameter; - const float alpha = BKE_brush_alpha_get(scene, brush); - const bool use_masking = painter->cache.use_masking; + const int diameter = 2 * size; bool do_random = false; bool do_partial_update = false; - bool do_view = false; + bool update_color = (brush->flag & BRUSH_USE_GRADIENT) && + ((ELEM(brush->gradient_stroke_mode, + BRUSH_GRADIENT_SPACING_REPEAT, + BRUSH_GRADIENT_SPACING_CLAMP)) || + (cache->last_pressure != pressure)); float tex_rotation = -brush->mtex.rot; float mask_rotation = -brush->mask_mtex.rot; + painter->pool = BKE_image_pool_new(); + /* determine how can update based on textures used */ if (painter->cache.is_texbrush) { if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) { - do_view = true; tex_rotation += ups->brush_rotation; } else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) do_random = true; - else + else if (!((brush->flag & BRUSH_ANCHORED) || update_color)) do_partial_update = true; - brush_painter_2d_tex_mapping(s, size, painter->startpaintpos, pos, mouse, + brush_painter_2d_tex_mapping(s, diameter, painter->startpaintpos, pos, mouse, brush->mtex.brush_map_mode, &painter->tex_mapping); } if (painter->cache.is_maskbrush) { + bool renew_maxmask = false; + bool do_partial_update_mask = false; + /* invalidate case for all mapping modes */ if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) { - do_view = true; mask_rotation += ups->brush_rotation; } - else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) - do_random = true; - else - do_partial_update = true; + else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) { + renew_maxmask = true; + } + else if (!(brush->flag & BRUSH_ANCHORED)) { + do_partial_update_mask = true; + renew_maxmask = true; + } + /* explicilty disable partial update even if it has been enabled above */ + if (brush->mask_pressure) { + do_partial_update_mask = false; + renew_maxmask = true; + } + + if ((diameter != cache->lastdiameter) || + (mask_rotation != cache->last_mask_rotation) || + renew_maxmask) + { + if (cache->tex_mask) { + MEM_freeN(cache->tex_mask); + cache->tex_mask = NULL; + } - brush_painter_2d_tex_mapping(s, size, painter->startpaintpos, pos, mouse, - brush->mask_mtex.brush_map_mode, &painter->mask_mapping); + brush_painter_2d_tex_mapping(s, diameter, painter->startpaintpos, pos, mouse, + brush->mask_mtex.brush_map_mode, &painter->mask_mapping); + + if (do_partial_update_mask) + brush_painter_mask_imbuf_partial_update(painter, pos, diameter); + else + cache->tex_mask = brush_painter_mask_ibuf_new(painter, diameter); + cache->last_mask_rotation = mask_rotation; + } } - if (do_view || do_random) - do_partial_update = false; + /* curve mask can only change if the size changes */ + if (diameter != cache->lastdiameter) { + if (cache->curve_mask) { + MEM_freeN(cache->curve_mask); + cache->curve_mask = NULL; + } - painter->pool = BKE_image_pool_new(); + cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size); + } /* detect if we need to recreate image brush buffer */ - if (diameter != cache->lastsize || - alpha != cache->lastalpha || - brush->jitter != cache->lastjitter || - tex_rotation != cache->last_tex_rotation || - mask_rotation != cache->last_mask_rotation || - do_random) + if ((diameter != cache->lastdiameter) || + (tex_rotation != cache->last_tex_rotation) || + do_random || + update_color) { if (cache->ibuf) { IMB_freeImBuf(cache->ibuf); cache->ibuf = NULL; } - if (cache->mask) { - MEM_freeN(cache->mask); - cache->mask = NULL; - } if (do_partial_update) { - /* do partial update of texture + recreate mask */ - cache->mask = brush_painter_mask_new(painter, size); - brush_painter_imbuf_partial_update(painter, pos); + /* do partial update of texture */ + brush_painter_imbuf_partial_update(painter, pos, diameter); } else { - /* create brush and mask from scratch */ - if (use_masking) - cache->mask = brush_painter_mask_new(painter, size); - cache->ibuf = brush_painter_imbuf_new(painter, size); + /* create brush from scratch */ + cache->ibuf = brush_painter_imbuf_new(painter, diameter, pressure, distance); } - cache->lastsize = diameter; - cache->lastalpha = alpha; - cache->lastjitter = brush->jitter; + cache->lastdiameter = diameter; cache->last_tex_rotation = tex_rotation; - cache->last_mask_rotation = mask_rotation; + cache->last_pressure = pressure; } else if (do_partial_update) { /* do only partial update of texture */ @@ -650,7 +764,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *pai int dy = (int)painter->lastpaintpos[1] - (int)pos[1]; if ((dx != 0) || (dy != 0)) { - brush_painter_imbuf_partial_update(painter, pos); + brush_painter_imbuf_partial_update(painter, pos, diameter); } } @@ -703,7 +817,7 @@ static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus } } -static int paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus) +static float paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus, float w) { float inrgb[4]; @@ -716,16 +830,23 @@ static int paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, flo paint_2d_ibuf_rgb_get(ibuf, x, y, 0, inrgb); } + mul_v4_fl(inrgb, w); add_v4_v4(outrgb, inrgb); - return 1; + return w; } -static void paint_2d_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const bool is_torus) +static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short is_torus) { - int x, y, count, xi, yi, xo, yo; + bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0)); + float threshold = s->brush->sharp_threshold; + int x, y, xi, yi, xo, yo, xk, yk; + float count; int out_off[2], in_off[2], dim[2]; + int diff_pos[2]; float outrgb[4]; + float rgba[4]; + BlurKernel *kernel = s->blurkernel; dim[0] = ibufb->x; dim[1] = ibufb->y; @@ -741,28 +862,52 @@ static void paint_2d_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const bool return; } + /* find offset inside mask buffers to sample them */ + sub_v2_v2v2_int(diff_pos, out_off, in_off); + for (y = 0; y < dim[1]; y++) { for (x = 0; x < dim[0]; x++) { /* get input pixel */ xi = in_off[0] + x; yi = in_off[1] + y; - count = 1; - paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, outrgb); + count = 0.0; + paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, rgba); + zero_v4(outrgb); - count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi - 1, outrgb, is_torus); - count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi, outrgb, is_torus); - count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi + 1, outrgb, is_torus); + for (yk = 0; yk < kernel->side; yk++) { + for (xk = 0; xk < kernel->side; xk++) { + count += paint_2d_ibuf_add_if(ibuf, xi + xk - kernel->pixel_len, + yi + yk - kernel->pixel_len, outrgb, is_torus, + kernel->wdata[xk + yk * kernel->side]); + } + } - count += paint_2d_ibuf_add_if(ibuf, xi, yi - 1, outrgb, is_torus); - count += paint_2d_ibuf_add_if(ibuf, xi, yi + 1, outrgb, is_torus); + if (count > 0.0f) { + mul_v4_fl(outrgb, 1.0f / (float)count); - count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi - 1, outrgb, is_torus); - count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi, outrgb, is_torus); - count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi + 1, outrgb, is_torus); + if (sharpen) { + /* subtract blurred image from normal image gives high pass filter */ + sub_v3_v3v3(outrgb, rgba, outrgb); - mul_v4_fl(outrgb, 1.0f / (float)count); + /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid + * colored speckles appearing in final image, and also to check for threshold */ + outrgb[0] = outrgb[1] = outrgb[2] = rgb_to_grayscale(outrgb); + if (fabsf(outrgb[0]) > threshold) { + float mask = BKE_brush_alpha_get(s->scene, s->brush); + float alpha = rgba[3]; + rgba[3] = outrgb[3] = mask; + /* add to enhance edges */ + blend_color_add_float(outrgb, rgba, outrgb); + outrgb[3] = alpha; + } + else + copy_v4_v4(outrgb, rgba); + } + } + else + copy_v4_v4(outrgb, rgba); /* write into brush buffer */ xo = out_off[0] + x; yo = out_off[1] + y; @@ -830,10 +975,10 @@ static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos) tot = paint_2d_torus_split_region(region, ibufb, ibuf); for (a = 0; a < tot; a++) - IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, 0, region[a].destx, region[a].desty, + IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, NULL, 0, region[a].destx, region[a].desty, region[a].destx, region[a].desty, region[a].srcx, region[a].srcy, - region[a].width, region[a].height, IMB_BLEND_COPY_RGB); + region[a].width, region[a].height, IMB_BLEND_COPY_RGB, false); } static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos) @@ -844,10 +989,10 @@ static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos) ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags); IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h); - IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, NULL, 0, destx, desty, destx, desty, destx, desty, w, h, - IMB_BLEND_COPY_ALPHA); - IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h, - IMB_BLEND_COPY_RGB); + IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, NULL, NULL, 0, destx, desty, destx, desty, destx, desty, w, h, + IMB_BLEND_COPY_ALPHA, false); + IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h, + IMB_BLEND_COPY_RGB, false); return clonebuf; } @@ -858,17 +1003,16 @@ static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[ ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f); } -static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const float lastpos[2], const float pos[2]) +static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsigned short *texmaskb, const float lastpos[2], const float pos[2]) { ImagePaintState *s = ((ImagePaintState *)state); - ImBuf *clonebuf = NULL, *frombuf, *tmpbuf = NULL; + ImBuf *clonebuf = NULL, *frombuf; ImagePaintRegion region[4]; short torus = s->brush->flag & BRUSH_TORUS; short blend = s->blend; const float *offset = s->brush->clone.offset; float liftpos[2]; - float brush_alpha = BKE_brush_alpha_get(s->scene, s->brush); - unsigned short mask_max = (unsigned short)(brush_alpha * 65535.0f); + float mask_max = BKE_brush_alpha_get(s->scene, s->brush); int bpos[2], blastpos[2], bliftpos[2]; int a, tot; @@ -876,7 +1020,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f /* lift from canvas */ if (s->tool == PAINT_TOOL_SOFTEN) { - paint_2d_lift_soften(s->canvas, ibufb, bpos, torus); + paint_2d_lift_soften(s, s->canvas, ibufb, bpos, torus); } else if (s->tool == PAINT_TOOL_SMEAR) { if (lastpos[0] == pos[0] && lastpos[1] == pos[1]) @@ -903,9 +1047,6 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y); tot = 1; } - - if (s->do_masking) - tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0); /* blend into canvas */ for (a = 0; a < tot; a++) { @@ -916,11 +1057,14 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f if (s->do_masking) { /* masking, find original pixels tiles from undo buffer to composite over */ int tilex, tiley, tilew, tileh, tx, ty; + ImBuf *tmpbuf; imapaint_region_tiles(s->canvas, region[a].destx, region[a].desty, region[a].width, region[a].height, &tilex, &tiley, &tilew, &tileh); - + + tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0); + for (ty = tiley; ty <= tileh; ty++) { for (tx = tilex; tx <= tilew; tx++) { /* retrieve original pixels + mask from undo buffer */ @@ -929,31 +1073,32 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f int origy = region[a].desty - ty * IMAPAINT_TILE_SIZE; if (s->canvas->rect_float) - tmpbuf->rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask); + tmpbuf->rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); else - tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask); + tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); IMB_rectblend(s->canvas, tmpbuf, frombuf, mask, - maskb, mask_max, + curveb, texmaskb, mask_max, region[a].destx, region[a].desty, origx, origy, region[a].srcx, region[a].srcy, - region[a].width, region[a].height, blend); + region[a].width, region[a].height, blend, ((s->brush->flag & BRUSH_ACCUMULATE) != 0)); } } + + IMB_freeImBuf(tmpbuf); } else { /* no masking, composite brush directly onto canvas */ - IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, NULL, 0, + IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, curveb, texmaskb, mask_max, region[a].destx, region[a].desty, region[a].destx, region[a].desty, region[a].srcx, region[a].srcy, - region[a].width, region[a].height, blend); + region[a].width, region[a].height, blend, false); } } if (clonebuf) IMB_freeImBuf(clonebuf); - if (tmpbuf) IMB_freeImBuf(tmpbuf); return 1; } @@ -1003,10 +1148,7 @@ static int paint_2d_canvas_set(ImagePaintState *s, Image *ima) } /* set masking */ - s->do_masking = (s->brush->flag & BRUSH_AIRBRUSH || - (s->brush->imagepaint_tool == PAINT_TOOL_SMEAR) || - (s->brush->mtex.tex && !ELEM3(s->brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D))) - ? false : true; + s->do_masking = paint_use_opacity_masking(s->brush); return 1; } @@ -1016,11 +1158,15 @@ static void paint_2d_canvas_free(ImagePaintState *s) BKE_image_release_ibuf(s->image, s->canvas, NULL); BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL); - if (s->do_masking) - image_undo_remove_masks(); + if (s->blurkernel) { + paint_delete_blur_kernel(s->blurkernel); + MEM_freeN(s->blurkernel); + } + + image_undo_remove_masks(); } -void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], int eraser) +void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], const bool eraser, float pressure, float distance, float size) { float newuv[2], olduv[2]; ImagePaintState *s = ps; @@ -1063,17 +1209,17 @@ void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], in /* OCIO_TODO: float buffers are now always linear, so always use color correction * this should probably be changed when texture painting color space is supported */ - brush_painter_2d_require_imbuf(painter, (ibuf->rect_float != NULL), !is_data, s->do_masking); + brush_painter_2d_require_imbuf(painter, (ibuf->rect_float != NULL), !is_data); - brush_painter_2d_refresh_cache(s, painter, newuv, mval); + brush_painter_2d_refresh_cache(s, painter, newuv, mval, pressure, distance, size); - if (paint_2d_op(s, painter->cache.ibuf, painter->cache.mask, olduv, newuv)) + if (paint_2d_op(s, painter->cache.ibuf, painter->cache.curve_mask, painter->cache.tex_mask, olduv, newuv)) s->need_redraw = true; BKE_image_release_ibuf(s->image, ibuf, NULL); } -void *paint_2d_new_stroke(bContext *C, wmOperator *op) +void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode) { Scene *scene = CTX_data_scene(C); ToolSettings *settings = scene->toolsettings; @@ -1102,10 +1248,14 @@ void *paint_2d_new_stroke(bContext *C, wmOperator *op) return NULL; } + if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) { + s->blurkernel = paint_new_blur_kernel(brush, false); + } + paint_brush_init_tex(s->brush); /* create painter */ - s->painter = brush_painter_2d_new(scene, s->brush); + s->painter = brush_painter_2d_new(scene, s->brush, mode == BRUSH_STROKE_INVERT); return s; } @@ -1134,6 +1284,7 @@ void paint_2d_redraw(const bContext *C, void *ps, bool final) /* compositor listener deals with updating */ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image); + DAG_id_tag_update(&s->image->id, 0); } else { if (!s->sima || !s->sima->lock) @@ -1153,3 +1304,334 @@ void paint_2d_stroke_done(void *ps) MEM_freeN(s); } + +static void paint_2d_fill_add_pixel_byte( + const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched, + const float color[4], float threshold_sq) +{ + int coordinate; + + if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0) + return; + + coordinate = y_px * ibuf->x + x_px; + + if (!BLI_BITMAP_TEST(touched, coordinate)) { + float color_f[4]; + unsigned char *color_b = (unsigned char *)(ibuf->rect + coordinate); + rgba_uchar_to_float(color_f, color_b); + + if (compare_len_squared_v3v3(color_f, color, threshold_sq)) { + BLI_stack_push(stack, &coordinate); + } + BLI_BITMAP_SET(touched, coordinate, true); + } +} + +static void paint_2d_fill_add_pixel_float( + const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched, + const float color[4], float threshold_sq) +{ + int coordinate; + + if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0) + return; + + coordinate = y_px * ibuf->x + x_px; + + if (!BLI_BITMAP_TEST(touched, coordinate)) { + if (compare_len_squared_v3v3(ibuf->rect_float + 4 * coordinate, color, threshold_sq)) { + BLI_stack_push(stack, &coordinate); + } + BLI_BITMAP_SET(touched, coordinate, true); + } +} + +/* this function expects linear space color values */ +void paint_2d_bucket_fill( + const bContext *C, const float color[3], Brush *br, + const float mouse_init[2], + void *ps) +{ + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = sima->image; + + ImagePaintState *s = ps; + + ImBuf *ibuf; + int x_px, y_px; + unsigned int color_b; + float color_f[4]; + float strength = br ? br->alpha : 1.0f; + + bool do_float; + + if (!ima) + return; + + ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL); + + if (!ibuf) + return; + + do_float = (ibuf->rect_float != NULL); + /* first check if our image is float. If it is not we should correct the color to + * be in gamma space. strictly speaking this is not correct, but blender does not paint + * byte images in linear space */ + if (!do_float) { + linearrgb_to_srgb_uchar3((unsigned char *)&color_b, color); + *(((char *)&color_b) + 3) = strength * 255; + } + else { + copy_v3_v3(color_f, color); + color_f[3] = strength; + } + + if (!mouse_init || !br) { + /* first case, no image UV, fill the whole image */ + ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y); + + if (do_float) { + for (x_px = 0; x_px < ibuf->x; x_px++) { + for (y_px = 0; y_px < ibuf->y; y_px++) { + blend_color_mix_float(ibuf->rect_float + 4 * (y_px * ibuf->x + x_px), + ibuf->rect_float + 4 * (y_px * ibuf->x + x_px), color_f); + } + } + } + else { + for (x_px = 0; x_px < ibuf->x; x_px++) { + for (y_px = 0; y_px < ibuf->y; y_px++) { + blend_color_mix_byte((unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px), + (unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px), (unsigned char *)&color_b); + } + } + } + } + else { + /* second case, start sweeping the neighboring pixels, looking for pixels whose + * value is within the brush fill threshold from the fill color */ + BLI_Stack *stack; + BLI_bitmap *touched; + int coordinate; + int width = ibuf->x; + float image_init[2]; + int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0; + float pixel_color[4]; + float threshold_sq = br->fill_threshold * br->fill_threshold; + + UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]); + + x_px = image_init[0] * ibuf->x; + y_px = image_init[1] * ibuf->y; + + if (x_px >= ibuf->x || x_px < 0 || y_px > ibuf->y || y_px < 0) { + BKE_image_release_ibuf(ima, ibuf, NULL); + return; + } + + /* change image invalidation method later */ + ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y); + + stack = BLI_stack_new(sizeof(int), __func__); + touched = BLI_BITMAP_NEW(ibuf->x * ibuf->y, "bucket_fill_bitmap"); + + coordinate = (y_px * ibuf->x + x_px); + + if (do_float) { + copy_v4_v4(pixel_color, ibuf->rect_float + 4 * coordinate); + } + else { + int pixel_color_b = *(ibuf->rect + coordinate); + rgba_uchar_to_float(pixel_color, (unsigned char *)&pixel_color_b); + } + + BLI_stack_push(stack, &coordinate); + BLI_BITMAP_SET(touched, coordinate, true); + + if (do_float) { + while (!BLI_stack_is_empty(stack)) { + BLI_stack_pop(stack, &coordinate); + + IMB_blend_color_float(ibuf->rect_float + 4 * (coordinate), + ibuf->rect_float + 4 * (coordinate), + color_f, br->blend); + + /* reconstruct the coordinates here */ + x_px = coordinate % width; + y_px = coordinate / width; + + paint_2d_fill_add_pixel_float(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq); + + if (x_px > maxx) + maxx = x_px; + if (x_px < minx) + minx = x_px; + if (y_px > maxy) + maxy = y_px; + if (x_px > miny) + miny = y_px; + } + } + else { + while (!BLI_stack_is_empty(stack)) { + BLI_stack_pop(stack, &coordinate); + + IMB_blend_color_byte((unsigned char *)(ibuf->rect + coordinate), + (unsigned char *)(ibuf->rect + coordinate), + (unsigned char *)&color_b, br->blend); + + /* reconstruct the coordinates here */ + x_px = coordinate % width; + y_px = coordinate / width; + + paint_2d_fill_add_pixel_byte(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq); + + if (x_px > maxx) + maxx = x_px; + if (x_px < minx) + minx = x_px; + if (y_px > maxy) + maxy = y_px; + if (x_px > miny) + miny = y_px; + } + } + + MEM_freeN(touched); + BLI_stack_free(stack); + } + + imapaint_image_update(sima, ima, ibuf, false); + ED_imapaint_clear_partial_redraw(); + + BKE_image_release_ibuf(ima, ibuf, NULL); + + WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); +} + +void paint_2d_gradient_fill( + const bContext *C, Brush *br, + const float mouse_init[2], const float mouse_final[2], + void *ps) +{ + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = sima->image; + ImagePaintState *s = ps; + + ImBuf *ibuf; + int x_px, y_px; + unsigned int color_b; + float color_f[4]; + float image_init[2], image_final[2]; + float tangent[2]; + float line_len_sq_inv, line_len; + + bool do_float; + + if (!ima) + return; + + ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL); + + if (!ibuf) + return; + + UI_view2d_region_to_view(s->v2d, mouse_final[0], mouse_final[1], &image_final[0], &image_final[1]); + UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]); + + image_final[0] *= ibuf->x; + image_final[1] *= ibuf->y; + + image_init[0] *= ibuf->x; + image_init[1] *= ibuf->y; + + /* some math to get needed gradient variables */ + sub_v2_v2v2(tangent, image_final, image_init); + line_len = len_squared_v2(tangent); + line_len_sq_inv = 1.0f / line_len; + line_len = sqrt(line_len); + + do_float = (ibuf->rect_float != NULL); + + /* this will be substituted by something else when selection is available */ + ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y); + + if (do_float) { + for (x_px = 0; x_px < ibuf->x; x_px++) { + for (y_px = 0; y_px < ibuf->y; y_px++) { + float f; + float p[2] = {x_px - image_init[0], y_px - image_init[1]}; + + switch (br->gradient_fill_mode) { + case BRUSH_GRADIENT_LINEAR: + { + f = dot_v2v2(p, tangent) * line_len_sq_inv; + break; + } + case BRUSH_GRADIENT_RADIAL: + { + f = len_v2(p) / line_len; + break; + } + } + do_colorband(br->gradient, f, color_f); + /* convert to premultiplied */ + mul_v3_fl(color_f, color_f[3]); + color_f[3] *= br->alpha; + IMB_blend_color_float(ibuf->rect_float + 4 * (y_px * ibuf->x + x_px), + ibuf->rect_float + 4 * (y_px * ibuf->x + x_px), + color_f, br->blend); + } + } + } + else { + for (x_px = 0; x_px < ibuf->x; x_px++) { + for (y_px = 0; y_px < ibuf->y; y_px++) { + float f; + float p[2] = {x_px - image_init[0], y_px - image_init[1]}; + + switch (br->gradient_fill_mode) { + case BRUSH_GRADIENT_LINEAR: + { + f = dot_v2v2(p, tangent) * line_len_sq_inv; + break; + } + case BRUSH_GRADIENT_RADIAL: + { + f = len_v2(p) / line_len; + break; + } + } + + do_colorband(br->gradient, f, color_f); + rgba_float_to_uchar((unsigned char *)&color_b, color_f); + ((unsigned char *)&color_b)[3] *= br->alpha; + IMB_blend_color_byte((unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px), + (unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px), + (unsigned char *)&color_b, br->blend); + } + } + } + + imapaint_image_update(sima, ima, ibuf, false); + ED_imapaint_clear_partial_redraw(); + + BKE_image_release_ibuf(ima, ibuf, NULL); + + WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); +} diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 399b5044a05..ef4a4e9bf79 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -48,31 +48,42 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BLF_translation.h" + #include "PIL_time.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "DNA_brush_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" #include "BKE_camera.h" +#include "BKE_colortools.h" #include "BKE_context.h" +#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_idprop.h" #include "BKE_brush.h" #include "BKE_image.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_paint.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_texture.h" #include "UI_view2d.h" +#include "UI_interface.h" +#include "ED_image.h" +#include "ED_mesh.h" #include "ED_paint.h" #include "ED_screen.h" #include "ED_uvedit.h" @@ -88,6 +99,7 @@ #include "RNA_enum_types.h" #include "GPU_draw.h" +#include "GPU_buffers.h" #include "IMB_colormanagement.h" @@ -141,6 +153,7 @@ BLI_INLINE unsigned char f_to_char(const float val) #define PROJ_SRC_VIEW 1 #define PROJ_SRC_IMAGE_CAM 2 #define PROJ_SRC_IMAGE_VIEW 3 +#define PROJ_SRC_VIEW_FILL 4 #define PROJ_VIEW_DATA_ID "view_data" #define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3) /* viewmat + winmat + clipsta + clipend + is_ortho */ @@ -162,6 +175,9 @@ BLI_INLINE unsigned char f_to_char(const float val) /* vert flags */ #define PROJ_VERT_CULL 1 +/* to avoid locking in tile initialization */ +#define TILE_PENDING SET_INT_IN_POINTER(-1) + /* This is mainly a convenience struct used so we can keep an array of images we use * Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread * because 'partRedrawRect' and 'touch' values would not be thread safe */ @@ -169,7 +185,10 @@ typedef struct ProjPaintImage { Image *ima; ImBuf *ibuf; ImagePaintPartialRedraw *partRedrawRect; - void **undoRect; /* only used to build undo tiles after painting */ + volatile void **undoRect; /* only used to build undo tiles during painting */ + unsigned short **maskRect; /* the mask accumulation must happen on canvas, not on space screen bucket. + * Here we store the mask rectangle */ + bool **valid; /* store flag to enforce validation of undo rectangle */ int touch; } ProjPaintImage; @@ -181,9 +200,14 @@ typedef struct ProjPaintState { Scene *scene; int source; /* PROJ_SRC_**** */ + /* the paint color. It can change depending of inverted mode or not */ + float paint_color[3]; + float paint_color_linear[3]; + Brush *brush; short tool, blend, mode; int orig_brush_size; + float brush_size; Object *ob; /* end similarities with ImagePaintState */ @@ -194,10 +218,15 @@ typedef struct ProjPaintState { MVert *dm_mvert; MFace *dm_mface; - MTFace *dm_mtface; - MTFace *dm_mtface_clone; /* other UV map, use for cloning between layers */ + MTFace **dm_mtface; + MTFace **dm_mtface_clone; /* other UV map, use for cloning between layers */ MTFace *dm_mtface_stencil; + Image *stencil_ima; + Image *canvas_ima; + Image *clone_ima; + float stencil_value; + /* projection painting only */ MemArena *arena_mt[BLENDER_MAX_THREADS]; /* for multithreading, the first item is sometimes used for non threaded cases too */ LinkNode **bucketRect; /* screen sized 2D array, each pixel has a linked list of ProjPixel's */ @@ -231,6 +260,8 @@ typedef struct ProjPaintState { bool do_layer_clone; bool do_layer_stencil; bool do_layer_stencil_inv; + bool do_stencil_brush; + bool do_material_slots; bool do_occlude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/ bool do_backfacecull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */ @@ -245,7 +276,6 @@ typedef struct ProjPaintState { bool do_masking; /* use masking during painting. Some operations such as airbrush may disable */ bool is_texbrush; /* only to avoid running */ bool is_maskbrush; /* mask brush is applied before masking */ - bool is_maskbrush_tiled; /* mask brush is applied after masking */ #ifndef PROJ_DEBUG_NOSEAMBLEED float seam_bleed_px; #endif @@ -269,6 +299,10 @@ typedef struct ProjPaintState { /* redraw */ bool need_redraw; + + BlurKernel *blurkernel; + + SpinLock *tile_lock; } ProjPaintState; typedef union pixelPointer { @@ -290,14 +324,16 @@ typedef struct ProjPixel { * Store the max mask value to avoid painting over an area with a lower opacity * with an advantage that we can avoid touching the pixel at all, if the * new mask value is lower then mask_accum */ - unsigned short mask_accum; + unsigned short *mask_accum; /* for various reasons we may want to mask out painting onto this pixel */ unsigned short mask; short x_px, y_px; + /* horrible hack, store tile valid flag pointer here to re-validate tiles used for anchored and drag-dot strokes */ + bool *valid; - PixelStore origColor; + PixelPointer origColor; PixelStore newColor; PixelPointer pixel; @@ -310,33 +346,51 @@ typedef struct ProjPixelClone { PixelStore clonepx; } ProjPixelClone; -/* blur, store surrounding colors */ -#define PROJ_PIXEL_SOFTEN_TOT 4 -/* blur picking offset (in screenspace) */ -#define PROJ_PIXEL_SOFTEN_OFS_PX 1.0f +/* undo tile pushing */ +typedef struct { + SpinLock *lock; + bool masked; + unsigned short tile_width; + ImBuf **tmpibuf; + ProjPaintImage *pjima; +} TileInfo; -static const float proj_pixel_soften_v2[PROJ_PIXEL_SOFTEN_TOT][2] = { - {-PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f}, - { 0.0f, -PROJ_PIXEL_SOFTEN_OFS_PX}, - { 0.0f, PROJ_PIXEL_SOFTEN_OFS_PX}, - { PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f}, -}; /* Finish projection painting structs */ -static Image *project_paint_face_image(const ProjPaintState *ps, MTFace *dm_mtface, int face_index) +static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int face_index) { - Image *ima; + MFace *mf = ps->dm_mface + face_index; + Material *ma = ps->dm->mat[mf->mat_nr]; + return ma->texpaintslot + ma->paint_active_slot; +} - if (ps->do_new_shading_nodes) { /* cached BKE_scene_use_new_shading_nodes result */ - MFace *mf = ps->dm_mface + face_index; - ED_object_get_active_image(ps->ob, mf->mat_nr + 1, &ima, NULL, NULL); +static Image *project_paint_face_paint_image(const ProjPaintState *ps, int face_index) +{ + if (ps->do_stencil_brush) { + return ps->stencil_ima; } else { - ima = dm_mtface[face_index].tpage; + MFace *mf = ps->dm_mface + face_index; + Material *ma = ps->dm->mat[mf->mat_nr]; + TexPaintSlot *slot = ma->texpaintslot + ma->paint_active_slot; + return slot ? slot->ima : ps->canvas_ima; } +} + +static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int face_index) +{ + MFace *mf = ps->dm_mface + face_index; + Material *ma = ps->dm->mat[mf->mat_nr]; + return ma->texpaintslot + ma->paint_clone_slot; +} - return ima; +static Image *project_paint_face_clone_image(const ProjPaintState *ps, int face_index) +{ + MFace *mf = ps->dm_mface + face_index; + Material *ma = ps->dm->mat[mf->mat_nr]; + TexPaintSlot *slot = ma->texpaintslot + ma->paint_clone_slot; + return slot ? slot->ima : ps->clone_ima; } /* fast projection bucket array lookup, use the safe version for bound checking */ @@ -477,8 +531,8 @@ static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], f static void uvco_to_wrapped_pxco(const float uv[2], int ibuf_x, int ibuf_y, float *x, float *y) { /* use */ - *x = (float)fmodf(uv[0], 1.0f); - *y = (float)fmodf(uv[1], 1.0f); + *x = fmodf(uv[0], 1.0f); + *y = fmodf(uv[1], 1.0f); if (*x < 0.0f) *x += 1.0f; if (*y < 0.0f) *y += 1.0f; @@ -505,7 +559,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2], if (face_index == -1) return 0; - tf = ps->dm_mtface + face_index; + tf = *(ps->dm_mtface + face_index); if (side == 0) { interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[1], tf->uv[2], w); @@ -514,8 +568,9 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2], interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[2], tf->uv[3], w); } - ima = project_paint_face_image(ps, ps->dm_mtface, face_index); + ima = project_paint_face_paint_image(ps, face_index); ibuf = BKE_image_get_first_ibuf(ima); /* we must have got the imbuf before getting here */ + if (!ibuf) return 0; if (interp) { float x, y; @@ -762,11 +817,11 @@ static int line_isect_x(const float p1[2], const float p2[2], const float x_leve static bool cmp_uv(const float vec2a[2], const float vec2b[2]) { /* if the UV's are not between 0.0 and 1.0 */ - float xa = (float)fmodf(vec2a[0], 1.0f); - float ya = (float)fmodf(vec2a[1], 1.0f); + float xa = fmodf(vec2a[0], 1.0f); + float ya = fmodf(vec2a[1], 1.0f); - float xb = (float)fmodf(vec2b[0], 1.0f); - float yb = (float)fmodf(vec2b[1], 1.0f); + float xb = fmodf(vec2b[0], 1.0f); + float yb = fmodf(vec2b[1], 1.0f); if (xa < 0.0f) xa += 1.0f; if (ya < 0.0f) ya += 1.0f; @@ -843,7 +898,7 @@ static bool pixel_bounds_array(float (*uv)[2], rcti *bounds_px, const int ibuf_x static void project_face_winding_init(const ProjPaintState *ps, const int face_index) { /* detect the winding of faces in uv space */ - MTFace *tf = ps->dm_mtface + face_index; + MTFace *tf = ps->dm_mtface[face_index]; float winding = cross_tri_v2(tf->uv[0], tf->uv[1], tf->uv[2]); if (ps->dm_mface[face_index].v4) @@ -868,7 +923,7 @@ static bool check_seam(const ProjPaintState *ps, MFace *mf; MTFace *tf; const MFace *orig_mf = ps->dm_mface + orig_face; - const MTFace *orig_tf = ps->dm_mtface + orig_face; + const MTFace *orig_tf = ps->dm_mtface[orig_face]; /* vert indices from face vert order indices */ i1 = (*(&orig_mf->v1 + orig_i1_fidx)); @@ -890,17 +945,19 @@ static bool check_seam(const ProjPaintState *ps, /* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */ if (i2_fidx != -1) { - Image *tpage = project_paint_face_image(ps, ps->dm_mtface, face_index); - Image *orig_tpage = project_paint_face_image(ps, ps->dm_mtface, orig_face); + Image *tpage = project_paint_face_paint_image(ps, face_index); + Image *orig_tpage = project_paint_face_paint_image(ps, orig_face); BLI_assert(i1_fidx != -1); /* This IS an adjacent face!, now lets check if the UVs are ok */ - tf = ps->dm_mtface + face_index; + tf = ps->dm_mtface[face_index]; /* set up the other face */ *other_face = face_index; - *orig_fidx = (i1_fidx < i2_fidx) ? i1_fidx : i2_fidx; + + /* we check if difference is 1 here, else we might have a case of edge 2-0 or 3-0 for quads */ + *orig_fidx = (i1_fidx < i2_fidx && (i2_fidx - i1_fidx == 1)) ? i1_fidx : i2_fidx; /* initialize face winding if needed */ if ((ps->faceWindingFlags[face_index] & PROJ_FACE_WINDING_INIT) == 0) @@ -909,7 +966,7 @@ static bool check_seam(const ProjPaintState *ps, /* first test if they have the same image */ if ((orig_tpage == tpage) && cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) && - cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]) ) + cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx])) { /* if faces don't have the same winding in uv space, * they are on the same side so edge is boundary */ @@ -1168,7 +1225,7 @@ static float project_paint_uvpixel_mask( if (ps->do_layer_stencil) { /* another UV maps image is masking this one's */ ImBuf *ibuf_other; - Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_stencil, face_index); + Image *other_tpage = ps->stencil_ima; const MTFace *tf_other = ps->dm_mtface_stencil + face_index; if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) { @@ -1296,24 +1353,70 @@ static int project_paint_pixel_sizeof(const short tool) } } +static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty) +{ + ProjPaintImage *pjIma = tinf->pjima; + int tile_index = tx + ty * tinf->tile_width; + bool generate_tile = false; + + /* double check lock to avoid locking */ + if (UNLIKELY(!pjIma->undoRect[tile_index])) { + if (tinf->lock) + BLI_spin_lock(tinf->lock); + if (LIKELY(!pjIma->undoRect[tile_index])) { + pjIma->undoRect[tile_index] = TILE_PENDING; + generate_tile = true; + } + if (tinf->lock) + BLI_spin_unlock(tinf->lock); + } + + + if (generate_tile) { + volatile void *undorect; + if (tinf->masked) { + undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true); + } + else { + undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, NULL, &pjIma->valid[tile_index], true); + } + + pjIma->ibuf->userflags |= IB_BITMAPDIRTY; + /* tile ready, publish */ + if (tinf->lock) + BLI_spin_lock(tinf->lock); + pjIma->undoRect[tile_index] = undorect; + if (tinf->lock) + BLI_spin_unlock(tinf->lock); + + } + + return tile_index; +} /* run this function when we know a bucket's, face's pixel can be initialized, * return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */ static ProjPixel *project_paint_uvpixel_init( const ProjPaintState *ps, MemArena *arena, - const ImBuf *ibuf, + const TileInfo *tinf, int x_px, int y_px, const float mask, const int face_index, - const int image_index, const float pixelScreenCo[4], const float world_spaceCo[3], const int side, const float w[3]) { ProjPixel *projPixel; - + int x_tile, y_tile; + int x_round, y_round; + int tile_offset; + /* volatile is important here to ensure pending check is not optimized away by compiler*/ + volatile int tile_index; + + ProjPaintImage *projima = tinf->pjima; + ImBuf *ibuf = projima->ibuf; /* wrap pixel location */ x_px = mod_i(x_px, ibuf->x); @@ -1321,19 +1424,36 @@ static ProjPixel *project_paint_uvpixel_init( BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool)); projPixel = (ProjPixel *)BLI_memarena_alloc(arena, ps->pixel_sizeof); + + /* calculate the undo tile offset of the pixel, used to store the original + * pixel color and accumulated mask if any */ + x_tile = x_px >> IMAPAINT_TILE_BITS; + y_tile = y_px >> IMAPAINT_TILE_BITS; + + x_round = x_tile * IMAPAINT_TILE_SIZE; + y_round = y_tile * IMAPAINT_TILE_SIZE; //memset(projPixel, 0, size); + tile_offset = (x_px - x_round) + (y_px - y_round) * IMAPAINT_TILE_SIZE; + tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile); + + /* other thread may be initializing the tile so wait here */ + while (projima->undoRect[tile_index] == TILE_PENDING) + ; + + BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y))); + BLI_assert(tile_offset < (IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE)); + + projPixel->valid = projima->valid[tile_index]; + if (ibuf->rect_float) { projPixel->pixel.f_pt = ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4); - projPixel->origColor.f[0] = projPixel->pixel.f_pt[0]; - projPixel->origColor.f[1] = projPixel->pixel.f_pt[1]; - projPixel->origColor.f[2] = projPixel->pixel.f_pt[2]; - projPixel->origColor.f[3] = projPixel->pixel.f_pt[3]; + projPixel->origColor.f_pt = (float *)projima->undoRect[tile_index] + 4 * tile_offset; zero_v4(projPixel->newColor.f); } else { - projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x_px + y_px * ibuf->x) * 4)); - projPixel->origColor.uint = *projPixel->pixel.uint_pt; + projPixel->pixel.ch_pt = (unsigned char *)(ibuf->rect + (x_px + y_px * ibuf->x)); + projPixel->origColor.uint_pt = (unsigned int *)projima->undoRect[tile_index] + tile_offset; projPixel->newColor.uint = 0; } @@ -1348,7 +1468,10 @@ static ProjPixel *project_paint_uvpixel_init( projPixel->y_px = y_px; projPixel->mask = (unsigned short)(mask * 65535); - projPixel->mask_accum = 0; + if (ps->do_masking) + projPixel->mask_accum = projima->maskRect[tile_index] + tile_offset; + else + projPixel->mask_accum = NULL; /* which bounding box cell are we in?, needed for undo */ projPixel->bb_cell_index = ((int)(((float)x_px / (float)ibuf->x) * PROJ_BOUNDBOX_DIV)) + @@ -1358,8 +1481,8 @@ static ProjPixel *project_paint_uvpixel_init( if (ps->tool == PAINT_TOOL_CLONE) { if (ps->dm_mtface_clone) { ImBuf *ibuf_other; - Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_clone, face_index); - const MTFace *tf_other = ps->dm_mtface_clone + face_index; + Image *other_tpage = project_paint_face_clone_image(ps, face_index); + const MTFace *tf_other = ps->dm_mtface_clone[face_index]; if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) { /* BKE_image_acquire_ibuf - TODO - this may be slow */ @@ -1423,7 +1546,8 @@ static ProjPixel *project_paint_uvpixel_init( if (ibuf->rect_float) projPixel->pixel.f_pt[0] = 0; else projPixel->pixel.ch_pt[0] = 0; #endif - projPixel->image_index = image_index; + /* pointer arithmetics */ + projPixel->image_index = projima - ps->projImages; return projPixel; } @@ -2131,15 +2255,24 @@ static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot /* One of the most important function for projection painting, since it selects the pixels to be added into each bucket. * initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */ -static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, const ImBuf *ibuf, const short clamp_u, const short clamp_v) +static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf, const short clamp_u, const short clamp_v) { /* Projection vars, to get the 3D locations into screen space */ MemArena *arena = ps->arena_mt[thread_index]; LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index; LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index]; + bool threaded = (ps->thread_tot > 1); + + TileInfo tinf = { + ps->tile_lock, + ps->do_masking, + IMAPAINT_TILE_NUMBER(ibuf->x), + tmpibuf, + ps->projImages + image_index + }; const MFace *mf = ps->dm_mface + face_index; - const MTFace *tf = ps->dm_mtface + face_index; + const MTFace *tf = ps->dm_mtface[face_index]; /* UV/pixel seeking data */ int x; /* Image X-Pixel */ @@ -2183,8 +2316,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i /* Use tf_uv_pxoffset instead of tf->uv so we can offset the UV half a pixel * this is done so we can avoid offsetting all the pixels by 0.5 which causes * problems when wrapping negative coords */ - xhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE * (1.0f / 3.0f))) / ibuf_xf; - yhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE * (1.0f / 4.0f))) / ibuf_yf; + xhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 3.0f))) / ibuf_xf; + yhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 4.0f))) / ibuf_yf; /* Note about (PROJ_GEOM_TOLERANCE/x) above... * Needed to add this offset since UV coords are often quads aligned to pixels. @@ -2258,6 +2391,10 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i CLAMP(bounds_px.ymax, 0, ibuf->y); } + /* + project_paint_undo_tiles_init(&bounds_px, ps->projImages + image_index, tmpibuf, + tile_width, threaded, ps->do_masking); + */ /* clip face and */ has_isect = 0; @@ -2300,8 +2437,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i if (mask > 0.0f) { BLI_linklist_prepend_arena( bucketPixelNodes, - project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, - image_index, pixelScreenCo, wco, side, w), + project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, face_index, + pixelScreenCo, wco, side, w), arena ); } @@ -2333,7 +2470,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i if (ps->seam_bleed_px > 0.0f) { int face_seam_flag; - if (ps->thread_tot > 1) + if (threaded) BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ face_seam_flag = ps->faceSeamFlags[face_index]; @@ -2351,7 +2488,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2 | PROJ_FACE_SEAM3 | PROJ_FACE_SEAM4)) == 0) { - if (ps->thread_tot > 1) + if (threaded) BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ } @@ -2376,7 +2513,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4 != 0); /* ps->faceSeamUVs cant be modified when threading, now this is done we can unlock */ - if (ps->thread_tot > 1) + if (threaded) BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ vCoSS[0] = ps->screenCoords[mf->v1]; @@ -2520,7 +2657,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i if (mask > 0.0f) { BLI_linklist_prepend_arena( bucketPixelNodes, - project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, wco, side, w), + project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, face_index, + pixelScreenCo, wco, side, w), arena ); } @@ -2589,6 +2727,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index ImBuf *ibuf = NULL; Image *tpage_last = NULL, *tpage; Image *ima = NULL; + ImBuf *tmpibuf = NULL; if (ps->image_tot == 1) { /* Simple loop, no context switching */ @@ -2596,7 +2735,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index ima = ps->projImages[0].ima; for (node = ps->bucketFaces[bucket_index]; node; node = node->next) { - project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); + project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, &tmpibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); } } else { @@ -2606,7 +2745,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index face_index = GET_INT_FROM_POINTER(node->link); /* Image context switching */ - tpage = project_paint_face_image(ps, ps->dm_mtface, face_index); + tpage = project_paint_face_paint_image(ps, face_index); if (tpage_last != tpage) { tpage_last = tpage; @@ -2620,10 +2759,13 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index } /* context switching done */ - project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); + project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, &tmpibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); } } + if (tmpibuf) + IMB_freeImBuf(tmpibuf); + ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT; } @@ -2771,11 +2913,17 @@ static void project_paint_begin(ProjPaintState *ps) ProjPaintImage *projIma; Image *tpage_last = NULL, *tpage; + TexPaintSlot *slot_last = NULL, *slot = NULL; + TexPaintSlot *slot_last_clone = NULL, *slot_clone; /* Face vars */ MPoly *mpoly_orig; MFace *mf; - MTFace *tf; + MTFace **tf; + MTFace *tf_base; + + MTFace **tf_clone; + MTFace *tf_clone_base = NULL; int a, i; /* generic looping vars */ int image_index = -1, face_index; @@ -2821,7 +2969,7 @@ static void project_paint_begin(ProjPaintState *ps) ps->dm_release = true; } - if (!CustomData_has_layer(&ps->dm->faceData, CD_MTFACE) ) { + if (!CustomData_has_layer(&ps->dm->faceData, CD_MTFACE)) { if (ps->dm_release) ps->dm->release(ps->dm); @@ -2830,13 +2978,15 @@ static void project_paint_begin(ProjPaintState *ps) return; } - ps->dm_mvert = ps->dm->getVertArray(ps->dm); - ps->dm_mface = ps->dm->getTessFaceArray(ps->dm); - ps->dm_mtface = ps->dm->getTessFaceDataArray(ps->dm, CD_MTFACE); + DM_update_materials(ps->dm, ps->ob); ps->dm_totvert = ps->dm->getNumVerts(ps->dm); ps->dm_totface = ps->dm->getNumTessFaces(ps->dm); + ps->dm_mvert = ps->dm->getVertArray(ps->dm); + ps->dm_mface = ps->dm->getTessFaceArray(ps->dm); + ps->dm_mtface = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces"); + if (ps->do_face_sel) { index_mf_to_mpoly = ps->dm->getTessFaceDataArray(ps->dm, CD_ORIGINDEX); index_mp_to_orig = ps->dm->getPolyDataArray(ps->dm, CD_ORIGINDEX); @@ -2852,32 +3002,36 @@ static void project_paint_begin(ProjPaintState *ps) } /* use clone mtface? */ - - - /* Note, use the original mesh for getting the clone and mask layer index - * this avoids re-generating the derived mesh just to get the new index */ if (ps->do_layer_clone) { - //int layer_num = CustomData_get_clone_layer(&ps->dm->faceData, CD_MTFACE); - int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY); - if (layer_num != -1) - ps->dm_mtface_clone = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num); - - if (ps->dm_mtface_clone == NULL || ps->dm_mtface_clone == ps->dm_mtface) { - ps->do_layer_clone = false; - ps->dm_mtface_clone = NULL; - } + ps->dm_mtface_clone = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces"); } - if (ps->do_layer_stencil) { + if (ps->do_layer_stencil || ps->do_stencil_brush) { //int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData, CD_MTFACE); int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY); if (layer_num != -1) ps->dm_mtface_stencil = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num); - if (ps->dm_mtface_stencil == NULL || ps->dm_mtface_stencil == ps->dm_mtface) { - ps->do_layer_stencil = false; - ps->dm_mtface_stencil = NULL; + if (ps->dm_mtface_stencil == NULL) { + /* get active instead */ + ps->dm_mtface_stencil = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); } + + if (ps->do_stencil_brush) + tf_base = ps->dm_mtface_stencil; + } + + if (ps->do_layer_clone) { + int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY); + + if (layer_num != -1) + tf_clone_base = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num); + + if (tf_clone_base == NULL) { + /* get active instead */ + tf_clone_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); + } + } /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */ @@ -3092,6 +3246,13 @@ static void project_paint_begin(ProjPaintState *ps) if (reset_threads) ps->thread_tot = 1; + if (ps->thread_tot > 1) { + ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock"); + BLI_spin_init(ps->tile_lock); + } + + image_undo_init_locks(); + for (a = 0; a < ps->thread_tot; a++) { ps->arena_mt[a] = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "project paint arena"); } @@ -3153,7 +3314,60 @@ static void project_paint_begin(ProjPaintState *ps) is_face_sel = true; } - if (is_face_sel && (tpage = project_paint_face_image(ps, ps->dm_mtface, face_index))) { + if (!ps->do_stencil_brush) { + slot = project_paint_face_paint_slot(ps, face_index); + /* all faces should have a valid slot, reassert here */ + if (slot == NULL) { + tf_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); + tpage = ps->canvas_ima; + } + else { + if (slot != slot_last) { + if (!slot->uvname || !(tf_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot->uvname))) + tf_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); + slot_last = slot; + } + + /* don't allow using the same inage for painting and stencilling */ + if (slot->ima == ps->stencil_ima) + continue; + + tpage = slot->ima; + } + } + else { + tpage = ps->stencil_ima; + } + + *tf = tf_base + face_index; + + if (ps->do_layer_clone) { + if (ps->do_material_slots) { + slot_clone = project_paint_face_clone_slot(ps, face_index); + /* all faces should have a valid slot, reassert here */ + if (ELEM(slot_clone, NULL, slot)) + continue; + } + else if (ps->clone_ima == ps->canvas_ima) + continue; + + tf_clone = ps->dm_mtface_clone + face_index; + + if (ps->do_material_slots) { + if (slot_clone != slot_last_clone) { + if (!slot->uvname || !(tf_clone_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot_clone->uvname))) + tf_clone_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); + slot_last_clone = slot_clone; + } + } + + *tf_clone = tf_clone_base + face_index; + } + + /* tfbase here should be non-null! */ + BLI_assert (tf_base != NULL); + + if (is_face_sel && tpage) { const float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL; v1coSS = ps->screenCoords[mf->v1]; @@ -3251,10 +3465,19 @@ static void project_paint_begin(ProjPaintState *ps) projIma = ps->projImages = (ProjPaintImage *)BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot); for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) { + int size; projIma->ima = node->link; projIma->touch = 0; projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL); - projIma->partRedrawRect = BLI_memarena_calloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); + size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(projIma->ibuf->y); + projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); + memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); + projIma->undoRect = (volatile void **) BLI_memarena_alloc(arena, size); + memset(projIma->undoRect, 0, size); + projIma->maskRect = (unsigned short **) BLI_memarena_alloc(arena, size); + memset(projIma->maskRect, 0, size); + projIma->valid = (bool **) BLI_memarena_alloc(arena, size); + memset(projIma->valid, 0, size); } /* we have built the array, discard the linked list */ @@ -3281,95 +3504,12 @@ static void project_paint_end(ProjPaintState *ps) int a; ProjPaintImage *projIma; - /* build undo data from original pixel colors */ - if (U.uiflag & USER_GLOBALUNDO) { - ProjPixel *projPixel; - ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL; - LinkNode *pixel_node; - void *tilerect; - MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */ - - int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */ - int bucket_index; - int tile_index; - int x_round, y_round; - int x_tile, y_tile; - int is_float = -1; - - /* context */ - ProjPaintImage *last_projIma; - int last_image_index = -1; - int last_tile_width = 0; - - for (a = 0, last_projIma = ps->projImages; a < ps->image_tot; a++, last_projIma++) { - int size = sizeof(void **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y); - last_projIma->undoRect = (void **) BLI_memarena_calloc(arena, size); - last_projIma->ibuf->userflags |= IB_BITMAPDIRTY; - } - - for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) { - /* loop through all pixels */ - for (pixel_node = ps->bucketRect[bucket_index]; pixel_node; pixel_node = pixel_node->next) { - - /* ok we have a pixel, was it modified? */ - projPixel = (ProjPixel *)pixel_node->link; - - if (last_image_index != projPixel->image_index) { - /* set the context */ - last_image_index = projPixel->image_index; - last_projIma = ps->projImages + last_image_index; - last_tile_width = IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x); - is_float = last_projIma->ibuf->rect_float ? 1 : 0; - } - - - if ((is_float == 0 && projPixel->origColor.uint != *projPixel->pixel.uint_pt) || - (is_float == 1 && - (projPixel->origColor.f[0] != projPixel->pixel.f_pt[0] || - projPixel->origColor.f[1] != projPixel->pixel.f_pt[1] || - projPixel->origColor.f[2] != projPixel->pixel.f_pt[2] || - projPixel->origColor.f[3] != projPixel->pixel.f_pt[3])) - ) - { - - x_tile = projPixel->x_px >> IMAPAINT_TILE_BITS; - y_tile = projPixel->y_px >> IMAPAINT_TILE_BITS; - - x_round = x_tile * IMAPAINT_TILE_SIZE; - y_round = y_tile * IMAPAINT_TILE_SIZE; - - tile_index = x_tile + y_tile * last_tile_width; - - if (last_projIma->undoRect[tile_index] == NULL) { - /* add the undo tile from the modified image, then write the original colors back into it */ - tilerect = last_projIma->undoRect[tile_index] = image_undo_push_tile(last_projIma->ima, last_projIma->ibuf, is_float ? (&tmpibuf_float) : (&tmpibuf), x_tile, y_tile); - } - else { - tilerect = last_projIma->undoRect[tile_index]; - } - - /* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color - * because allocating the tiles along the way slows down painting */ - - if (is_float) { - float *rgba_fp = (float *)tilerect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4; - copy_v4_v4(rgba_fp, projPixel->origColor.f); - } - else { - ((unsigned int *)tilerect)[(projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE] = projPixel->origColor.uint; - } - } - } - } - - if (tmpibuf) IMB_freeImBuf(tmpibuf); - if (tmpibuf_float) IMB_freeImBuf(tmpibuf_float); - } - /* done calculating undo data */ + image_undo_remove_masks(); /* dereference used image buffers */ for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) { BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL); + DAG_id_tag_update(&projIma->ima->id, 0); } BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL); @@ -3378,6 +3518,14 @@ static void project_paint_end(ProjPaintState *ps) MEM_freeN(ps->bucketRect); MEM_freeN(ps->bucketFaces); MEM_freeN(ps->bucketFlags); + MEM_freeN(ps->dm_mtface); + if (ps->do_layer_clone) + MEM_freeN(ps->dm_mtface_clone); + if (ps->thread_tot > 1) { + BLI_spin_end(ps->tile_lock); + MEM_freeN((void *)ps->tile_lock); + } + image_undo_end_locks(); #ifndef PROJ_DEBUG_NOSEAMBLEED if (ps->seam_bleed_px > 0.0f) { @@ -3388,6 +3536,11 @@ static void project_paint_end(ProjPaintState *ps) } #endif + if (ps->blurkernel) { + paint_delete_blur_kernel(ps->blurkernel); + MEM_freeN(ps->blurkernel); + } + if (ps->vertFlags) MEM_freeN(ps->vertFlags); for (a = 0; a < ps->thread_tot; a++) { @@ -3480,7 +3633,7 @@ static bool project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2]) { if (ps->source == PROJ_SRC_VIEW) { float min_brush[2], max_brush[2]; - const float radius = (float)BKE_brush_size_get(ps->scene, ps->brush); + const float radius = ps->brush_size; /* so we don't have a bucket bounds that is way too small to paint into */ // if (radius < 1.0f) radius = 1.0f; // this doesn't work yet :/ @@ -3518,7 +3671,7 @@ static bool project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2]) static bool project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf *bucket_bounds, const float mval[2]) { - const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush); + const int diameter = 2 * ps->brush_size; if (ps->thread_tot > 1) BLI_lock_thread(LOCK_CUSTOM1); @@ -3580,7 +3733,7 @@ static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, floa clone_rgba[3] = (unsigned char)(clone_pt[3] * mask); if (ps->do_masking) { - IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch, clone_rgba, ps->blend); + IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, clone_rgba, ps->blend); } else { IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, clone_rgba, ps->blend); @@ -3598,7 +3751,7 @@ static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, fl mul_v4_v4fl(clone_rgba, clone_pt, mask); if (ps->do_masking) { - IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f, clone_rgba, ps->blend); + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, clone_rgba, ps->blend); } else { IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, clone_rgba, ps->blend); @@ -3636,42 +3789,58 @@ static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, fl BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena); } -/* do_projectpaint_soften for float & byte - */ -static float inv_pow2(float f) -{ - f = 1.0f - f; - f = f * f; - return 1.0f - f; -} - static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, float mask, MemArena *softenArena, LinkNode **softenPixels) { - unsigned int accum_tot = 0; - unsigned int i; - + float accum_tot = 0.0f; + int xk, yk; + BlurKernel *kernel = ps->blurkernel; float *rgba = projPixel->newColor.f; - /* sigh, mask values tend to need to be a _lot_ stronger with blur */ - mask = inv_pow2(mask); - /* rather then painting, accumulate surrounding colors */ zero_v4(rgba); - for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) { - float co_ofs[2]; - float rgba_tmp[4]; - sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]); - if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) { - add_v4_v4(rgba, rgba_tmp); - accum_tot++; + for (yk = 0; yk < kernel->side; yk++) { + for (xk = 0; xk < kernel->side; xk++) { + float rgba_tmp[4]; + float co_ofs[2] = {2.0f * xk - 1.0f, 2.0f * yk - 1.0f}; + + add_v2_v2(co_ofs, projPixel->projCoSS); + + if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) { + float weight = kernel->wdata[xk + yk * kernel->side]; + mul_v4_fl(rgba_tmp, weight); + add_v4_v4(rgba, rgba_tmp); + accum_tot += weight; + } } } if (LIKELY(accum_tot != 0)) { mul_v4_fl(rgba, 1.0f / (float)accum_tot); - blend_color_interpolate_float(rgba, rgba, projPixel->pixel.f_pt, mask); + + if (ps->mode == BRUSH_STROKE_INVERT) { + /* subtract blurred image from normal image gives high pass filter */ + sub_v3_v3v3(rgba, projPixel->pixel.f_pt, rgba); + + /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid + * colored speckles appearing in final image, and also to check for threshold */ + rgba[0] = rgba[1] = rgba[2] = rgb_to_grayscale(rgba); + if (fabsf(rgba[0]) > ps->brush->sharp_threshold) { + float alpha = projPixel->pixel.f_pt[3]; + projPixel->pixel.f_pt[3] = rgba[3] = mask; + + /* add to enhance edges */ + blend_color_add_float(rgba, projPixel->pixel.f_pt, rgba); + rgba[3] = alpha; + } + else + return; + } + else { + blend_color_interpolate_float(rgba, rgba, projPixel->pixel.f_pt, mask); + } + BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena); } } @@ -3679,24 +3848,27 @@ static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, f static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, float mask, MemArena *softenArena, LinkNode **softenPixels) { - unsigned int accum_tot = 0; - unsigned int i; - + float accum_tot = 0; + int xk, yk; + BlurKernel *kernel = ps->blurkernel; float rgba[4]; /* convert to byte after */ - /* sigh, mask values tend to need to be a _lot_ stronger with blur */ - mask = inv_pow2(mask); - /* rather then painting, accumulate surrounding colors */ zero_v4(rgba); - for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) { - float co_ofs[2]; - float rgba_tmp[4]; - sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]); - if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) { - add_v4_v4(rgba, rgba_tmp); - accum_tot++; + for (yk = 0; yk < kernel->side; yk++) { + for (xk = 0; xk < kernel->side; xk++) { + float rgba_tmp[4]; + float co_ofs[2] = {2.0f * xk - 1.0f, 2.0f * yk - 1.0f}; + + add_v2_v2(co_ofs, projPixel->projCoSS); + + if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) { + float weight = kernel->wdata[xk + yk * kernel->side]; + mul_v4_fl(rgba_tmp, weight); + add_v4_v4(rgba, rgba_tmp); + accum_tot += weight; + } } } @@ -3704,9 +3876,34 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo unsigned char *rgba_ub = projPixel->newColor.ch; mul_v4_fl(rgba, 1.0f / (float)accum_tot); - premul_float_to_straight_uchar(rgba_ub, rgba); - blend_color_interpolate_byte(rgba_ub, rgba_ub, projPixel->pixel.ch_pt, mask); + if (ps->mode == BRUSH_STROKE_INVERT) { + float rgba_pixel[4]; + + straight_uchar_to_premul_float(rgba_pixel, projPixel->pixel.ch_pt); + + /* subtract blurred image from normal image gives high pass filter */ + sub_v3_v3v3(rgba, rgba_pixel, rgba); + /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid + * colored speckles appearing in final image, and also to check for threshold */ + rgba[0] = rgba[1] = rgba[2] = rgb_to_grayscale(rgba); + if (fabsf(rgba[0]) > ps->brush->sharp_threshold) { + float alpha = rgba_pixel[3]; + rgba[3] = rgba_pixel[3] = mask; + + /* add to enhance edges */ + blend_color_add_float(rgba, rgba_pixel, rgba); + + rgba[3] = alpha; + premul_float_to_straight_uchar(rgba_ub, rgba); + } + else + return; + } + else { + premul_float_to_straight_uchar(rgba_ub, rgba); + blend_color_interpolate_byte(rgba_ub, rgba_ub, projPixel->pixel.ch_pt, mask); + } BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena); } } @@ -3716,7 +3913,7 @@ static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const float rgb[3]; unsigned char rgba_ub[4]; - copy_v3_v3(rgb, ps->brush->rgb); + copy_v3_v3(rgb, ps->paint_color); if (ps->is_texbrush) { mul_v3_v3(rgb, texrgb); @@ -3728,7 +3925,7 @@ static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const rgba_ub[3] = f_to_char(mask); if (ps->do_masking) { - IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch, rgba_ub, ps->blend); + IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend); } else { IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend); @@ -3739,7 +3936,7 @@ static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, con { float rgba[4]; - srgb_to_linearrgb_v3_v3(rgba, ps->brush->rgb); + copy_v3_v3(rgba, ps->paint_color_linear); if (ps->is_texbrush) mul_v3_v3(rgba, texrgb); @@ -3748,13 +3945,42 @@ static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, con rgba[3] = mask; if (ps->do_masking) { - IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f, rgba, ps->blend); + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend); } else { IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend); } } +static void do_projectpaint_mask(ProjPaintState *ps, ProjPixel *projPixel, float mask) +{ + unsigned char rgba_ub[4]; + rgba_ub[0] = rgba_ub[1] = rgba_ub[2] = ps->stencil_value * 255.0f; + rgba_ub[3] = f_to_char(mask); + + if (ps->do_masking) { + IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend); + } + else { + IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend); + } +} + +static void do_projectpaint_mask_f(ProjPaintState *ps, ProjPixel *projPixel, float mask) +{ + float rgba[4]; + rgba[0] = rgba[1] = rgba[2] = ps->stencil_value; + rgba[3] = mask; + + if (ps->do_masking) { + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend); + } + else { + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend); + } +} + + /* run this for single and multithreaded painting */ static void *do_projectpaint_thread(void *ph_v) { @@ -3788,7 +4014,7 @@ static void *do_projectpaint_thread(void *ph_v) float co[2]; unsigned short mask_short; const float brush_alpha = BKE_brush_alpha_get(ps->scene, brush); - const float brush_radius = (float)BKE_brush_size_get(ps->scene, brush); + const float brush_radius = ps->brush_size; const float brush_radius_sq = brush_radius * brush_radius; /* avoid a square root with every dist comparison */ short lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ? 0 : brush->flag & BRUSH_LOCK_ALPHA; @@ -3838,32 +4064,107 @@ static void *do_projectpaint_thread(void *ph_v) } /* end copy */ - if (is_floatbuf) { - /* re-project buffer is assumed byte - TODO, allow float */ - bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, - projPixel->projCoSS[0], projPixel->projCoSS[1]); - if (projPixel->newColor.ch[3]) { - float newColor_f[4]; - float mask = ((float)projPixel->mask) * (1.0f / 65535.0f); + /* fill tools */ + if (ps->source == PROJ_SRC_VIEW_FILL) { + if (brush->flag & BRUSH_USE_GRADIENT) { + /* these could probably be cached instead of being done per pixel */ + float tangent[2]; + float line_len_sq_inv, line_len; + float f; + float color_f[4]; + float p[2] = {projPixel->projCoSS[0] - lastpos[0], projPixel->projCoSS[1] - lastpos[1]}; + + sub_v2_v2v2(tangent, pos, lastpos); + line_len = len_squared_v2(tangent); + line_len_sq_inv = 1.0f / line_len; + line_len = sqrt(line_len); + + switch (brush->gradient_fill_mode) { + case BRUSH_GRADIENT_LINEAR: + { + f = dot_v2v2(p, tangent) * line_len_sq_inv; + break; + } + case BRUSH_GRADIENT_RADIAL: + { + f = len_v2(p) / line_len; + break; + } + } + do_colorband(brush->gradient, f, color_f); + color_f[3] *= ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha; + + if (is_floatbuf) { + /* convert to premultipied */ + mul_v3_fl(color_f, color_f[3]); + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, + color_f, ps->blend); + } + else { + rgba_float_to_uchar(projPixel->newColor.ch, color_f); + IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, + projPixel->newColor.ch, ps->blend); + } + } + else { + if (is_floatbuf) { + float newColor_f[4]; + newColor_f[3] = ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha; + copy_v3_v3(newColor_f, ps->paint_color_linear); - 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); - mul_v4_v4fl(newColor_f, newColor_f, mask); + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, + newColor_f, ps->blend); + } + else { + float mask = ((float)projPixel->mask) * (1.0f / 65535.0f); + projPixel->newColor.ch[3] = mask * 255 * brush->alpha; - blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, - newColor_f); + rgb_float_to_uchar(projPixel->newColor.ch, ps->paint_color); + IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, + projPixel->newColor.ch, ps->blend); + } } + + if (lock_alpha) { + if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f_pt[3]; + else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3]; + } + + last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index; + last_partial_redraw_cell->x1 = min_ii(last_partial_redraw_cell->x1, (int)projPixel->x_px); + last_partial_redraw_cell->y1 = min_ii(last_partial_redraw_cell->y1, (int)projPixel->y_px); + + last_partial_redraw_cell->x2 = max_ii(last_partial_redraw_cell->x2, (int)projPixel->x_px + 1); + last_partial_redraw_cell->y2 = max_ii(last_partial_redraw_cell->y2, (int)projPixel->y_px + 1); } else { - /* re-project buffer is assumed byte - TODO, allow float */ - bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, - projPixel->projCoSS[0], projPixel->projCoSS[1]); - if (projPixel->newColor.ch[3]) { - float mask = ((float)projPixel->mask) * (1.0f / 65535.0f); - projPixel->newColor.ch[3] *= mask; - - blend_color_mix_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch, - projPixel->newColor.ch); + if (is_floatbuf) { + /* re-project buffer is assumed byte - TODO, allow float */ + bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, + projPixel->projCoSS[0], projPixel->projCoSS[1]); + if (projPixel->newColor.ch[3]) { + float newColor_f[4]; + 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); + mul_v4_v4fl(newColor_f, newColor_f, mask); + + blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, + newColor_f); + } + } + else { + /* re-project buffer is assumed byte - TODO, allow float */ + bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, + projPixel->projCoSS[0], projPixel->projCoSS[1]); + if (projPixel->newColor.ch[3]) { + float mask = ((float)projPixel->mask) * (1.0f / 65535.0f); + projPixel->newColor.ch[3] *= mask; + + blend_color_mix_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, + projPixel->newColor.ch); + } } } } @@ -3885,7 +4186,7 @@ static void *do_projectpaint_thread(void *ph_v) if (falloff > 0.0f) { float texrgb[3]; - float mask = falloff; + float mask; if (ps->do_masking) { /* masking to keep brush contribution to a pixel limited. note we do not do @@ -3894,20 +4195,24 @@ static void *do_projectpaint_thread(void *ph_v) * * Instead we use a formula that adds up but approaches brush_alpha slowly * and never exceeds it, which gives nice smooth results. */ - float mask_accum = projPixel->mask_accum; + float mask_accum = *projPixel->mask_accum; + float max_mask = brush_alpha * falloff * 65535.0f; if (ps->is_maskbrush) { float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool); - CLAMP(texmask, 0.0f, 1.0f); - mask = mask_accum + (brush_alpha * texmask * 65535.0f - mask_accum) * mask; - } - else { - mask = mask_accum + (brush_alpha * 65535.0f - mask_accum) * mask; + max_mask *= texmask; } + + if (brush->flag & BRUSH_ACCUMULATE) + mask = mask_accum + max_mask; + else + mask = mask_accum + (max_mask - mask_accum * falloff); + + mask = min_ff(mask, 65535.0f); mask_short = (unsigned short)mask; - if (mask_short > projPixel->mask_accum) { - projPixel->mask_accum = mask_short; + if (mask_short > *projPixel->mask_accum) { + *projPixel->mask_accum = mask_short; mask = mask_short * (1.0f / 65535.0f); } else { @@ -3916,7 +4221,7 @@ static void *do_projectpaint_thread(void *ph_v) } } else { - mask *= brush_alpha; + mask = brush_alpha * falloff; if (ps->is_maskbrush) { float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool); CLAMP(texmask, 0.0f, 1.0f); @@ -3945,10 +4250,6 @@ static void *do_projectpaint_thread(void *ph_v) mask *= texrgba[3]; } - if (ps->is_maskbrush_tiled) { - mask *= BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool); - } - /* extra mask for normal, layer stencil, .. */ mask *= ((float)projPixel->mask) * (1.0f / 65535.0f); @@ -3964,6 +4265,9 @@ static void *do_projectpaint_thread(void *ph_v) } /* end copy */ + /* validate undo tile, since we will modify t*/ + *projPixel->valid = true; + last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index; last_partial_redraw_cell->x1 = min_ii(last_partial_redraw_cell->x1, (int)projPixel->x_px); last_partial_redraw_cell->y1 = min_ii(last_partial_redraw_cell->y1, (int)projPixel->y_px); @@ -3987,6 +4291,10 @@ static void *do_projectpaint_thread(void *ph_v) if (is_floatbuf) do_projectpaint_soften_f(ps, projPixel, mask, softenArena, &softenPixels_f); else do_projectpaint_soften(ps, projPixel, mask, softenArena, &softenPixels); break; + case PAINT_TOOL_MASK: + if (is_floatbuf) do_projectpaint_mask_f(ps, projPixel, mask); + else do_projectpaint_mask(ps, projPixel, mask); + break; default: if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, texrgb, mask); else do_projectpaint_draw(ps, projPixel, texrgb, mask); @@ -3995,8 +4303,8 @@ static void *do_projectpaint_thread(void *ph_v) } if (lock_alpha) { - if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f[3]; - else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch[3]; + if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f_pt[3]; + else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3]; } /* done painting */ @@ -4114,14 +4422,20 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po } -void paint_proj_stroke(bContext *C, void *pps, const float prev_pos[2], const float pos[2]) +void paint_proj_stroke(const bContext *C, void *pps, const float prev_pos[2], const float pos[2], const bool eraser, float pressure, float distance, float size) { ProjPaintState *ps = pps; + Brush *brush = ps->brush; + Scene *scene = ps->scene; int a; + ps->brush_size = size; + ps->blend = brush->blend; + if (eraser) + ps->blend = IMB_BLEND_ERASE_ALPHA; + /* clone gets special treatment here to avoid going through image initialization */ if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) { - Scene *scene = ps->scene; View3D *v3d = ps->v3d; float *cursor = ED_view3d_cursor3d_get(scene, v3d); int mval_i[2] = {(int)pos[0], (int)pos[1]}; @@ -4136,6 +4450,25 @@ void paint_proj_stroke(bContext *C, void *pps, const float prev_pos[2], const fl return; } + /* handle gradient and inverted stroke color here */ + if (ps->tool == PAINT_TOOL_DRAW) { + paint_brush_color_get(scene, brush, false, ps->mode == BRUSH_STROKE_INVERT, distance, pressure, ps->paint_color, NULL); + srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color); + } + else if (ps->tool == PAINT_TOOL_FILL) { + copy_v3_v3(ps->paint_color, BKE_brush_color_get(scene, brush)); + srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color); + } + else if (ps->tool == PAINT_TOOL_MASK) { + ps->stencil_value = brush->weight; + + if ((ps->mode == BRUSH_STROKE_INVERT) ^ + ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0)) + { + ps->stencil_value = 1.0f - ps->stencil_value; + } + } + /* continue adding to existing partial redraw rects until redraw */ if (!ps->need_redraw) { for (a = 0; a < ps->image_tot; a++) @@ -4160,30 +4493,24 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int Brush *brush = ps->brush; ps->tool = brush->imagepaint_tool; ps->blend = brush->blend; + /* only check for inversion for the soften tool, elsewhere, a resident brush inversion flag can cause issues */ + if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) { + ps->mode = ((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0) ? + BRUSH_STROKE_INVERT : BRUSH_STROKE_NORMAL); + + ps->blurkernel = paint_new_blur_kernel(brush, true); + } /* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */ - ps->do_masking = (brush->flag & BRUSH_AIRBRUSH || - (brush->imagepaint_tool == PAINT_TOOL_SMEAR) || - (brush->mtex.tex && !ELEM3(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D))) - ? false : true; + ps->do_masking = paint_use_opacity_masking(brush); ps->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false; - ps->is_maskbrush = false; - ps->is_maskbrush_tiled = false; - if (brush->mask_mtex.tex) { - if (ELEM(brush->mask_mtex.brush_map_mode, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_TILED)) { - ps->is_maskbrush_tiled = true; - } - else { - ps->is_maskbrush = true; - } - } + ps->is_maskbrush = (brush->mask_mtex.tex) ? true : false; } else { /* brush may be NULL*/ ps->do_masking = false; ps->is_texbrush = false; ps->is_maskbrush = false; - ps->is_maskbrush_tiled = false; } /* sizeof(ProjPixel), since we alloc this a _lot_ */ @@ -4198,6 +4525,13 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int ps->scene = scene; ps->ob = ob; /* allow override of active object */ + ps->do_material_slots = (settings->imapaint.mode == IMAGEPAINT_MODE_MATERIAL); + ps->stencil_ima = settings->imapaint.stencil; + ps->canvas_ima = (!ps->do_material_slots) ? + settings->imapaint.canvas : NULL; + ps->clone_ima = (!ps->do_material_slots) ? + settings->imapaint.clone : NULL; + /* setup projection painting data */ ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1; ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1; @@ -4207,8 +4541,11 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int if (ps->tool == PAINT_TOOL_CLONE) ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) ? 1 : 0; - ps->do_layer_stencil = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? 1 : 0; - ps->do_layer_stencil_inv = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) ? 1 : 0; + ps->do_stencil_brush = ps->brush->imagepaint_tool == PAINT_TOOL_MASK; + /* deactivate stenciling for the stencil brush :) */ + ps->do_layer_stencil = ((settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) && + !(ps->do_stencil_brush) && ps->stencil_ima); + ps->do_layer_stencil_inv = ((settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0); #ifndef PROJ_DEBUG_NOSEAMBLEED @@ -4236,6 +4573,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int mode) { ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState"); + project_state_init(C, ob, ps, mode); if (ps->tool == PAINT_TOOL_CLONE && mode == BRUSH_STROKE_INVERT) { @@ -4268,6 +4606,10 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m paint_proj_begin_clone(ps, mouse); + /* special full screen draw mode for fill tool */ + if (ps->tool == PAINT_TOOL_FILL) + ps->source = PROJ_SRC_VIEW_FILL; + return ps; } @@ -4316,8 +4658,11 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) int orig_brush_size; IDProperty *idgroup; IDProperty *view_data = NULL; + Object *ob = OBACT; + + paint_proj_mesh_data_ensure(C, ob, op); - project_state_init(C, OBACT, &ps, BRUSH_STROKE_NORMAL); + project_state_init(C, ob, &ps, BRUSH_STROKE_NORMAL); if (ps.ob == NULL || ps.ob->type != OB_MESH) { BKE_report(op->reports, RPT_ERROR, "No active mesh object"); @@ -4365,7 +4710,6 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) /* override */ ps.is_texbrush = false; ps.is_maskbrush = false; - ps.is_maskbrush_tiled = false; ps.do_masking = false; orig_brush_size = BKE_brush_size_get(scene, ps.brush); BKE_brush_size_set(scene, ps.brush, 32); /* cover the whole image */ @@ -4375,7 +4719,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING; ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, - ED_image_undo_restore, ED_image_undo_free); + ED_image_undo_restore, ED_image_undo_free, NULL); /* allocate and initialize spatial data structures */ project_paint_begin(&ps); @@ -4508,3 +4852,338 @@ void PAINT_OT_image_from_view(wmOperatorType *ot) RNA_def_string_file_name(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Name of the file"); } + +/********************************************* + * Data generation for projective texturing * + * *******************************************/ + + +/* Make sure that active object has a material, and assign UVs and image layers if they do not exist */ +void paint_proj_mesh_data_ensure(bContext *C, Object *ob, wmOperator *op) +{ + Mesh *me; + int layernum; + ImagePaintSettings *imapaint = &(CTX_data_tool_settings(C)->imapaint); + bScreen *sc; + Scene *scene = CTX_data_scene(C); + Main *bmain = CTX_data_main(C); + Brush *br = BKE_paint_brush(&imapaint->paint); + + /* no material, add one */ + if (ob->totcol == 0) { + Material *ma = BKE_material_add(CTX_data_main(C), "Material"); + /* no material found, just assign to first slot */ + assign_material(ob, ma, 1, BKE_MAT_ASSIGN_USERPREF); + proj_paint_add_slot(C, ma, NULL); + } + else { + /* there may be material slots but they may be empty, check */ + int i; + + for (i = 1; i < ob->totcol + 1; i++) { + Material *ma = give_current_material(ob, i); + + if (ma) { + if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) { + if (!ma->texpaintslot) { + /* refresh here just in case */ + BKE_texpaint_slot_refresh_cache(scene, ma); + + /* if still no slots, we have to add */ + if (!ma->texpaintslot) { + proj_paint_add_slot(C, ma, NULL); + + if (ma->texpaintslot) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + ScrArea *sa; + for (sa = sc->areabase.first; sa; sa = sa->next) { + SpaceLink *sl; + for (sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_IMAGE) { + SpaceImage *sima = (SpaceImage *)sl; + + ED_space_image_set(sima, scene, scene->obedit, ma->texpaintslot[0].ima); + } + } + } + } + } + } + } + } + } + else { + Material *ma = BKE_material_add(CTX_data_main(C), "Material"); + /* no material found, just assign to first slot */ + assign_material(ob, ma, i, BKE_MAT_ASSIGN_USERPREF); + proj_paint_add_slot(C, ma, NULL); + } + } + } + + if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) { + if (imapaint->canvas == NULL) { + int width; + int height; + Main *bmain = CTX_data_main(C); + float color[4] = {0.0, 0.0, 0.0, 1.0}; + + width = 1024; + height = 1024; + imapaint->canvas = BKE_image_add_generated(bmain, width, height, "Canvas", 32, false, IMA_GENTYPE_BLANK, color); + + GPU_drawobject_free(ob->derivedFinal); + + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + ScrArea *sa; + for (sa = sc->areabase.first; sa; sa = sa->next) { + SpaceLink *sl; + for (sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_IMAGE) { + SpaceImage *sima = (SpaceImage *)sl; + + ED_space_image_set(sima, scene, scene->obedit, imapaint->canvas); + } + } + } + } + } + } + + me = BKE_mesh_from_object(ob); + layernum = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY); + + if (layernum == 0) { + BKE_reportf(op->reports, RPT_WARNING, "Object did not have UV map, manual unwrap recommended"); + + ED_mesh_uv_texture_add(me, "UVMap", true); + } + + /* Make sure we have a stencil to paint on! */ + if (br && br->imagepaint_tool == PAINT_TOOL_MASK) { + imapaint->flag |= IMAGEPAINT_PROJECT_LAYER_STENCIL; + + if (imapaint->stencil == NULL) { + int width; + int height; + Main *bmain = CTX_data_main(C); + float color[4] = {0.0, 0.0, 0.0, 1.0}; + + width = 1024; + height = 1024; + imapaint->stencil = BKE_image_add_generated(bmain, width, height, "Stencil", 32, false, IMA_GENTYPE_BLANK, color); + } + } +} + +/* Add layer operator */ + +static EnumPropertyItem layer_type_items[] = { + {MAP_COL, "DIFFUSE_COLOR", 0, "Diffuse Color", ""}, + {MAP_REF, "DIFFUSE_INTENSITY", 0, "Diffuse Intensity", ""}, + {MAP_ALPHA, "ALPHA", 0, "Alpha", ""}, + {MAP_TRANSLU, "TRANSLUCENCY", 0, "Translucency", ""}, + {MAP_COLSPEC, "SPECULAR_COLOR", 0, "Specular Color", ""}, + {MAP_SPEC, "SPECULAR_INTENSITY", 0, "Specular Intensity", ""}, + {MAP_HAR, "SPECULAR_HARDNESS", 0, "Specular Hardness", ""}, + {MAP_AMB, "AMBIENT", 0, "Ambient", ""}, + {MAP_EMIT, "EMMIT", 0, "Emmit", ""}, + {MAP_COLMIR, "MIRROR_COLOR", 0, "Mirror Color", ""}, + {MAP_RAYMIRR, "RAYMIRROR", 0, "Ray Mirror", ""}, + {MAP_NORM, "NORMAL", 0, "Normal", ""}, + {MAP_WARP, "WARP", 0, "Warp", ""}, + {MAP_DISPLACE, "DISPLACE", 0, "Displace", ""}, + {0, NULL, 0, NULL, NULL} +}; + +bool proj_paint_add_slot(bContext *C, Material *ma, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); + bool is_bi = BKE_scene_uses_blender_internal(scene); + + if (!ob) + return false; + + if (!ma) + ma = give_current_material(ob, ob->actcol); + + if (ma) { + + if (!is_bi || ma->use_nodes) { + /* not supported for now */ + } + else { + MTex *mtex = add_mtex_id(&ma->id, -1); + + /* successful creation of mtex layer, now create set */ + if (mtex) { + Main *bmain = CTX_data_main(C); + Image *ima; + int type = MAP_COL; + int type_id = 0; + + if (op) { + int i; + type = RNA_enum_get(op->ptr, "type"); + + for (i = 0; i < ARRAY_SIZE(layer_type_items); i++) { + if (layer_type_items[i].value == type) { + type_id = i; + break; + } + } + } + + mtex->tex = add_texture(bmain, DATA_(layer_type_items[type_id].name)); + mtex->mapto = type; + + if (mtex->tex) { + float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + char imagename[MAX_ID_NAME - 2] = "Material Diffuse Color"; + int width = 1024; + int height = 1024; + bool use_float = false; + short gen_type = IMA_GENTYPE_BLANK; + bool alpha = false; + + if (op) { + width = RNA_int_get(op->ptr, "width"); + height = RNA_int_get(op->ptr, "height"); + use_float = RNA_boolean_get(op->ptr, "float"); + gen_type = RNA_enum_get(op->ptr, "generated_type"); + RNA_float_get_array(op->ptr, "color", color); + alpha = RNA_boolean_get(op->ptr, "alpha"); + RNA_string_get(op->ptr, "name", imagename); + } + + ima = mtex->tex->ima = BKE_image_add_generated(bmain, width, height, imagename, alpha ? 32 : 24, use_float, + gen_type, color); + + BKE_texpaint_slot_refresh_cache(scene, ma); + BKE_image_signal(ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE); + WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, mtex->tex); + WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima); + DAG_id_tag_update(&ma->id, 0); + ED_area_tag_redraw(CTX_wm_area(C)); + } + + WM_event_add_notifier(C, NC_TEXTURE, CTX_data_scene(C)); + return true; + } + } + } + + return false; +} + +static int texture_paint_add_texture_paint_slot_exec(bContext *C, wmOperator *op) +{ + return proj_paint_add_slot(C, NULL, op); +} + + +static int texture_paint_add_texture_paint_slot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + char imagename[MAX_ID_NAME - 2]; + Object *ob = CTX_data_active_object(C); + Material *ma = give_current_material(ob, ob->actcol); + int type = RNA_enum_get(op->ptr, "type"); + + type = RNA_enum_from_value(layer_type_items, type); + + /* get the name of the texture layer type */ + BLI_assert(type != -1); + + /* take the second letter to avoid the ID identifier */ + BLI_snprintf(imagename, FILE_MAX, "%s %s", &ma->id.name[2], layer_type_items[type].name); + + RNA_string_set(op->ptr, "name", imagename); + return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y); +} + +#define IMA_DEF_NAME N_("Untitled") + + +void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot) +{ + PropertyRNA *prop; + static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + + /* identifiers */ + ot->name = "Add Texture Paint Slot"; + ot->description = "Add a texture paint slot"; + ot->idname = "PAINT_OT_add_texture_paint_slot"; + + /* api callbacks */ + ot->invoke = texture_paint_add_texture_paint_slot_invoke; + ot->exec = texture_paint_add_texture_paint_slot_exec; + ot->poll = ED_operator_region_view3d_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum(ot->srna, "type", layer_type_items, 0, "Type", "Merge method to use"); + RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image datablock name"); + prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384); + RNA_def_property_subtype(prop, PROP_PIXEL); + prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384); + RNA_def_property_subtype(prop, PROP_PIXEL); + prop = RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f); + RNA_def_property_subtype(prop, PROP_COLOR_GAMMA); + RNA_def_property_float_array_default(prop, default_color); + RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel"); + RNA_def_enum(ot->srna, "generated_type", image_generated_type_items, IMA_GENTYPE_BLANK, + "Generated Type", "Fill the image with a grid for UV map testing"); + RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth"); +} + +static int texture_paint_delete_texture_paint_slot_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); + Material *ma; + bool is_bi = BKE_scene_uses_blender_internal(scene); + TexPaintSlot *slot; + + /* not supported for node-based engines */ + if (!ob || !is_bi) + return OPERATOR_CANCELLED; + + ma = give_current_material(ob, ob->actcol); + + if (!ma->texpaintslot || ma->use_nodes) + return OPERATOR_CANCELLED; + + slot = ma->texpaintslot + ma->paint_active_slot; + + if (ma->mtex[slot->index]->tex) + id_us_min(&ma->mtex[slot->index]->tex->id); + MEM_freeN(ma->mtex[slot->index]); + ma->mtex[slot->index] = NULL; + + BKE_texpaint_slot_refresh_cache(scene, ma); + DAG_id_tag_update(&ma->id, 0); + WM_event_add_notifier(C, NC_MATERIAL, CTX_data_scene(C)); + /* we need a notifier for data change since we change the displayed modifier uvs */ + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + return OPERATOR_FINISHED; +} + + +void PAINT_OT_delete_texture_paint_slot(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete Texture Paint Slot"; + ot->description = "Add a texture paint slot"; + ot->idname = "PAINT_OT_delete_texture_paint_slot"; + + /* api callbacks */ + ot->exec = texture_paint_delete_texture_paint_slot_exec; + ot->poll = ED_operator_region_view3d_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index b20c1756d75..5e1ac0cf8a8 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -38,7 +38,9 @@ struct bglMats; struct Brush; struct ImagePool; struct ColorSpace; +struct ColorManagedDisplay; struct ListBase; +struct Material; struct Mesh; struct MTex; struct Object; @@ -65,7 +67,7 @@ typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke, typedef void (*StrokeRedraw)(const struct bContext *C, struct PaintStroke *stroke, bool final); typedef void (*StrokeDone)(const struct bContext *C, struct PaintStroke *stroke); -struct PaintStroke *paint_stroke_new(struct bContext *C, +struct PaintStroke *paint_stroke_new(struct bContext *C, struct wmOperator *op, StrokeGetLocation get_location, StrokeTestStart test_start, StrokeUpdateStep update_step, StrokeRedraw redraw, StrokeDone done, int event_type); @@ -82,8 +84,10 @@ struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf); int paint_stroke_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); int paint_stroke_exec(struct bContext *C, struct wmOperator *op); void paint_stroke_cancel(struct bContext *C, struct wmOperator *op); +bool paint_stroke_flipped(struct PaintStroke *stroke); struct ViewContext *paint_stroke_view_context(struct PaintStroke *stroke); void *paint_stroke_mode_data(struct PaintStroke *stroke); +float paint_stroke_distance_get(struct PaintStroke *stroke); void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data); int paint_poll(struct bContext *C); void paint_cursor_start(struct bContext *C, int (*poll)(struct bContext *C)); @@ -117,7 +121,7 @@ void PAINT_OT_weight_gradient(struct wmOperatorType *ot); void PAINT_OT_vertex_paint_toggle(struct wmOperatorType *ot); void PAINT_OT_vertex_paint(struct wmOperatorType *ot); -unsigned int vpaint_get_current_col(struct VPaint *vp); +unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp); /* paint_vertex_proj.c */ @@ -144,32 +148,43 @@ typedef struct ImagePaintPartialRedraw { #define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS) int image_texture_paint_poll(struct bContext *C); -void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask); -void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile); +void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate); +void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **, bool **valid, bool proj); void image_undo_remove_masks(void); +void image_undo_init_locks(void); +void image_undo_end_locks(void); + void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint); struct ImagePaintPartialRedraw *get_imapaintpartial(void); void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr); void imapaint_region_tiles(struct ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th); int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy); -void *paint_2d_new_stroke(struct bContext *, struct wmOperator *); +void *paint_2d_new_stroke(struct bContext *, struct wmOperator *, int mode); void paint_2d_redraw(const bContext *C, void *ps, bool final); void paint_2d_stroke_done(void *ps); -void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], int eraser); +void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], const bool eraser, float pressure, float distance, float size); +void paint_2d_bucket_fill(const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps); +void paint_2d_gradient_fill (const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps); void *paint_proj_new_stroke(struct bContext *C, struct Object *ob, const float mouse[2], int mode); -void paint_proj_stroke(struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2]); -void paint_proj_redraw(const bContext *C, void *pps, bool final); +void paint_proj_stroke(const struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2], const bool eraser, float pressure, float distance, float size); +void paint_proj_redraw(const struct bContext *C, void *pps, bool final); void paint_proj_stroke_done(void *ps); +void paint_proj_mesh_data_ensure(bContext *C, struct Object *ob, struct wmOperator *op); +bool proj_paint_add_slot(bContext *C, struct Material *ma, struct wmOperator *op); + +void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, float pressure, float color[3], struct ColorManagedDisplay *display); +bool paint_use_opacity_masking(struct Brush *brush); void paint_brush_init_tex(struct Brush *brush); void paint_brush_exit_tex(struct Brush *brush); void PAINT_OT_grab_clone(struct wmOperatorType *ot); void PAINT_OT_sample_color(struct wmOperatorType *ot); +void PAINT_OT_brush_colors_flip(struct wmOperatorType *ot); void PAINT_OT_texture_paint_toggle(struct wmOperatorType *ot); void PAINT_OT_project_image(struct wmOperatorType *ot); void PAINT_OT_image_from_view(struct wmOperatorType *ot); - -/* new texture painting */ +void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot); +void PAINT_OT_delete_texture_paint_slot(struct wmOperatorType *ot); void PAINT_OT_image_paint(struct wmOperatorType *ot); /* uv sculpting */ @@ -202,7 +217,10 @@ float paint_calc_object_space_radius(struct ViewContext *vc, const float center[ float paint_get_tex_pixel(struct MTex *mtex, float u, float v, struct ImagePool *pool, int thread); void paint_get_tex_pixel_col(struct MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool, int thread, bool convert, struct ColorSpace *colorspace); -void paint_sample_color(const struct bContext *C, struct ARegion *ar, int x, int y); +void paint_sample_color(bContext *C, struct ARegion *ar, int x, int y, bool texpaint_proj, bool palette); + +void paint_stroke_operator_properties(struct wmOperatorType *ot); + void BRUSH_OT_curve_preset(struct wmOperatorType *ot); void PAINT_OT_face_select_linked(struct wmOperatorType *ot); @@ -213,8 +231,10 @@ void PAINT_OT_face_select_reveal(struct wmOperatorType *ot); void PAINT_OT_vert_select_all(struct wmOperatorType *ot); void PAINT_OT_vert_select_ungrouped(struct wmOperatorType *ot); + int vert_paint_poll(struct bContext *C); int mask_paint_poll(struct bContext *C); +int paint_curve_poll(struct bContext *C); int facemask_paint_poll(struct bContext *C); void flip_v3_v3(float out[3], const float in[3], const char symm); @@ -229,7 +249,6 @@ typedef enum BrushStrokeMode { /* paint_undo.c */ struct ListBase *undo_paint_push_get_list(int type); void undo_paint_push_count_alloc(int type, int size); -bool sculpt_undo_cleanup(struct bContext *C, struct ListBase *lb); /* paint_hide.c */ @@ -258,4 +277,29 @@ typedef enum { void PAINT_OT_mask_flood_fill(struct wmOperatorType *ot); void PAINT_OT_mask_lasso_gesture(struct wmOperatorType *ot); +/* paint_curve.c */ +void PAINTCURVE_OT_new(struct wmOperatorType *ot); +void PAINTCURVE_OT_add_point(struct wmOperatorType *ot); +void PAINTCURVE_OT_delete_point(struct wmOperatorType *ot); +void PAINTCURVE_OT_select(struct wmOperatorType *ot); +void PAINTCURVE_OT_slide(struct wmOperatorType *ot); +void PAINTCURVE_OT_draw(struct wmOperatorType *ot); +void PAINTCURVE_OT_cursor(struct wmOperatorType *ot); + +/* image painting blur kernel */ +typedef struct { + float *wdata; /* actual kernel */ + int side; /* kernel side */ + int side_squared; /* data side */ + int pixel_len; /* pixels around center that kernel is wide */ +} BlurKernel; + +enum BlurKernelType; +/* can be extended to other blur kernels later */ +BlurKernel *paint_new_blur_kernel(struct Brush *br, bool proj); +void paint_delete_blur_kernel(BlurKernel *); + +/* paint curve defines */ +#define PAINT_CURVE_NUM_SEGMENTS 40 + #endif /* __PAINT_INTERN_H__ */ diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index b3f81f379f3..8faa4cfaf33 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -115,7 +115,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) sculpt_undo_push_begin("Mask flood fill"); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (i = 0; i < totnode; i++) { PBVHVertexIter vi; @@ -236,7 +236,7 @@ int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *r BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (i = 0; i < totnode; i++) { PBVHVertexIter vi; bool any_masked = false; @@ -385,7 +385,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) /* gather nodes inside lasso's enclosing rectangle (should greatly help with bigger meshes) */ BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (i = 0; i < totnode; i++) { PBVHVertexIter vi; bool any_masked = false; diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 9021581d47f..90161fa87dd 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -149,11 +149,112 @@ static void BRUSH_OT_scale_size(wmOperatorType *ot) RNA_def_float(ot->srna, "scalar", 1, 0, 2, "Scalar", "Factor to scale brush size by", 0, 2); } +/* Palette operators */ + +static int palette_new_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + Main *bmain = CTX_data_main(C); + Palette *palette; + + palette = BKE_palette_add(bmain, "Palette"); + + BKE_paint_palette_set(paint, palette); + + return OPERATOR_FINISHED; +} + +static void PALETTE_OT_new(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add New Palette"; + ot->description = "Add new palette"; + ot->idname = "PALETTE_OT_new"; + + /* api callbacks */ + ot->exec = palette_new_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int palette_poll(bContext *C) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + + if (paint && paint->palette != NULL) + return true; + + return false; +} + +static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = paint->brush; + PaintMode mode = BKE_paintmode_get_active_from_context(C); + Palette *palette = paint->palette; + PaletteColor *color = BKE_palette_color_add(palette); + + if (ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX)) { + copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush)); + color->value = 0.0; + } + else if (mode == PAINT_WEIGHT) { + zero_v3(color->rgb); + color->value = brush->weight; + } + + return OPERATOR_FINISHED; +} + +static void PALETTE_OT_color_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "New Palette Color"; + ot->description = "Add new color to active palette"; + ot->idname = "PALETTE_OT_color_add"; + + /* api callbacks */ + ot->exec = palette_color_add_exec; + ot->poll = palette_poll; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + +static int palette_color_delete_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + Palette *palette = paint->palette; + + BKE_palette_color_delete(palette); + + return OPERATOR_FINISHED; +} + +static void PALETTE_OT_color_delete(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete Palette Color"; + ot->description = "Remove active color from palette"; + ot->idname = "PALETTE_OT_color_delete"; + + /* api callbacks */ + ot->exec = palette_color_delete_exec; + ot->poll = palette_poll; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + + static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); Object *obact = CTX_data_active_object(C); - unsigned int paintcol = vpaint_get_current_col(scene->toolsettings->vpaint); + unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint); if (ED_vpaint_fill(obact, paintcol)) { ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views @@ -332,6 +433,7 @@ static int brush_generic_tool_set(Main *bmain, Paint *paint, const int tool, if (brush) { BKE_paint_brush_set(paint, brush); BKE_paint_invalidate_overlay_all(); + WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush); return OPERATOR_FINISHED; } @@ -928,8 +1030,37 @@ static void ed_keymap_stencil(wmKeyMap *keymap) /**************************** registration **********************************/ +void ED_operatormacros_paint(void) +{ + wmOperatorType *ot; + wmOperatorTypeMacro *otmacro; + + ot = WM_operatortype_append_macro("PAINTCURVE_OT_add_point_slide", "Add Curve Point and Slide", + "Add new curve point and slide it", OPTYPE_UNDO); + ot->description = "Add new curve point and slide it"; + WM_operatortype_macro_define(ot, "PAINTCURVE_OT_add_point"); + otmacro = WM_operatortype_macro_define(ot, "PAINTCURVE_OT_slide"); + RNA_boolean_set(otmacro->ptr, "align", true); + RNA_boolean_set(otmacro->ptr, "select", false); +} + + void ED_operatortypes_paint(void) { + /* palette */ + WM_operatortype_append(PALETTE_OT_new); + WM_operatortype_append(PALETTE_OT_color_add); + WM_operatortype_append(PALETTE_OT_color_delete); + + /* paint curve */ + WM_operatortype_append(PAINTCURVE_OT_new); + WM_operatortype_append(PAINTCURVE_OT_add_point); + WM_operatortype_append(PAINTCURVE_OT_delete_point); + WM_operatortype_append(PAINTCURVE_OT_select); + WM_operatortype_append(PAINTCURVE_OT_slide); + WM_operatortype_append(PAINTCURVE_OT_draw); + WM_operatortype_append(PAINTCURVE_OT_cursor); + /* brush */ WM_operatortype_append(BRUSH_OT_add); WM_operatortype_append(BRUSH_OT_scale_size); @@ -950,6 +1081,9 @@ void ED_operatortypes_paint(void) WM_operatortype_append(PAINT_OT_grab_clone); WM_operatortype_append(PAINT_OT_project_image); WM_operatortype_append(PAINT_OT_image_from_view); + WM_operatortype_append(PAINT_OT_brush_colors_flip); + WM_operatortype_append(PAINT_OT_add_texture_paint_slot); + WM_operatortype_append(PAINT_OT_delete_texture_paint_slot); /* weight */ WM_operatortype_append(PAINT_OT_weight_paint_toggle); @@ -1119,12 +1253,44 @@ static void paint_partial_visibility_keys(wmKeyMap *keymap) RNA_enum_set(kmi->ptr, "area", PARTIALVIS_ALL); } + +static void paint_keymap_curve(wmKeyMap *keymap) +{ + wmKeyMapItem *kmi; + + WM_keymap_add_item(keymap, "PAINTCURVE_OT_add_point_slide", ACTIONMOUSE, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "extend", true); + WM_keymap_add_item(keymap, "PAINTCURVE_OT_slide", ACTIONMOUSE, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_slide", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "align", true); + kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", AKEY, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "toggle", true); + + WM_keymap_add_item(keymap, "PAINTCURVE_OT_cursor", ACTIONMOUSE, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "PAINTCURVE_OT_delete_point", XKEY, KM_PRESS, 0, 0); + + WM_keymap_add_item(keymap, "PAINTCURVE_OT_draw", RETKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "PAINTCURVE_OT_draw", PADENTER, KM_PRESS, 0, 0); + + WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", EVT_TWEAK_S, KM_ANY, 0, 0); + WM_keymap_add_item(keymap, "TRANSFORM_OT_rotate", RKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "TRANSFORM_OT_resize", SKEY, KM_PRESS, 0, 0); +} + void ED_keymap_paint(wmKeyConfig *keyconf) { wmKeyMap *keymap; wmKeyMapItem *kmi; int i; + keymap = WM_keymap_find(keyconf, "Paint Curve", 0, 0); + keymap->poll = paint_curve_poll; + + paint_keymap_curve(keymap); + /* Sculpt mode */ keymap = WM_keymap_find(keyconf, "Sculpt", 0, 0); keymap->poll = sculpt_mode_poll; @@ -1191,7 +1357,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) RNA_boolean_set(kmi->ptr, "create_missing", 1); /* */ - kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.brush.stroke_method"); kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0); @@ -1225,7 +1391,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", RKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.texture_angle_source_random"); - kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.stroke_method"); /* Weight Paint mode */ @@ -1250,7 +1416,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) ed_keymap_stencil(keymap); - kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.stroke_method"); kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* face mask toggle */ @@ -1283,6 +1449,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "mode", BRUSH_STROKE_NORMAL); RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "mode", BRUSH_STROKE_INVERT); + WM_keymap_add_item(keymap, "PAINT_OT_brush_colors_flip", XKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "PAINT_OT_grab_clone", RIGHTMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "PAINT_OT_sample_color", SKEY, KM_PRESS, 0, 0); @@ -1301,7 +1468,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", RKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.texture_angle_source_random"); - kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.stroke_method"); /* face-mask mode */ diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index e87f8ca6827..8f189b49aa6 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -36,16 +36,19 @@ #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_rand.h" +#include "BLI_listbase.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_brush_types.h" +#include "DNA_curve_types.h" #include "RNA_access.h" #include "BKE_context.h" #include "BKE_paint.h" #include "BKE_brush.h" +#include "BKE_curve.h" #include "BKE_colortools.h" #include "BKE_image.h" @@ -72,7 +75,7 @@ typedef struct PaintSample { typedef struct PaintStroke { void *mode_data; - void *smooth_stroke_cursor; + void *stroke_cursor; wmTimer *timer; /* Cached values */ @@ -81,6 +84,9 @@ typedef struct PaintStroke { Brush *brush; UnifiedPaintSettings *ups; + /* used for lines and curves */ + ListBase line; + /* Paint stroke can use up to PAINT_MAX_INPUT_SAMPLES prior inputs * to smooth the stroke */ PaintSample samples[PAINT_MAX_INPUT_SAMPLES]; @@ -88,6 +94,8 @@ typedef struct PaintStroke { int cur_sample; float last_mouse_position[2]; + /* space distance covered so far */ + float stroke_distance; /* Set whether any stroke step has yet occurred * e.g. in sculpt mode, stroke doesn't start until cursor @@ -104,7 +112,7 @@ typedef struct PaintStroke { float cached_size_pressure; /* last pressure will store last pressure value for use in interpolation for space strokes */ float last_pressure; - + int stroke_mode; float zoom_2d; int pen_flip; @@ -116,18 +124,17 @@ typedef struct PaintStroke { StrokeDone done; } PaintStroke; -/*** Cursor ***/ -static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata) +/*** Cursors ***/ +static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata) { Paint *paint = BKE_paint_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); PaintStroke *stroke = customdata; - if (stroke && brush && (brush->flag & BRUSH_SMOOTH_STROKE)) { - glColor4ubv(paint->paint_cursor_col); + if (stroke && brush) { glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - + glColor4ubv(paint->paint_cursor_col); sdrawline(x, y, (int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1]); glDisable(GL_BLEND); @@ -135,32 +142,39 @@ static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata } } -/* if this is a tablet event, return tablet pressure and set *pen_flip - * to 1 if the eraser tool is being used, 0 otherwise */ -static float event_tablet_data(const wmEvent *event, int *pen_flip) +static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata) { - int erasor = 0; - float pressure = 1; + Paint *paint = BKE_paint_get_active_from_context(C); + PaintStroke *stroke = customdata; - if (event->tablet_data) { - wmTabletData *wmtab = event->tablet_data; + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); - erasor = (wmtab->Active == EVT_TABLET_ERASER); - pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1; - } + glEnable(GL_LINE_STIPPLE); + glLineStipple(3, 0xAAAA); + + glColor4ub(0, 0, 0, paint->paint_cursor_col[3]); + glLineWidth(3.0); + sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1], + x, y); + + glColor4ub(255, 255, 255, paint->paint_cursor_col[3]); + glLineWidth(1.0); + sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1], + x, y); - if (pen_flip) - (*pen_flip) = erasor; + glDisable(GL_LINE_STIPPLE); - return pressure; + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); } static bool paint_tool_require_location(Brush *brush, PaintMode mode) { switch (mode) { case PAINT_SCULPT: - if (ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, - SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)) + if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, + SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)) { return false; } @@ -175,13 +189,18 @@ static bool paint_tool_require_location(Brush *brush, PaintMode mode) } /* Initialize the stroke cache variants from operator properties */ -static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode, - struct PaintStroke *stroke, - const float mouse[2], float pressure) +static bool paint_brush_update(bContext *C, + Brush *brush, + PaintMode mode, + struct PaintStroke *stroke, + const float mouse_init[2], + float mouse[2], float pressure, + float location[3]) { Scene *scene = CTX_data_scene(C); - UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; - + UnifiedPaintSettings *ups = stroke->ups; + bool location_sampled = false; + bool location_success = false; /* XXX: Use pressure value from first brush step for brushes which don't * support strokes (grab, thumb). They depends on initial state and * brush coord/pressure/etc. @@ -194,6 +213,9 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode, copy_v2_v2(ups->mask_tex_mouse, mouse); stroke->cached_size_pressure = pressure; + ups->do_linear_conversion = false; + ups->colorspace = NULL; + /* check here if color sampling the main brush should do color conversion. This is done here * to avoid locking up to get the image buffer during sampling */ if (brush->mtex.tex && brush->mtex.tex->type == TEX_IMAGE && brush->mtex.tex->ima) { @@ -242,14 +264,14 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode, else { copy_v2_v2(ups->tex_mouse, mouse); } - } - /* take care of mask texture, if any */ - if (brush->mask_mtex.tex) { - if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) - BKE_brush_randomize_texture_coordinates(ups, true); - else { - copy_v2_v2(ups->mask_tex_mouse, mouse); + /* take care of mask texture, if any */ + if (brush->mask_mtex.tex) { + if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) + BKE_brush_randomize_texture_coordinates(ups, true); + else { + copy_v2_v2(ups->mask_tex_mouse, mouse); + } } } @@ -266,14 +288,14 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode, ups->brush_rotation = atan2(dx, dy) + M_PI; if (brush->flag & BRUSH_EDGE_TO_EDGE) { - float out[3]; - halfway[0] = dx * 0.5f + stroke->initial_mouse[0]; halfway[1] = dy * 0.5f + stroke->initial_mouse[1]; if (stroke->get_location) { - if (stroke->get_location(C, out, halfway)) { + if (stroke->get_location(C, location, halfway)) { hit = true; + location_sampled = true; + location_success = true; } else if (!paint_tool_require_location(brush, mode)) { hit = true; @@ -286,30 +308,69 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode, if (hit) { copy_v2_v2(ups->anchored_initial_mouse, halfway); copy_v2_v2(ups->tex_mouse, halfway); + copy_v2_v2(ups->mask_tex_mouse, halfway); + copy_v2_v2(mouse, halfway); ups->anchored_size /= 2.0f; ups->pixel_radius /= 2.0f; + stroke->stroke_distance = ups->pixel_radius; } - else + else { copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse); - + copy_v2_v2(mouse, stroke->initial_mouse); + stroke->stroke_distance = ups->pixel_radius; + } + ups->pixel_radius /= stroke->zoom_2d; ups->draw_anchored = true; } else if (brush->flag & BRUSH_RAKE) { - paint_calculate_rake_rotation(ups, mouse); + /* here we are using the initial mouse coordinate because we do not want the rake + * result to depend on jittering */ + if (!stroke->brush_init) + copy_v2_v2(ups->last_rake, mouse_init); + else + paint_calculate_rake_rotation(ups, mouse_init); + } + + if (!location_sampled) { + if (stroke->get_location) { + if (stroke->get_location(C, location, mouse)) + location_success = true; + else if (!paint_tool_require_location(brush, mode)) + location_success = true; + } + else { + zero_v3(location); + location_success = true; + } } + + return location_success; } +static bool paint_stroke_use_jitter(PaintMode mode, Brush *brush, bool invert) +{ + bool use_jitter = (brush->flag & BRUSH_ABSOLUTE_JITTER) ? + (brush->jitter_absolute != 0) : (brush->jitter != 0); + + /* jitter-ed brush gives weird and unpredictable result for this + * kinds of stroke, so manually disable jitter usage (sergey) */ + use_jitter &= (brush->flag & (BRUSH_DRAG_DOT | BRUSH_ANCHORED)) == 0; + use_jitter &= (!ELEM(mode, PAINT_TEXTURE_2D, PAINT_TEXTURE_PROJECTIVE) || + !(invert && brush->imagepaint_tool == PAINT_TOOL_CLONE)); + + + return use_jitter; +} /* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float mouse_in[2], float pressure) { Scene *scene = CTX_data_scene(C); - wmWindow *window = CTX_wm_window(C); - ARegion *ar = CTX_wm_region(C); Paint *paint = BKE_paint_get_active_from_context(C); PaintMode mode = BKE_paintmode_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); PaintStroke *stroke = op->customdata; + UnifiedPaintSettings *ups = stroke->ups; float mouse_out[2]; PointerRNA itemptr; float location[3]; @@ -335,9 +396,7 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float copy_v2_v2(stroke->last_mouse_position, mouse_in); stroke->last_pressure = pressure; - paint_brush_update(C, brush, mode, stroke, mouse_in, pressure); - - { + if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) { float delta[2]; float factor = stroke->zoom_2d; @@ -355,23 +414,17 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float add_v2_v2v2(mouse_out, mouse_in, delta); } } + else { + copy_v2_v2(mouse_out, mouse_in); + } - /* TODO: can remove the if statement once all modes have this */ - if (stroke->get_location) { - if (!stroke->get_location(C, location, mouse_out)) { - if (paint_tool_require_location(brush, mode)) { - if (ar && (paint->flags & PAINT_SHOW_BRUSH)) - WM_paint_cursor_tag_redraw(window, ar); - return; - } - } + if (!paint_brush_update(C, brush, mode, stroke, mouse_in, mouse_out, pressure, location)) { + return; } - else - zero_v3(location); /* Add to stroke */ RNA_collection_add(op->ptr, "stroke", &itemptr); - + RNA_float_set(&itemptr, "size", ups->pixel_radius); RNA_float_set_array(&itemptr, "location", location); RNA_float_set_array(&itemptr, "mouse", mouse_out); RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip); @@ -382,20 +435,12 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float /* don't record this for now, it takes up a lot of memory when doing long * strokes with small brush size, and operators have register disabled */ RNA_collection_clear(op->ptr, "stroke"); - - /* always redraw region if brush is shown */ - if (ar && (paint->flags & PAINT_SHOW_BRUSH)) - WM_paint_cursor_tag_redraw(window, ar); } /* Returns zero if no sculpt changes should be made, non-zero otherwise */ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], float *outpressure, const PaintSample *sample, PaintMode mode) { - output[0] = sample->mouse[0]; - output[1] = sample->mouse[1]; - *outpressure = sample->pressure; - if (paint_supports_smooth_stroke(stroke->brush, mode)) { float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d; float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u; @@ -411,6 +456,11 @@ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], float *outp output[1] = sample->mouse[1] * v + stroke->last_mouse_position[1] * u; *outpressure = sample->pressure * v + stroke->last_pressure * u; } + else { + output[0] = sample->mouse[0]; + output[1] = sample->mouse[1]; + *outpressure = sample->pressure; + } return 1; } @@ -433,6 +483,55 @@ static float paint_space_stroke_spacing(const Scene *scene, PaintStroke *stroke, return max_ff(1.0, size_clamp * spacing / 50.0f); } + + +static float paint_stroke_overlapped_curve(Brush *br, float x, float spacing) +{ + int i; + const int n = 100 / spacing; + const float h = spacing / 50.0f; + const float x0 = x - 1; + + float sum; + + sum = 0; + for (i = 0; i < n; i++) { + float xx; + + xx = fabs(x0 + i * h); + + if (xx < 1.0f) + sum += BKE_brush_curve_strength(br, xx, 1); + } + + return sum; +} + +static float paint_stroke_integrate_overlap(Brush *br, float factor) +{ + int i; + int m; + float g; + float max; + + float spacing = br->spacing * factor; + + if (!(br->flag & BRUSH_SPACE_ATTEN && (br->spacing < 100))) + return 1.0; + + m = 10; + g = 1.0f / m; + max = 0; + for (i = 0; i < m; i++) { + float overlap = paint_stroke_overlapped_curve(br, i * g, spacing); + + if (overlap > max) + max = overlap; + } + + return 1.0f / max; +} + static float paint_space_stroke_spacing_variable(const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length) { if (BKE_brush_use_size_pressure(scene, stroke->brush)) { @@ -464,40 +563,42 @@ static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mou { const Scene *scene = CTX_data_scene(C); PaintStroke *stroke = op->customdata; - PaintMode mode = BKE_paintmode_get_active_from_context(C); + UnifiedPaintSettings *ups = stroke->ups; int cnt = 0; - if (paint_space_stroke_enabled(stroke->brush, mode)) { - float pressure, dpressure; - float mouse[2], dmouse[2]; - float length; + float pressure, dpressure; + float mouse[2], dmouse[2]; + float length; + float no_pressure_spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f); - sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position); + sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position); - pressure = stroke->last_pressure; - dpressure = final_pressure - stroke->last_pressure; + pressure = stroke->last_pressure; + dpressure = final_pressure - stroke->last_pressure; - length = normalize_v2(dmouse); + length = normalize_v2(dmouse); - while (length > 0.0f) { - float spacing = paint_space_stroke_spacing_variable(scene, stroke, pressure, dpressure, length); - - if (length >= spacing) { - mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing; - mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing; - pressure = stroke->last_pressure + (spacing / length) * dpressure; + while (length > 0.0f) { + float spacing = paint_space_stroke_spacing_variable(scene, stroke, pressure, dpressure, length); - paint_brush_stroke_add_step(C, op, mouse, pressure); + if (length >= spacing) { + mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing; + mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing; + pressure = stroke->last_pressure + (spacing / length) * dpressure; - length -= spacing; - pressure = stroke->last_pressure; - dpressure = final_pressure - stroke->last_pressure; + ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, spacing / no_pressure_spacing); - cnt++; - } - else { - break; - } + stroke->stroke_distance += spacing / stroke->zoom_2d; + paint_brush_stroke_add_step(C, op, mouse, pressure); + + length -= spacing; + pressure = stroke->last_pressure; + dpressure = final_pressure - stroke->last_pressure; + + cnt++; + } + else { + break; } } @@ -507,6 +608,7 @@ static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mou /**** Public API ****/ PaintStroke *paint_stroke_new(bContext *C, + wmOperator *op, StrokeGetLocation get_location, StrokeTestStart test_start, StrokeUpdateStep update_step, @@ -517,6 +619,7 @@ PaintStroke *paint_stroke_new(bContext *C, ToolSettings *toolsettings = CTX_data_tool_settings(C); UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings; Brush *br = stroke->brush = BKE_paint_brush(BKE_paint_get_active_from_context(C)); + float zoomx, zoomy; view3d_set_viewcontext(C, &stroke->vc); if (stroke->vc.v3d) @@ -529,6 +632,19 @@ PaintStroke *paint_stroke_new(bContext *C, stroke->done = done; stroke->event_type = event_type; /* for modal, return event */ stroke->ups = ups; + stroke->stroke_mode = RNA_enum_get(op->ptr, "mode"); + + get_imapaint_zoom(C, &zoomx, &zoomy); + stroke->zoom_2d = max_ff(zoomx, zoomy); + + if ((br->flag & BRUSH_CURVE) && + RNA_struct_property_is_set(op->ptr, "mode")) + { + RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL); + } + /* initialize here */ + ups->overlap_factor = 1.0; + ups->stroke_active = true; /* initialize here to avoid initialization conflict with threaded strokes */ curvemapping_initialize(br->curve); @@ -541,8 +657,7 @@ PaintStroke *paint_stroke_new(bContext *C, void paint_stroke_data_free(struct wmOperator *op) { BKE_paint_set_overlay_override(0); - MEM_freeN(op->customdata); - op->customdata = NULL; + MEM_SAFE_FREE(op->customdata); } static void stroke_done(struct bContext *C, struct wmOperator *op) @@ -572,8 +687,10 @@ static void stroke_done(struct bContext *C, struct wmOperator *op) stroke->timer); } - if (stroke->smooth_stroke_cursor) - WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor); + if (stroke->stroke_cursor) + WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor); + + BLI_freelistN(&stroke->line); paint_stroke_data_free(op); } @@ -586,7 +703,7 @@ bool paint_space_stroke_enabled(Brush *br, PaintMode mode) static bool sculpt_is_grab_tool(Brush *br) { - return ELEM4(br->sculpt_tool, + return ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, @@ -604,6 +721,16 @@ bool paint_supports_dynamic_size(Brush *br, PaintMode mode) if (sculpt_is_grab_tool(br)) return false; break; + + case PAINT_TEXTURE_2D: /* fall through */ + case PAINT_TEXTURE_PROJECTIVE: + if ((br->imagepaint_tool == PAINT_TOOL_FILL) && + (br->flag & BRUSH_USE_GRADIENT)) + { + return false; + } + break; + default: break; } @@ -613,8 +740,7 @@ bool paint_supports_dynamic_size(Brush *br, PaintMode mode) bool paint_supports_smooth_stroke(Brush *br, PaintMode mode) { if (!(br->flag & BRUSH_SMOOTH_STROKE) || - (br->flag & BRUSH_ANCHORED) || - (br->flag & BRUSH_DRAG_DOT)) + (br->flag & (BRUSH_ANCHORED | BRUSH_DRAG_DOT | BRUSH_LINE))) { return false; } @@ -633,7 +759,7 @@ bool paint_supports_smooth_stroke(Brush *br, PaintMode mode) bool paint_supports_texture(PaintMode mode) { /* ommit: PAINT_WEIGHT, PAINT_SCULPT_UV, PAINT_INVALID */ - return ELEM4(mode, PAINT_SCULPT, PAINT_VERTEX, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D); + return ELEM(mode, PAINT_SCULPT, PAINT_VERTEX, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D); } /* return true if the brush size can change during paint (normally used for pressure) */ @@ -721,28 +847,141 @@ static void paint_stroke_sample_average(const PaintStroke *stroke, /*printf("avg=(%f, %f), num=%d\n", average->mouse[0], average->mouse[1], stroke->num_samples);*/ } +/** + * Slightly different version of spacing for line/curve strokes, + * makes sure the dabs stay on the line path. + */ +static void paint_line_strokes_spacing( + bContext *C, wmOperator *op, PaintStroke *stroke, float spacing, float *length_residue, + const float old_pos[2], const float new_pos[2]) +{ + UnifiedPaintSettings *ups = stroke->ups; + + float mouse[2], dmouse[2]; + float length; + + sub_v2_v2v2(dmouse, new_pos, old_pos); + copy_v2_v2(stroke->last_mouse_position, old_pos); + + length = normalize_v2(dmouse); + + BLI_assert(length >= 0.0f); + + if (length == 0.0f) + return; + + while (length > 0.0f) { + float spacing_final = spacing - *length_residue; + length += *length_residue; + *length_residue = 0.0; + + if (length >= spacing) { + mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing_final; + mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing_final; + + ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, 1.0); + + stroke->stroke_distance += spacing / stroke->zoom_2d; + paint_brush_stroke_add_step(C, op, mouse, 1.0); + + length -= spacing; + spacing_final = spacing; + } + else { + break; + } + } + + *length_residue = length; +} + + +static void paint_stroke_line_end(bContext *C, wmOperator *op, PaintStroke *stroke, float mouse[2]) +{ + Brush *br = stroke->brush; + if (stroke->stroke_started && (br->flag & BRUSH_LINE)) { + stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0); + + paint_brush_stroke_add_step(C, op, stroke->last_mouse_position, 1.0); + paint_space_stroke(C, op, mouse, 1.0); + } +} + +static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *stroke) +{ + Brush *br = stroke->brush; + if (br->flag & BRUSH_CURVE) { + const Scene *scene = CTX_data_scene(C); + const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f); + PaintCurve *pc = br->paint_curve; + PaintCurvePoint *pcp; + float length_residue = 0.0f; + int i; + + if (!pc) + return true; + + pcp = pc->points; + stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0); + + for (i = 0; i < pc->tot_points - 1; i++, pcp++) { + int j; + float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2]; + PaintCurvePoint *pcp_next = pcp + 1; + + for (j = 0; j < 2; j++) + BKE_curve_forward_diff_bezier( + pcp->bez.vec[1][j], + pcp->bez.vec[2][j], + pcp_next->bez.vec[0][j], + pcp_next->bez.vec[1][j], + data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2])); + + + for (j = 0; j < PAINT_CURVE_NUM_SEGMENTS; j++) { + if (!stroke->stroke_started) { + stroke->last_pressure = 1.0; + copy_v2_v2(stroke->last_mouse_position, data + 2 * j); + stroke->stroke_started = stroke->test_start(C, op, stroke->last_mouse_position); + + if (stroke->stroke_started) { + paint_brush_stroke_add_step(C, op, data + 2 * j, 1.0); + paint_line_strokes_spacing(C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1)); + } + } + else { + paint_line_strokes_spacing(C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1)); + } + } + } + + stroke_done(C, op); + return true; + } + + return false; +} + + int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) { Paint *p = BKE_paint_get_active_from_context(C); PaintMode mode = BKE_paintmode_get_active_from_context(C); PaintStroke *stroke = op->customdata; + Brush *br = stroke->brush; PaintSample sample_average; float mouse[2]; bool first_dab = false; bool first_modal = false; - float zoomx, zoomy; bool redraw = false; float pressure; - /* see if tablet affects event */ - pressure = event_tablet_data(event, &stroke->pen_flip); + /* see if tablet affects event. Line, anchored and drag dot strokes do not support pressure */ + pressure = (br->flag & (BRUSH_LINE | BRUSH_ANCHORED | BRUSH_DRAG_DOT)) ? 1.0f : WM_event_tablet_data(event, &stroke->pen_flip, NULL); paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure); paint_stroke_sample_average(stroke, &sample_average); - get_imapaint_zoom(C, &zoomx, &zoomy); - stroke->zoom_2d = max_ff(zoomx, zoomy); - /* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously! * this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it * since the 2D deltas are zero -- code in this file needs to be updated to use the @@ -752,8 +991,12 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) /* one time initialization */ if (!stroke->stroke_init) { - stroke->smooth_stroke_cursor = - WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_stroke, stroke); + if (paint_stroke_curve_end(C, op, stroke)) + return OPERATOR_FINISHED; + + if (paint_supports_smooth_stroke(br, mode)) + stroke->stroke_cursor = + WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_cursor, stroke); stroke->stroke_init = true; first_modal = true; @@ -767,9 +1010,14 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */ if (stroke->stroke_started) { - if (stroke->brush->flag & BRUSH_AIRBRUSH) + if (br->flag & BRUSH_AIRBRUSH) stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate); + if (br->flag & BRUSH_LINE) { + stroke->stroke_cursor = + WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_line_cursor, stroke); + } + first_dab = true; } } @@ -785,20 +1033,42 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } - if (event->type == stroke->event_type && event->val == KM_RELEASE && !first_modal) { + if (event->type == stroke->event_type && !first_modal) { + if (event->val == KM_RELEASE) { + paint_stroke_line_end (C, op, stroke, sample_average.mouse); + stroke_done(C, op); + return OPERATOR_FINISHED; + } + } + else if (ELEM(event->type, RETKEY, SPACEKEY)) { + paint_stroke_line_end(C, op, stroke, sample_average.mouse); stroke_done(C, op); return OPERATOR_FINISHED; } - else if (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) || - (event->type == TIMER && (event->customdata == stroke->timer)) ) + else if ((br->flag & BRUSH_LINE) && stroke->stroke_started && + (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) + { + if (br->flag & BRUSH_RAKE) { + copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position); + paint_calculate_rake_rotation(stroke->ups, sample_average.mouse); + } + } + else if (first_modal || + /* regular dabs */ + (!(br->flag & (BRUSH_AIRBRUSH)) && (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))) || + /* airbrush */ + ((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER && event->customdata == stroke->timer)) { if (paint_smooth_stroke(stroke, mouse, &pressure, &sample_average, mode)) { if (stroke->stroke_started) { - if (paint_space_stroke_enabled(stroke->brush, mode)) { + if (paint_space_stroke_enabled(br, mode)) { if (paint_space_stroke(C, op, mouse, pressure)) redraw = true; } else { + float dmouse[2]; + sub_v2_v2v2(dmouse, mouse, stroke->last_mouse_position); + stroke->stroke_distance += len_v2(dmouse); paint_brush_stroke_add_step(C, op, mouse, pressure); redraw = true; } @@ -809,19 +1079,27 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) /* we want the stroke to have the first daub at the start location * instead of waiting till we have moved the space distance */ if (first_dab && - paint_space_stroke_enabled(stroke->brush, mode) && - !(stroke->brush->flag & BRUSH_ANCHORED) && - !(stroke->brush->flag & BRUSH_SMOOTH_STROKE)) + paint_space_stroke_enabled(br, mode) && + !(br->flag & BRUSH_SMOOTH_STROKE)) { - paint_brush_stroke_add_step(C, op, mouse, pressure); + stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0); + paint_brush_stroke_add_step(C, op, sample_average.mouse, sample_average.pressure); redraw = true; } /* do updates for redraw. if event is inbetween mousemove there are more * coming, so postpone potentially slow redraw updates until all are done */ - if (event->type != INBETWEEN_MOUSEMOVE) + if (event->type != INBETWEEN_MOUSEMOVE) { + wmWindow *window = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + + /* At the very least, invalidate the cursor */ + if (ar && (p->flags & PAINT_SHOW_BRUSH)) + WM_paint_cursor_tag_redraw(window, ar); + if (redraw && stroke->redraw) stroke->redraw(C, stroke, false); + } return OPERATOR_RUNNING_MODAL; } @@ -863,6 +1141,16 @@ void *paint_stroke_mode_data(struct PaintStroke *stroke) return stroke->mode_data; } +bool paint_stroke_flipped(struct PaintStroke *stroke) +{ + return stroke->pen_flip; +} + +float paint_stroke_distance_get(struct PaintStroke *stroke) +{ + return stroke->stroke_distance; +} + void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data) { stroke->mode_data = mode_data; @@ -876,6 +1164,6 @@ int paint_poll(bContext *C) ARegion *ar = CTX_wm_region(C); return p && ob && BKE_paint_brush(p) && - (sa && sa->spacetype == SPACE_VIEW3D) && + (sa && ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) && (ar && ar->regiontype == RGN_TYPE_WINDOW); } diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c index c5c747dbab4..20e3155c01d 100644 --- a/source/blender/editors/sculpt_paint/paint_undo.c +++ b/source/blender/editors/sculpt_paint/paint_undo.c @@ -51,19 +51,17 @@ typedef struct UndoElem { UndoRestoreCb restore; UndoFreeCb free; + UndoCleanupCb cleanup; } UndoElem; -typedef bool (*UndoCleanupCb)(struct bContext *C, ListBase *lb); - typedef struct UndoStack { int type; ListBase elems; UndoElem *current; - UndoCleanupCb cleanup; } UndoStack; -static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL, NULL}; -static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL, sculpt_undo_cleanup}; +static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL}; +static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL}; /* Generic */ @@ -81,7 +79,7 @@ static void undo_elem_free(UndoStack *UNUSED(stack), UndoElem *uel) } } -static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free) +static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup) { UndoElem *uel; int nr; @@ -101,6 +99,7 @@ static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestor stack->current = uel = MEM_callocN(sizeof(UndoElem), "undo file"); uel->restore = restore; uel->free = free; + uel->cleanup = cleanup; BLI_addtail(&stack->elems, uel); /* name can be a dynamic string */ @@ -179,25 +178,24 @@ static void undo_stack_cleanup(UndoStack *stack, bContext *C) UndoElem *uel = stack->elems.first; bool stack_reset = false; - if (stack->cleanup) { - while (uel) { - if (stack->cleanup(C, &uel->elems)) { - UndoElem *uel_tmp = uel->next; - if (stack->current == uel) { - stack->current = NULL; - stack_reset = true; - } - undo_elem_free(stack, uel); - BLI_freelinkN(&stack->elems, uel); - uel = uel_tmp; + while (uel) { + if (uel->cleanup && uel->cleanup(C, &uel->elems)) { + UndoElem *uel_tmp = uel->next; + if (stack->current == uel) { + stack->current = NULL; + stack_reset = true; } - else - uel = uel->next; - } - if (stack_reset) { - stack->current = stack->elems.last; + undo_elem_free(stack, uel); + BLI_freelinkN(&stack->elems, uel); + uel = uel_tmp; } + else + uel = uel->next; + } + if (stack_reset) { + stack->current = stack->elems.last; } + } static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *name) @@ -255,23 +253,25 @@ static void undo_stack_free(UndoStack *stack) /* Exported Functions */ -void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free) +void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup) { if (type == UNDO_PAINT_IMAGE) - undo_stack_push_begin(&ImageUndoStack, name, restore, free); + undo_stack_push_begin(&ImageUndoStack, name, restore, free, cleanup); else if (type == UNDO_PAINT_MESH) - undo_stack_push_begin(&MeshUndoStack, name, restore, free); + undo_stack_push_begin(&MeshUndoStack, name, restore, free, cleanup); } ListBase *undo_paint_push_get_list(int type) { if (type == UNDO_PAINT_IMAGE) { - if (ImageUndoStack.current) + if (ImageUndoStack.current) { return &ImageUndoStack.current->elems; + } } else if (type == UNDO_PAINT_MESH) { - if (MeshUndoStack.current) + if (MeshUndoStack.current) { return &MeshUndoStack.current->elems; + } } return NULL; diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 25308f6595e..f34d0ff3f7b 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -35,23 +35,28 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "DNA_material_types.h" #include "DNA_scene_types.h" #include "DNA_brush_types.h" #include "BLI_math.h" +#include "BLI_math_color.h" #include "BLI_utildefines.h" #include "BLI_listbase.h" #include "BLI_rect.h" #include "BLF_translation.h" +#include "BKE_scene.h" #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_DerivedMesh.h" +#include "BKE_material.h" #include "BKE_image.h" #include "BKE_paint.h" #include "BKE_report.h" +#include "BKE_image.h" #include "RNA_access.h" #include "RNA_define.h" @@ -67,6 +72,10 @@ #include "ED_view3d.h" #include "ED_screen.h" +#include "ED_uvedit.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" #include "BLI_sys_types.h" #include "ED_mesh.h" /* for face mask functions */ @@ -205,6 +214,192 @@ void paint_get_tex_pixel_col(MTex *mtex, float u, float v, float rgba[4], struct CLAMP(rgba[3], 0.0f, 1.0f); } +void paint_stroke_operator_properties(wmOperatorType *ot) +{ + static EnumPropertyItem stroke_mode_items[] = { + {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally"}, + {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"}, + {BRUSH_STROKE_SMOOTH, "SMOOTH", 0, "Smooth", "Switch brush to smooth mode for duration of stroke"}, + {0} + }; + + RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); + + RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, + "Stroke Mode", + "Action taken when a paint stroke is made"); + +} + +/* 3D Paint */ + +static void imapaint_project(float matrix[4][4], const float co[3], float pco[4]) +{ + copy_v3_v3(pco, co); + pco[3] = 1.0f; + + mul_m4_v4(matrix, pco); +} + +static void imapaint_tri_weights(float matrix[4][4], GLint view[4], + const float v1[3], const float v2[3], const float v3[3], + const float co[2], float w[3]) +{ + float pv1[4], pv2[4], pv3[4], h[3], divw; + float wmat[3][3], invwmat[3][3]; + + /* compute barycentric coordinates */ + + /* project the verts */ + imapaint_project(matrix, v1, pv1); + imapaint_project(matrix, v2, pv2); + imapaint_project(matrix, v3, pv3); + + /* do inverse view mapping, see gluProject man page */ + h[0] = (co[0] - view[0]) * 2.0f / view[2] - 1.0f; + h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1.0f; + h[2] = 1.0f; + + /* solve for (w1,w2,w3)/perspdiv in: + * h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3) */ + + wmat[0][0] = pv1[0]; wmat[1][0] = pv2[0]; wmat[2][0] = pv3[0]; + wmat[0][1] = pv1[1]; wmat[1][1] = pv2[1]; wmat[2][1] = pv3[1]; + wmat[0][2] = pv1[3]; wmat[1][2] = pv2[3]; wmat[2][2] = pv3[3]; + + invert_m3_m3(invwmat, wmat); + mul_m3_v3(invwmat, h); + + copy_v3_v3(w, h); + + /* w is still divided by perspdiv, make it sum to one */ + divw = w[0] + w[1] + w[2]; + if (divw != 0.0f) { + mul_v3_fl(w, 1.0f / divw); + } +} + +/* compute uv coordinates of mouse in face */ +static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2]) +{ + DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); + MTFace *tf_base, *tf; + Material *ma; + TexPaintSlot *slot; + int numfaces = dm->getNumTessFaces(dm), a, findex; + float p[2], w[3], absw, minabsw; + MFace mf; + MVert mv[4]; + float matrix[4][4], proj[4][4]; + GLint view[4]; + + /* compute barycentric coordinates */ + + /* double lookup */ + const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); + if (index_mf_to_mpoly == NULL) { + index_mp_to_orig = NULL; + } + + /* get the needed opengl matrices */ + glGetIntegerv(GL_VIEWPORT, view); + glGetFloatv(GL_MODELVIEW_MATRIX, (float *)matrix); + glGetFloatv(GL_PROJECTION_MATRIX, (float *)proj); + view[0] = view[1] = 0; + mul_m4_m4m4(matrix, matrix, ob->obmat); + mul_m4_m4m4(matrix, proj, matrix); + + minabsw = 1e10; + uv[0] = uv[1] = 0.0; + + /* test all faces in the derivedmesh with the original index of the picked face */ + for (a = 0; a < numfaces; a++) { + findex = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a; + + if (findex == faceindex) { + dm->getTessFace(dm, a, &mf); + + ma = dm->mat[mf.mat_nr]; + slot = &ma->texpaintslot[ma->paint_active_slot]; + + dm->getVert(dm, mf.v1, &mv[0]); + dm->getVert(dm, mf.v2, &mv[1]); + dm->getVert(dm, mf.v3, &mv[2]); + if (mf.v4) + dm->getVert(dm, mf.v4, &mv[3]); + + if (!(slot && slot->uvname && (tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, slot->uvname)))) + tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE); + + tf = &tf_base[a]; + + p[0] = xy[0]; + p[1] = xy[1]; + + if (mf.v4) { + /* the triangle with the largest absolute values is the one + * with the most negative weights */ + imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[3].co, p, w); + absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]); + if (absw < minabsw) { + uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[3][0] * w[2]; + uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[3][1] * w[2]; + minabsw = absw; + } + + imapaint_tri_weights(matrix, view, mv[1].co, mv[2].co, mv[3].co, p, w); + absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]); + if (absw < minabsw) { + uv[0] = tf->uv[1][0] * w[0] + tf->uv[2][0] * w[1] + tf->uv[3][0] * w[2]; + uv[1] = tf->uv[1][1] * w[0] + tf->uv[2][1] * w[1] + tf->uv[3][1] * w[2]; + minabsw = absw; + } + } + else { + imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[2].co, p, w); + absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]); + if (absw < minabsw) { + uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[2][0] * w[2]; + uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[2][1] * w[2]; + minabsw = absw; + } + } + } + } + + dm->release(dm); +} + +/* returns 0 if not found, otherwise 1 */ +static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *r_index, unsigned int totface) +{ + if (totface == 0) + return 0; + + /* sample only on the exact position */ + *r_index = view3d_sample_backbuf(vc, mval[0], mval[1]); + + if ((*r_index) == 0 || (*r_index) > (unsigned int)totface) { + return 0; + } + + (*r_index)--; + + return 1; +} + + +static Image *imapaint_face_image(DerivedMesh *dm, int face_index) +{ + Image *ima; + MFace *mf = dm->getTessFaceArray(dm) + face_index; + Material *ma = dm->mat[mf->mat_nr]; + ima = ma->texpaintslot[ma->paint_active_slot].ima; + + return ima; +} + /* Uses symm to selectively flip any axis of a coordinate. */ void flip_v3_v3(float out[3], const float in[3], const char symm) { @@ -223,25 +418,132 @@ void flip_v3_v3(float out[3], const float in[3], const char symm) } /* used for both 3d view and image window */ -void paint_sample_color(const bContext *C, ARegion *ar, int x, int y) /* frontbuf */ +void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_proj, bool use_palette) { + Scene *scene = CTX_data_scene(C); + Paint *paint = BKE_paint_get_active_from_context(C); + Palette *palette = BKE_paint_palette(paint); + PaletteColor *color; Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C)); unsigned int col; - const char *cp; + const unsigned char *cp; CLAMP(x, 0, ar->winx); CLAMP(y, 0, ar->winy); - glReadBuffer(GL_FRONT); - glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); - glReadBuffer(GL_BACK); + if (use_palette) { + if (!palette) { + palette = BKE_palette_add(CTX_data_main(C), "Palette"); + BKE_paint_palette_set(paint, palette); + } - cp = (char *)&col; + color = BKE_palette_color_add(palette); + } + + + if (CTX_wm_view3d(C) && texpaint_proj) { + /* first try getting a colour directly from the mesh faces if possible */ + Object *ob = OBACT; + bool sample_success = false; + ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; + bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL); + + if (ob) { + DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); + + ViewContext vc; + const int mval[2] = {x, y}; + unsigned int faceindex; + unsigned int totface = dm->getNumTessFaces(dm); + MTFace *dm_mtface = dm->getTessFaceDataArray(dm, CD_MTFACE); + + DM_update_materials(dm, ob); + + if (dm_mtface) { + view3d_set_viewcontext(C, &vc); + + view3d_operator_needs_opengl(C); + + if (imapaint_pick_face(&vc, mval, &faceindex, totface)) { + Image *image; + + if (use_material) + image = imapaint_face_image(dm, faceindex); + else + image = imapaint->canvas; + + if (image) { + ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); + if (ibuf && ibuf->rect) { + float uv[2]; + float u, v; + imapaint_pick_uv(scene, ob, faceindex, mval, uv); + sample_success = true; + + u = fmodf(uv[0], 1.0f); + v = fmodf(uv[1], 1.0f); + + if (u < 0.0f) u += 1.0f; + if (v < 0.0f) v += 1.0f; + + u = u * ibuf->x - 0.5f; + v = v * ibuf->y - 0.5f; + + if (ibuf->rect_float) { + float rgba_f[4]; + bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v); + straight_to_premul_v4(rgba_f); + if (use_palette) { + linearrgb_to_srgb_v3_v3(color->rgb, rgba_f); + } + else { + linearrgb_to_srgb_v3_v3(rgba_f, rgba_f); + BKE_brush_color_set(scene, br, rgba_f); + } + } + else { + unsigned char rgba[4]; + bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v); + if (use_palette) { + rgb_uchar_to_float(color->rgb, rgba); + } + else { + float rgba_f[3]; + rgb_uchar_to_float(rgba_f, rgba); + BKE_brush_color_set(scene, br, rgba_f); + } + } + } + + BKE_image_release_ibuf(image, ibuf, NULL); + } + } + } + dm->release(dm); + } + + if (!sample_success) { + glReadBuffer(GL_FRONT); + glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); + glReadBuffer(GL_BACK); + } + else + return; + } + else { + glReadBuffer(GL_FRONT); + glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); + glReadBuffer(GL_BACK); + } + cp = (unsigned char *)&col; - if (br) { - br->rgb[0] = cp[0] / 255.0f; - br->rgb[1] = cp[1] / 255.0f; - br->rgb[2] = cp[2] / 255.0f; + if (use_palette) { + rgb_uchar_to_float(color->rgb, cp); + } + else { + float rgba_f[3]; + rgb_uchar_to_float(rgba_f, cp); + BKE_brush_color_set(scene, br, rgba_f); } } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 969c5a09a82..509a7f31f5b 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -33,6 +33,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_bitmap.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -75,7 +76,6 @@ #include "paint_intern.h" /* own include */ - /* check if we can do partial updates and have them draw realtime * (without rebuilding the 'derivedFinal') */ static bool vertex_paint_use_fast_update_check(Object *ob) @@ -197,11 +197,11 @@ static int *get_indexarray(Mesh *me) return MEM_mallocN(sizeof(int) * (me->totpoly + 1), "vertexpaint"); } -unsigned int vpaint_get_current_col(VPaint *vp) +unsigned int vpaint_get_current_col(Scene *scene, VPaint *vp) { Brush *brush = BKE_paint_brush(&vp->paint); unsigned char col[4]; - rgb_float_to_uchar(col, brush->rgb); + rgb_float_to_uchar(col, BKE_brush_color_get(scene, brush)); col[3] = 255; /* alpha isn't used, could even be removed to speedup paint a little */ return *(unsigned int *)col; } @@ -2547,14 +2547,17 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; - op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start, wpaint_stroke_update_step, NULL, wpaint_stroke_done, event->type); + if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { + paint_stroke_data_free(op); + return OPERATOR_FINISHED; + } /* add modal handler */ WM_event_add_modal_handler(C, op); - retval = op->type->modal(C, op, event); OPERATOR_RETVAL_CHECK(retval); BLI_assert(retval == OPERATOR_RUNNING_MODAL); @@ -2563,7 +2566,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int wpaint_exec(bContext *C, wmOperator *op) { - op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start, wpaint_stroke_update_step, NULL, wpaint_stroke_done, 0); @@ -2595,8 +2598,8 @@ void PAINT_OT_weight_paint(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; - - RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); + + paint_stroke_operator_properties(ot); } static int weight_paint_set_exec(bContext *C, wmOperator *op) @@ -2778,7 +2781,8 @@ static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me) static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float UNUSED(mouse[2])) { - ToolSettings *ts = CTX_data_tool_settings(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; struct PaintStroke *stroke = op->customdata; VPaint *vp = ts->vpaint; Brush *brush = BKE_paint_brush(&vp->paint); @@ -2810,7 +2814,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f vpd->vp_handle = ED_vpaint_proj_handle_create(vpd->vc.scene, ob, &vpd->vertexcosnos); vpd->indexar = get_indexarray(me); - vpd->paintcol = vpaint_get_current_col(vp); + vpd->paintcol = vpaint_get_current_col(scene, vp); vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) && brush->mtex.tex; @@ -3062,14 +3066,18 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; - op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start, vpaint_stroke_update_step, NULL, vpaint_stroke_done, event->type); + if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { + paint_stroke_data_free(op); + return OPERATOR_FINISHED; + } + /* add modal handler */ WM_event_add_modal_handler(C, op); - retval = op->type->modal(C, op, event); OPERATOR_RETVAL_CHECK(retval); BLI_assert(retval == OPERATOR_RUNNING_MODAL); @@ -3078,7 +3086,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int vpaint_exec(bContext *C, wmOperator *op) { - op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start, vpaint_stroke_update_step, NULL, vpaint_stroke_done, 0); @@ -3110,7 +3118,7 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; - RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); + paint_stroke_operator_properties(ot); } /* ********************** weight from bones operator ******************* */ @@ -3184,6 +3192,8 @@ typedef struct DMGradient_userData { int def_nr; short is_init; DMGradient_vertStore *vert_cache; + /* only for init */ + BLI_bitmap *vert_visit; /* options */ short use_select; @@ -3191,19 +3201,81 @@ typedef struct DMGradient_userData { float weightpaint; } DMGradient_userData; -static void gradientVert__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +static void gradientVert_update(DMGradient_userData *grad_data, int index) { - DMGradient_userData *grad_data = userData; Mesh *me = grad_data->me; + DMGradient_vertStore *vs = &grad_data->vert_cache[index]; + float alpha; + + if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) { + alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end); + } + else { + BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL); + alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div; + } + /* no need to clamp 'alpha' yet */ - if (grad_data->use_select == false || (me->mvert[index].flag & SELECT)) { + /* adjust weight */ + alpha = BKE_brush_curve_strength_clamp(grad_data->brush, alpha, 1.0f); + + if (alpha != 0.0f) { + MDeformVert *dv = &me->dvert[index]; + MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr); + // dw->weight = alpha; // testing + int tool = grad_data->brush->vertexpaint_tool; + float testw; + + /* init if we just added */ + testw = wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha); + CLAMP(testw, 0.0f, 1.0f); + dw->weight = testw; + } + else { + MDeformVert *dv = &me->dvert[index]; + if (vs->flag & VGRAD_STORE_DW_EXIST) { + /* normally we NULL check, but in this case we know it exists */ + MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); + dw->weight = vs->weight_orig; + } + else { + /* wasn't originally existing, remove */ + MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); + if (dw) { + defvert_remove_group(dv, dw); + } + } + } +} + +static void gradientVertUpdate__mapFunc( + void *userData, int index, const float UNUSED(co[3]), + const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +{ + DMGradient_userData *grad_data = userData; + Mesh *me = grad_data->me; + if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) { DMGradient_vertStore *vs = &grad_data->vert_cache[index]; + if (vs->sco[0] != FLT_MAX) { + gradientVert_update(grad_data, index); + } + } +} - /* run first pass only, could be split into its own mapFunc +static void gradientVertInit__mapFunc( + void *userData, int index, const float co[3], + const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +{ + DMGradient_userData *grad_data = userData; + Mesh *me = grad_data->me; + + if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) { + /* run first pass only, * the screen coords of the verts need to be cached because * updating the mesh may move them about (entering feedback loop) */ - if (grad_data->is_init) { + + if (BLI_BITMAP_TEST(grad_data->vert_visit, index) == 0) { + DMGradient_vertStore *vs = &grad_data->vert_cache[index]; if (ED_view3d_project_float_object(grad_data->ar, co, vs->sco, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) @@ -3220,55 +3292,14 @@ static void gradientVert__mapFunc(void *userData, int index, const float co[3], vs->weight_orig = 0.0f; vs->flag = VGRAD_STORE_NOP; } - } - else { - /* no go */ - copy_v2_fl(vs->sco, FLT_MAX); - } - } - /* end init */ - if (vs->sco[0] != FLT_MAX) { - float alpha; + BLI_BITMAP_ENABLE(grad_data->vert_visit, index); - if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) { - alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end); + gradientVert_update(grad_data, index); } else { - BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL); - alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div; - } - /* no need to clamp 'alpha' yet */ - - /* adjust weight */ - alpha = BKE_brush_curve_strength_clamp(grad_data->brush, alpha, 1.0f); - - if (alpha != 0.0f) { - MDeformVert *dv = &me->dvert[index]; - MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr); - // dw->weight = alpha; // testing - int tool = grad_data->brush->vertexpaint_tool; - float testw; - - /* init if we just added */ - testw = wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha); - CLAMP(testw, 0.0f, 1.0f); - dw->weight = testw; - } - else { - MDeformVert *dv = &me->dvert[index]; - if (vs->flag & VGRAD_STORE_DW_EXIST) { - /* normally we NULL check, but in this case we know it exists */ - MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); - dw->weight = vs->weight_orig; - } - else { - /* wasn't originally existing, remove */ - MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr); - if (dw) { - defvert_remove_group(dv, dw); - } - } + /* no go */ + copy_v2_fl(vs->sco, FLT_MAX); } } } @@ -3364,6 +3395,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) data.def_nr = ob->actdef - 1; data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)); data.vert_cache = vert_cache; + data.vert_visit = NULL; data.type = RNA_enum_get(op->ptr, "type"); { @@ -3379,7 +3411,17 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) ED_view3d_init_mats_rv3d(ob, ar->regiondata); - dm->foreachMappedVert(dm, gradientVert__mapFunc, &data, DM_FOREACH_NOP); + if (data.is_init) { + data.vert_visit = BLI_BITMAP_NEW(me->totvert, __func__); + + dm->foreachMappedVert(dm, gradientVertInit__mapFunc, &data, DM_FOREACH_NOP); + + MEM_freeN(data.vert_visit); + data.vert_visit = NULL; + } + else { + dm->foreachMappedVert(dm, gradientVertUpdate__mapFunc, &data, DM_FOREACH_NOP); + } DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 12223effcf5..33d0510c08a 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -37,6 +37,7 @@ #include "BLI_math.h" #include "BLI_blenlib.h" +#include "BLI_dial.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" #include "BLI_threads.h" @@ -238,12 +239,8 @@ typedef struct StrokeCache { float anchored_location[3]; float vertex_rotation; /* amount to rotate the vertices when using rotate brush */ - float previous_vertex_rotation; /* previous rotation, used to detect if we rotate more than - * PI radians */ - short num_vertex_turns; /* records number of full 2*PI turns */ - float initial_mouse_dir[2]; /* used to calculate initial angle */ - bool init_dir_set; /* detect if we have initialized the initial mouse direction */ - + Dial *dial; + char saved_active_brush_name[MAX_ID_NAME]; char saved_mask_brush_tool; int saved_smooth_size; /* smooth tool copies the size of the current tool */ @@ -359,19 +356,19 @@ static int sculpt_stroke_dynamic_topology(const SculptSession *ss, !(brush->flag & BRUSH_ANCHORED) && !(brush->flag & BRUSH_DRAG_DOT) && - (!ELEM6(brush->sculpt_tool, - /* These brushes, as currently coded, cannot - * support dynamic topology */ - SCULPT_TOOL_GRAB, - SCULPT_TOOL_ROTATE, - SCULPT_TOOL_THUMB, - SCULPT_TOOL_LAYER, + (!ELEM(brush->sculpt_tool, + /* These brushes, as currently coded, cannot + * support dynamic topology */ + SCULPT_TOOL_GRAB, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_LAYER, - /* These brushes could handle dynamic topology, - * but user feedback indicates it's better not - * to */ - SCULPT_TOOL_SMOOTH, - SCULPT_TOOL_MASK))); + /* These brushes could handle dynamic topology, + * but user feedback indicates it's better not + * to */ + SCULPT_TOOL_SMOOTH, + SCULPT_TOOL_MASK))); } /*** paint mesh ***/ @@ -396,7 +393,7 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob) * entries might be inserted by sculpt_undo_push_node() into the * GHash used internally by BM_log_original_vert_co() by a * different thread. [#33787] */ -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP && !ss->bm) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { SculptUndoNode *unode; SculptUndoType type = (brush->sculpt_tool == SCULPT_TOOL_MASK ? @@ -663,47 +660,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float loca /* ===== Sculpting ===== * */ - -static float overlapped_curve(Brush *br, float x) -{ - int i; - const int n = 100 / br->spacing; - const float h = br->spacing / 50.0f; - const float x0 = x - 1; - - float sum; - - sum = 0; - for (i = 0; i < n; i++) { - float xx; - - xx = fabsf(x0 + i * h); - - if (xx < 1.0f) - sum += BKE_brush_curve_strength(br, xx, 1); - } - - return sum; -} - -static float integrate_overlap(Brush *br) -{ - int i; - int m = 10; - float g = 1.0f / m; - float max; - - max = 0; - for (i = 0; i < m; i++) { - float overlap = overlapped_curve(br, i * g); - - if (overlap > max) - max = overlap; - } - - return max; -} - static void flip_v3(float v[3], const char symm) { flip_v3_v3(v, v, symm); @@ -776,7 +732,7 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache) /* Return modified brush strength. Includes the direction of the brush, positive * values pull vertices, negative values push. Uses tablet pressure and a * special multiplier found experimentally to scale the strength factor. */ -static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather) +static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather, UnifiedPaintSettings *ups) { const Scene *scene = cache->vc->scene; Brush *brush = BKE_paint_brush(&sd->paint); @@ -788,13 +744,10 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather) float pressure = BKE_brush_use_alpha_pressure(scene, brush) ? cache->pressure : 1; float pen_flip = cache->pen_flip ? -1 : 1; float invert = cache->invert ? -1 : 1; - float accum = integrate_overlap(brush); + float overlap = ups->overlap_factor; /* spacing is integer percentage of radius, divide by 50 to get * normalized diameter */ - float overlap = (brush->flag & BRUSH_SPACE_ATTEN && - brush->flag & BRUSH_SPACE && - !(brush->flag & BRUSH_ANCHORED) && - (brush->spacing < 100)) ? 1.0f / accum : 1; + float flip = dir * invert * pen_flip; switch (brush->sculpt_tool) { @@ -1040,7 +993,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod zero_v3(an); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1236,14 +1189,14 @@ static int brush_needs_sculpt_normal(const Brush *brush) SCULPT_TOOL_SNAKE_HOOK) && (brush->normal_weight > 0)) || - ELEM7(brush->sculpt_tool, - SCULPT_TOOL_BLOB, - SCULPT_TOOL_CREASE, - SCULPT_TOOL_DRAW, - SCULPT_TOOL_LAYER, - SCULPT_TOOL_NUDGE, - SCULPT_TOOL_ROTATE, - SCULPT_TOOL_THUMB) || + ELEM(brush->sculpt_tool, + SCULPT_TOOL_BLOB, + SCULPT_TOOL_CREASE, + SCULPT_TOOL_DRAW, + SCULPT_TOOL_LAYER, + SCULPT_TOOL_NUDGE, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_THUMB) || (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)); } @@ -1646,7 +1599,7 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, for (iteration = 0; iteration <= count; ++iteration) { float strength = (iteration != count) ? 1.0f : last; -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { switch (type) { case PBVH_GRIDS: @@ -1682,7 +1635,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot int n; /* threaded loop over nodes */ -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1735,7 +1688,7 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) mul_v3_fl(offset, bstrength); /* threaded loop over nodes */ -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1790,7 +1743,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod if (brush->sculpt_tool == SCULPT_TOOL_BLOB) flippedbstrength *= -1.0f; /* threaded loop over nodes */ -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1833,7 +1786,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode float bstrength = ss->cache->bstrength; int n; -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1880,7 +1833,7 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) add_v3_v3(grab_delta, ss->cache->sculpt_normal_symm); } -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1928,7 +1881,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta); cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1976,7 +1929,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to add_v3_v3(grab_delta, ss->cache->sculpt_normal_symm); } -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2016,7 +1969,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta); cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2059,7 +2012,7 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod static const int flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 }; float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass]; -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2112,7 +2065,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode mul_v3_v3v3(offset, ss->cache->scale, ss->cache->sculpt_normal_symm); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2175,7 +2128,7 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno float bstrength = ss->cache->bstrength; int n; -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2220,7 +2173,7 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to zero_v3(fc); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2327,7 +2280,7 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, /* for flatten center */ zero_v3(fc); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2579,7 +2532,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno mul_v3_fl(temp, displace); add_v3_v3(fc, temp); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2651,7 +2604,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) /* add_v3_v3v3(p, ss->cache->location, an); */ -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2752,7 +2705,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t mul_m4_m4m4(tmat, mat, scale); invert_m4_m4(mat, tmat); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2816,7 +2769,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) mul_v3_fl(temp, displace); add_v3_v3(fc, temp); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2880,7 +2833,7 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod mul_v3_fl(temp, displace); add_v3_v3(fc, temp); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2934,7 +2887,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl mul_v3_fl(offset, bstrength); /* threaded loop over nodes */ -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -3030,11 +2983,11 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush) radius = ss->cache->radius * 1.25f; data.radius_squared = radius * radius; - data.original = ELEM4(brush->sculpt_tool, - SCULPT_TOOL_GRAB, - SCULPT_TOOL_ROTATE, - SCULPT_TOOL_THUMB, - SCULPT_TOOL_LAYER) ? true : ss->cache->original; + data.original = ELEM(brush->sculpt_tool, + SCULPT_TOOL_GRAB, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_LAYER) ? true : ss->cache->original; BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); @@ -3092,18 +3045,18 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush) data.ss = ss; data.sd = sd; data.radius_squared = ss->cache->radius_squared; - data.original = ELEM4(brush->sculpt_tool, - SCULPT_TOOL_GRAB, - SCULPT_TOOL_ROTATE, - SCULPT_TOOL_THUMB, - SCULPT_TOOL_LAYER) ? true : ss->cache->original; + data.original = ELEM(brush->sculpt_tool, + SCULPT_TOOL_GRAB, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_LAYER) ? true : ss->cache->original; BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); /* Only act if some verts are inside the brush area */ if (totnode) { float location[3]; -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { sculpt_undo_push_node(ob, nodes[n], brush->sculpt_tool == SCULPT_TOOL_MASK ? @@ -3233,10 +3186,10 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) ss->cache->supports_gravity) { /* these brushes start from original coordinates */ - const bool use_orco = ELEM3(brush->sculpt_tool, SCULPT_TOOL_GRAB, - SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB); + const bool use_orco = ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, + SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; PBVHProxyNode *proxies; @@ -3329,7 +3282,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob) BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; @@ -3377,7 +3330,7 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm, /* XXX This reduces the length of the grab delta if it approaches the line of symmetry * XXX However, a different approach appears to be needed */ #if 0 - if (sd->flags & SCULPT_SYMMETRY_FEATHER) { + if (sd->paint.symmetry_flags & SCULPT_SYMMETRY_FEATHER) { float frac = 1.0f / max_overlap_count(sd); float reduce = (feather - frac) / (1 - frac); @@ -3437,7 +3390,7 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob) } static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob, - BrushActionFunc action) + BrushActionFunc action, UnifiedPaintSettings *ups) { Brush *brush = BKE_paint_brush(&sd->paint); SculptSession *ss = ob->sculpt; @@ -3447,7 +3400,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob, float feather = calc_symmetry_feather(sd, ss->cache); - cache->bstrength = brush_strength(sd, cache, feather); + cache->bstrength = brush_strength(sd, cache, feather, ups); cache->symmetry = symm; /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ @@ -3571,6 +3524,8 @@ static void sculpt_cache_free(StrokeCache *cache) { if (cache->face_norms) MEM_freeN(cache->face_norms); + if (cache->dial) + MEM_freeN(cache->dial); MEM_freeN(cache); } @@ -3733,8 +3688,8 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio /* not very nice, but with current events system implementation * we can't handle brush appearance inversion hotkey separately (sergey) */ - if (cache->invert) brush->flag |= BRUSH_INVERTED; - else brush->flag &= ~BRUSH_INVERTED; + if (cache->invert) ups->draw_inverted = true; + else ups->draw_inverted = false; /* Alt-Smooth */ if (cache->alt_smooth) { @@ -3780,7 +3735,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio mul_m3_v3(mat, viewDir); normalize_v3_v3(cache->true_view_normal, viewDir); - cache->supports_gravity = (!ELEM3(brush->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY) && + cache->supports_gravity = (!ELEM(brush->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY) && (sd->gravity_factor > 0.0f)); /* get gravity vector in world space */ if (cache->supports_gravity) { @@ -3838,10 +3793,10 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio cache->original = 1; } - 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_FLATTEN)) + if (ELEM(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_FLATTEN)) { if (!(brush->flag & BRUSH_ACCUMULATE)) { cache->original = 1; @@ -3850,11 +3805,12 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio cache->first_time = 1; - cache->vertex_rotation = 0; - cache->num_vertex_turns = 0; - cache->previous_vertex_rotation = 0; - cache->init_dir_set = false; - +#define PIXEL_INPUT_THRESHHOLD 5 + if (brush->sculpt_tool == SCULPT_TOOL_ROTATE) + cache->dial = BLI_dial_initialize(cache->initial_mouse, PIXEL_INPUT_THRESHHOLD); + +#undef PIXEL_INPUT_THRESHHOLD + sculpt_omp_start(sd, ss); } @@ -3868,10 +3824,10 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru }; int tool = brush->sculpt_tool; - if (ELEM5(tool, - SCULPT_TOOL_GRAB, SCULPT_TOOL_NUDGE, - SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_SNAKE_HOOK, - SCULPT_TOOL_THUMB)) + if (ELEM(tool, + SCULPT_TOOL_GRAB, SCULPT_TOOL_NUDGE, + SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_SNAKE_HOOK, + SCULPT_TOOL_THUMB)) { float grab_location[3], imat[4][4], delta[3], loc[3]; @@ -3992,16 +3948,9 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, cache->radius_squared = cache->radius * cache->radius; if (brush->flag & BRUSH_ANCHORED) { + /* true location has been calculated as part of the stroke system already here */ if (brush->flag & BRUSH_EDGE_TO_EDGE) { - float halfway[2]; - float out[3]; - halfway[0] = 0.5f * (cache->mouse[0] + cache->initial_mouse[0]); - halfway[1] = 0.5f * (cache->mouse[1] + cache->initial_mouse[1]); - - if (sculpt_stroke_get_location(C, out, halfway)) { - copy_v3_v3(cache->anchored_location, out); - copy_v3_v3(cache->true_location, cache->anchored_location); - } + RNA_float_get_array(ptr, "location", cache->true_location); } cache->radius = paint_calc_object_space_radius(cache->vc, @@ -4015,48 +3964,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, sculpt_update_brush_delta(ups, ob, brush); if (brush->sculpt_tool == SCULPT_TOOL_ROTATE) { -#define PIXEL_INPUT_THRESHHOLD 5 - - const float dx = cache->mouse[0] - cache->initial_mouse[0]; - const float dy = cache->mouse[1] - cache->initial_mouse[1]; - - /* only update when we have enough precision, by having the mouse adequately away from center - * may be better to convert to radial representation but square works for small values too*/ - if (fabsf(dx) > PIXEL_INPUT_THRESHHOLD && fabsf(dy) > PIXEL_INPUT_THRESHHOLD) { - float mouse_angle; - float dir[2] = {dx, dy}; - float cosval, sinval; - normalize_v2(dir); - - if (!cache->init_dir_set) { - copy_v2_v2(cache->initial_mouse_dir, dir); - cache->init_dir_set = true; - } - - /* calculate mouse angle between initial and final mouse position */ - cosval = dot_v2v2(dir, cache->initial_mouse_dir); - sinval = cross_v2v2(dir, cache->initial_mouse_dir); - - /* clamp to avoid nans in acos */ - CLAMP(cosval, -1.0f, 1.0f); - mouse_angle = (sinval > 0) ? acosf(cosval) : -acosf(cosval); - - /* change of sign, we passed the 180 degree threshold. This means we need to add a turn. - * to distinguish between transition from 0 to -1 and -PI to +PI, use comparison with PI/2 */ - if ((mouse_angle * cache->previous_vertex_rotation < 0.0f) && - (fabsf(cache->previous_vertex_rotation) > (float)M_PI_2)) - { - if (cache->previous_vertex_rotation < 0) - cache->num_vertex_turns--; - else - cache->num_vertex_turns++; - } - cache->previous_vertex_rotation = mouse_angle; - - cache->vertex_rotation = -(mouse_angle + 2.0f * (float)M_PI * cache->num_vertex_turns) * cache->bstrength; - -#undef PIXEL_INPUT_THRESHHOLD - } + cache->vertex_rotation = -BLI_dial_angle(cache->dial, cache->mouse) * cache->bstrength; ups->draw_anchored = true; copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse); @@ -4393,10 +4301,10 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st } if (sculpt_stroke_dynamic_topology(ss, brush)) { - do_symmetrical_brush_actions(sd, ob, sculpt_topology_update); + do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups); } - do_symmetrical_brush_actions(sd, ob, do_brush_action); + do_symmetrical_brush_actions(sd, ob, do_brush_action, ups); sculpt_combine_proxies(sd, ob); @@ -4446,8 +4354,9 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str /* Finished */ if (ss->cache) { + UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; Brush *brush = BKE_paint_brush(&sd->paint); - brush->flag &= ~BRUSH_INVERTED; + ups->draw_inverted = false; sculpt_stroke_modifiers_check(C, ob); @@ -4506,7 +4415,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent if (!sculpt_brush_stroke_init(C, op)) return OPERATOR_CANCELLED; - stroke = paint_stroke_new(C, sculpt_stroke_get_location, + stroke = paint_stroke_new(C, op, sculpt_stroke_get_location, sculpt_stroke_test_start, sculpt_stroke_update_step, NULL, sculpt_stroke_done, event->type); @@ -4521,10 +4430,13 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_PASS_THROUGH; } + if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { + paint_stroke_data_free(op); + return OPERATOR_FINISHED; + } /* add modal handler */ WM_event_add_modal_handler(C, op); - retval = op->type->modal(C, op, event); OPERATOR_RETVAL_CHECK(retval); BLI_assert(retval == OPERATOR_RUNNING_MODAL); @@ -4536,7 +4448,7 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op) if (!sculpt_brush_stroke_init(C, op)) return OPERATOR_CANCELLED; - op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, sculpt_stroke_test_start, + op->customdata = paint_stroke_new(C, op, sculpt_stroke_get_location, sculpt_stroke_test_start, sculpt_stroke_update_step, NULL, sculpt_stroke_done, 0); /* frees op->customdata */ @@ -4567,13 +4479,6 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op) static void SCULPT_OT_brush_stroke(wmOperatorType *ot) { - static EnumPropertyItem stroke_mode_items[] = { - {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally"}, - {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"}, - {BRUSH_STROKE_SMOOTH, "SMOOTH", 0, "Smooth", "Switch brush to smooth mode for duration of stroke"}, - {0} - }; - /* identifiers */ ot->name = "Sculpt"; ot->idname = "SCULPT_OT_brush_stroke"; @@ -4591,15 +4496,11 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot) /* properties */ - RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); - - RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, - "Sculpt Stroke Mode", - "Action taken when a sculpt stroke is made"); + paint_stroke_operator_properties(ot); RNA_def_boolean(ot->srna, "ignore_background_click", 0, "Ignore Background Click", - "Clicks on the background do not start the stroke"); + "Clicks on the background do not start the stroke"); } /**** Reset the copy of the mesh that is being sculpted on (currently just for the layer brush) ****/ @@ -4856,7 +4757,7 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co bool modifiers = false; for (i = 0; i < CD_NUMTYPES; i++) { - if (!ELEM7(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) && + if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) && (CustomData_has_layer(&me->vdata, i) || CustomData_has_layer(&me->edata, i) || CustomData_has_layer(&me->fdata, i))) @@ -5062,11 +4963,11 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) ts->sculpt->paint.flags |= PAINT_SHOW_BRUSH; /* Make sure at least dyntopo subdivision is enabled */ - ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE; + ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE; } if (!ts->sculpt->detail_size) { - ts->sculpt->detail_size = 30; + ts->sculpt->detail_size = 12; } if (ts->sculpt->constant_detail == 0.0f) diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index cd79f525d82..a61f571fdf6 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -130,4 +130,11 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]); void sculpt_update_object_bounding_box(struct Object *ob); +/* Setting zero so we can catch bugs in OpenMP/sculpt. */ +#ifdef DEBUG +# define SCULPT_OMP_LIMIT 0 +#else +# define SCULPT_OMP_LIMIT 4 +#endif + #endif diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 0d49049c78e..91f80a4fc40 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -291,7 +291,7 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C, BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (i = 0; i < totnode; i++) { BKE_pbvh_node_mark_redraw(nodes[i]); } @@ -543,7 +543,7 @@ static void sculpt_undo_free(ListBase *lb) } } -bool sculpt_undo_cleanup(bContext *C, ListBase *lb) +static bool sculpt_undo_cleanup(bContext *C, ListBase *lb) { Object *ob = CTX_data_active_object(C); SculptUndoNode *unode; @@ -551,10 +551,8 @@ bool sculpt_undo_cleanup(bContext *C, ListBase *lb) unode = lb->first; if (unode && strcmp(unode->idname, ob->id.name) != 0) { - for (unode = lb->first; unode; unode = unode->next) { - if (unode->bm_entry) - BM_log_cleanup_entry(unode->bm_entry); - } + if (unode->bm_entry) + BM_log_cleanup_entry(unode->bm_entry); return true; } @@ -881,7 +879,7 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, void sculpt_undo_push_begin(const char *name) { ED_undo_paint_push_begin(UNDO_PAINT_MESH, name, - sculpt_undo_restore, sculpt_undo_free); + sculpt_undo_restore, sculpt_undo_free, sculpt_undo_cleanup); } void sculpt_undo_push_end(void) diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index 797a881ce79..292d6236bab 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -239,12 +239,14 @@ void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings BKE_paint_init(&settings->uvsculpt->paint, PAINT_CURSOR_SCULPT); - WM_paint_cursor_activate(wm, uv_sculpt_brush_poll, - brush_drawcursor_uvsculpt, NULL); + settings->uvsculpt->paint.paint_cursor = WM_paint_cursor_activate(wm, uv_sculpt_brush_poll, + brush_drawcursor_uvsculpt, NULL); } else { - if (settings->uvsculpt) - settings->uvsculpt->paint.flags &= ~PAINT_SHOW_BRUSH; + if (settings->uvsculpt) { + WM_paint_cursor_end(wm, settings->uvsculpt->paint.paint_cursor); + settings->uvsculpt->paint.paint_cursor = NULL; + } } } diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index b2e55085579..335949e8495 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -219,7 +219,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT)) sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT); - if (ELEM3(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) { + if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) { switch (ale->type) { case ANIMTYPE_SUMMARY: { diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index cf18cffefb6..ddfca98a119 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -1086,8 +1086,9 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_ View2D *v2d = &ac->ar->v2d; bDopeSheet *ads = NULL; int channel_index; - short found = 0; - float selx = 0.0f; + bool found = false; + float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */ + float selx = 0.0f; /* frame of keyframe under mouse */ float x, y; rctf rectf; @@ -1179,7 +1180,8 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_ * requiring to map each frame once again... */ selx = BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP); - found = 1; + frame = ak->cfra; + found = true; break; } else if (ak->cfra < rectf.xmin) @@ -1258,8 +1260,11 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_ if (found) { /* apply selection to keyframes */ if (column) { - /* select all keyframes in the same frame as the one we hit on the active channel */ - actkeys_mselect_column(ac, select_mode, selx); + /* select all keyframes in the same frame as the one we hit on the active channel + * [T41077]: "frame" not "selx" here (i.e. no NLA corrections yet) as the code here + * does that itself again as it needs to work on multiple datablocks + */ + actkeys_mselect_column(ac, select_mode, frame); } else if (same_channel) { /* select all keyframes in the active channel */ diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 7a74a58c69d..c8431d58bf5 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -61,6 +61,7 @@ #include "ED_space_api.h" #include "ED_sound.h" #include "ED_uvedit.h" +#include "ED_view3d.h" #include "ED_mball.h" #include "ED_logic.h" #include "ED_clip.h" @@ -130,8 +131,17 @@ void ED_spacetypes_init(void) type->operatortypes(); } - /* Macros's must go last since they reference other operators - * maybe we'll need to have them go after python operators too? */ + /* register internal render callbacks */ + ED_render_internal_init(); +} + +void ED_spacemacros_init(void) +{ + const ListBase *spacetypes; + SpaceType *type; + + /* Macros's must go last since they reference other operators. + * We need to have them go after python operators too */ ED_operatormacros_armature(); ED_operatormacros_mesh(); ED_operatormacros_metaball(); @@ -144,6 +154,7 @@ void ED_spacetypes_init(void) ED_operatormacros_curve(); ED_operatormacros_mask(); ED_operatormacros_sequencer(); + ED_operatormacros_paint(); /* register dropboxes (can use macros) */ spacetypes = BKE_spacetypes_list(); @@ -151,9 +162,6 @@ void ED_spacetypes_init(void) if (type->dropboxes) type->dropboxes(); } - - /* register internal render callbacks */ - ED_render_internal_init(); } /* called in wm.c */ diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 5fcceb25e4e..524a42ba388 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -55,6 +55,7 @@ #include "BKE_particle.h" #include "BKE_screen.h" #include "BKE_texture.h" +#include "BKE_linestyle.h" #include "RNA_access.h" @@ -153,7 +154,7 @@ static int buttons_context_path_linestyle(ButsContextPath *path) /* if we have a scene, use the lineset's linestyle */ else if (buttons_context_path_scene(path)) { scene = path->ptr[path->len - 1].data; - linestyle = CTX_data_linestyle_from_scene(scene); + linestyle = BKE_linestyle_active_from_scene(scene); if (linestyle) { RNA_id_pointer_create(&linestyle->id, &path->ptr[path->len]); path->len++; @@ -199,7 +200,7 @@ static int buttons_context_path_data(ButsContextPath *path, int type) /* if we already have a data, we're done */ if (RNA_struct_is_a(ptr->type, &RNA_Mesh) && (type == -1 || type == OB_MESH)) return 1; - else if (RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM3(type, OB_CURVE, OB_SURF, OB_FONT))) return 1; + else if (RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM(type, OB_CURVE, OB_SURF, OB_FONT))) return 1; else if (RNA_struct_is_a(ptr->type, &RNA_Armature) && (type == -1 || type == OB_ARMATURE)) return 1; else if (RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) return 1; else if (RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) return 1; @@ -229,7 +230,7 @@ static int buttons_context_path_modifier(ButsContextPath *path) if (buttons_context_path_object(path)) { ob = path->ptr[path->len - 1].data; - if (ob && ELEM5(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE)) + if (ob && ELEM(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE)) return 1; } @@ -637,7 +638,7 @@ static int buttons_shading_context(const bContext *C, int mainb) { Object *ob = CTX_data_active_object(C); - if (ELEM3(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE)) + if (ELEM(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE)) return 1; if (mainb == BCONTEXT_DATA && ob && ELEM(ob->type, OB_LAMP, OB_CAMERA)) return 1; @@ -1119,7 +1120,7 @@ void buttons_context_draw(const bContext *C, uiLayout *layout) name = RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf), NULL); if (name) { - if (!ELEM3(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_RENDER_LAYER) && ptr->type == &RNA_Scene) + if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_RENDER_LAYER) && ptr->type == &RNA_Scene) uiItemLDrag(row, ptr, "", icon); /* save some space */ else uiItemLDrag(row, ptr, name, icon); diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 0aa3e47df4b..020d477fc39 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -53,8 +53,8 @@ #include "DNA_world_types.h" #include "DNA_linestyle_types.h" - #include "BKE_context.h" +#include "BKE_linestyle.h" #include "BKE_material.h" #include "BKE_modifier.h" #include "BKE_node.h" @@ -352,7 +352,7 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext * ob = (scene->basact) ? scene->basact->object : NULL; wrld = scene->world; brush = BKE_paint_brush(BKE_paint_get_active_from_context(C)); - linestyle = CTX_data_linestyle_from_scene(scene); + linestyle = BKE_linestyle_active_from_scene(scene); } if (ob && ob->type == OB_LAMP && !la) @@ -370,7 +370,7 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext * if (wrld && !limited_mode) buttons_texture_users_find_nodetree(users, &wrld->id, wrld->nodetree, "World"); if (linestyle && !limited_mode) - buttons_texture_users_find_nodetree(users, &linestyle->id, linestyle->nodetree, "LineStyle"); + buttons_texture_users_find_nodetree(users, &linestyle->id, linestyle->nodetree, "Line Style"); if (ob) { ParticleSystem *psys = psys_get_current(ob); diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 1c3bad9757d..8c6bf67c9a8 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -358,7 +358,7 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier * case NC_ANIMATION: switch (wmn->data) { case ND_KEYFRAME: - if (ELEM3(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) + if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) ED_area_tag_redraw(sa); break; } diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 9c31b909a95..cf7032cbe2d 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -1592,21 +1592,7 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip, } } - if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) { - MovieTrackingTrack *track = BKE_tracking_track_get_active(&sc->clip->tracking); - - if (track) { - int framenr = ED_space_clip_get_clip_frame_number(sc); - MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); - - offsx = marker->pos[0]; - offsy = marker->pos[1]; - - gpd = track->gpd; - } - - } - else { + if (sc->gpencil_src != SC_GPENCIL_SRC_TRACK) { gpd = clip->gpd; } @@ -1725,7 +1711,7 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar) smat[1][1] = 1.0f / height; invert_m4_m4(ismat, smat); - mul_serie_m4(sc->unistabmat, smat, sc->stabmat, ismat, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(sc->unistabmat, smat, sc->stabmat, ismat); } } else if ((sc->flag & SC_MUTE_FOOTAGE) == 0) { @@ -1775,13 +1761,15 @@ void clip_draw_grease_pencil(bContext *C, int onlyv2d) return; if (onlyv2d) { - /* if manual calibration is used then grease pencil data is already - * drawn in draw_distortion */ - if ((sc->flag & SC_MANUAL_CALIBRATION) == 0) { + bool is_track_source = sc->gpencil_src == SC_GPENCIL_SRC_TRACK; + /* if manual calibration is used then grease pencil data + * associated with the clip is already drawn in draw_distortion + */ + if ((sc->flag & SC_MANUAL_CALIBRATION) == 0 || is_track_source) { glPushMatrix(); glMultMatrixf(sc->unistabmat); - if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) { + if (is_track_source) { MovieTrackingTrack *track = BKE_tracking_track_get_active(&sc->clip->tracking); if (track) { diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c index 95f59e79c08..d1e2c770ade 100644 --- a/source/blender/editors/space_clip/clip_graph_ops.c +++ b/source/blender/editors/space_clip/clip_graph_ops.c @@ -104,7 +104,7 @@ typedef struct { 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 */ + float min_dist_sq, /* minimal distance between mouse and currently found entity */ mouse_co[2], /* mouse coordinate */ prev_co[2], /* coordinate of previeous point of segment */ min_co[2]; /* coordinate of entity with minimal distance */ @@ -121,11 +121,11 @@ static void find_nearest_tracking_segment_cb(void *userdata, MovieTrackingTrack float co[2] = {scene_framenr, val}; if (data->has_prev) { - float d = dist_to_line_segment_v2(data->mouse_co, data->prev_co, co); + float dist_sq = dist_squared_to_line_segment_v2(data->mouse_co, data->prev_co, co); - if (data->track == NULL || d < data->min_dist) { + if (data->track == NULL || dist_sq < data->min_dist_sq) { data->track = track; - data->min_dist = d; + data->min_dist_sq = dist_sq; data->coord = coord; copy_v2_v2(data->min_co, co); } @@ -146,15 +146,15 @@ static void find_nearest_tracking_knot_cb(void *userdata, MovieTrackingTrack *tr MovieTrackingMarker *marker, int coord, int scene_framenr, float val) { MouseSelectUserData *data = userdata; - float dx = scene_framenr - data->mouse_co[0], dy = val - data->mouse_co[1]; - float d = dx * dx + dy * dy; + float mdiff[2] = {scene_framenr - data->mouse_co[0], val - data->mouse_co[1]}; + float dist_sq = len_squared_v2(mdiff); - if (data->marker == NULL || d < data->min_dist) { + if (data->marker == NULL || dist_sq < data->min_dist_sq) { float co[2] = {scene_framenr, val}; data->track = track; data->marker = marker; - data->min_dist = d; + data->min_dist_sq = dist_sq; data->coord = coord; copy_v2_v2(data->min_co, co); } @@ -164,7 +164,7 @@ static void find_nearest_tracking_knot_cb(void *userdata, MovieTrackingTrack *tr static void mouse_select_init_data(MouseSelectUserData *userdata, const float co[2]) { memset(userdata, 0, sizeof(MouseSelectUserData)); - userdata->min_dist = FLT_MAX; + userdata->min_dist_sq = FLT_MAX; copy_v2_v2(userdata->mouse_co, co); } diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index c0434def3d5..87efaa615ee 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -591,6 +591,8 @@ static void view_zoom_cancel(bContext *C, wmOperator *op) void CLIP_OT_view_zoom(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "View Zoom"; ot->idname = "CLIP_OT_view_zoom"; @@ -607,8 +609,9 @@ void CLIP_OT_view_zoom(wmOperatorType *ot) ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER; /* properties */ - RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, - "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX); + prop = RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, "Factor", + "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); } /********************** view zoom in/out operator *********************/ @@ -641,6 +644,8 @@ static int view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event void CLIP_OT_view_zoom_in(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "View Zoom In"; ot->idname = "CLIP_OT_view_zoom_in"; @@ -652,8 +657,9 @@ void CLIP_OT_view_zoom_in(wmOperatorType *ot) ot->poll = ED_space_clip_view_clip_poll; /* properties */ - RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", - "Cursor location in screen coordinates", -10.0f, 10.0f); + prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", + "Cursor location in screen coordinates", -10.0f, 10.0f); + RNA_def_property_flag(prop, PROP_HIDDEN); } static int view_zoom_out_exec(bContext *C, wmOperator *op) @@ -684,6 +690,8 @@ static int view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent *even void CLIP_OT_view_zoom_out(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "View Zoom Out"; ot->idname = "CLIP_OT_view_zoom_out"; @@ -695,8 +703,9 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot) ot->poll = ED_space_clip_view_clip_poll; /* properties */ - RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", - "Cursor location in normalized (0.0-1.0) coordinates", -10.0f, 10.0f); + prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", + "Cursor location in normalized (0.0-1.0) coordinates", -10.0f, 10.0f); + RNA_def_property_flag(prop, PROP_HIDDEN); } /********************** view zoom ratio operator *********************/ diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index d3be25050c8..a6fbb0c399d 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -846,7 +846,7 @@ static int clip_context(const bContext *C, const char *member, bContextDataResul static int clip_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_PATH) - if (ELEM4(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */ + if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */ return true; return false; diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index ce14471f608..abbffcd8546 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -2277,7 +2277,7 @@ static void set_axis(Scene *scene, Object *ob, MovieClip *clip, MovieTrackingOb copy_v3_v3(lmat[3], obmat[3]); invert_m4_m4(ilmat, lmat); - mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL); + mul_m4_series(mat, lmat, mat, ilmat, obmat); } else { mul_m4_m4m4(mat, obmat, mat); @@ -2996,7 +2996,7 @@ void CLIP_OT_detect_features(wmOperatorType *ot) /* properties */ RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement", "Placement for detected features"); RNA_def_int(ot->srna, "margin", 16, 0, INT_MAX, "Margin", "Only features further than margin pixels from the image edges are considered", 0, 300); - RNA_def_float(ot->srna, "threshold", 1.0f, 0.0001f, FLT_MAX, "Threshold", "Threshold level to consider feature good enough for tracking", 0.0001f, FLT_MAX); + RNA_def_float(ot->srna, "threshold", 0.5f, 0.0001f, FLT_MAX, "Threshold", "Threshold level to consider feature good enough for tracking", 0.0001f, FLT_MAX); RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance", "Minimal distance accepted between two features", 0, 300); } diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 29846246a9b..f6f11316a04 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -414,11 +414,12 @@ static void draw_background(FileLayout *layout, View2D *v2d) int i; int sy; + UI_ThemeColorShade(TH_BACK, -7); + /* alternating flat shade background */ for (i = 0; (i <= layout->rows); i += 2) { sy = (int)v2d->cur.ymax - i * (layout->tile_h + 2 * layout->tile_border_y) - layout->tile_border_y; - UI_ThemeColorShade(TH_BACK, -7); glRectf(v2d->cur.xmin, (float)sy, v2d->cur.xmax, (float)(sy + layout->tile_h + 2 * layout->tile_border_y)); } @@ -426,18 +427,36 @@ static void draw_background(FileLayout *layout, View2D *v2d) static void draw_dividers(FileLayout *layout, View2D *v2d) { + const int step = (layout->tile_w + 2 * layout->tile_border_x); + int v1[2], v2[2]; int sx; + unsigned char col_hi[3], col_lo[3]; + + UI_GetThemeColorShade3ubv(TH_BACK, 30, col_hi); + UI_GetThemeColorShade3ubv(TH_BACK, -30, col_lo); + + v1[1] = v2d->cur.ymax - layout->tile_border_y; + v2[1] = v2d->cur.ymin; + + glBegin(GL_LINES); /* vertical column dividers */ sx = (int)v2d->tot.xmin; while (sx < v2d->cur.xmax) { - sx += (layout->tile_w + 2 * layout->tile_border_x); - - UI_ThemeColorShade(TH_BACK, 30); - sdrawline(sx + 1, (short)(v2d->cur.ymax - layout->tile_border_y), sx + 1, (short)v2d->cur.ymin); - UI_ThemeColorShade(TH_BACK, -30); - sdrawline(sx, (short)(v2d->cur.ymax - layout->tile_border_y), sx, (short)v2d->cur.ymin); + sx += step; + + glColor3ubv(col_lo); + v1[0] = v2[0] = sx; + glVertex2iv(v1); + glVertex2iv(v2); + + glColor3ubv(col_hi); + v1[0] = v2[0] = sx + 1; + glVertex2iv(v1); + glVertex2iv(v2); } + + glEnd(); } void file_draw_list(const bContext *C, ARegion *ar) diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 1d3013bd8b4..27d6fabba4e 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1277,8 +1277,9 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN const char *lastdir = folderlist_peeklastdir(sfile->folders_prev); /* if not, ask to create it and enter if confirmed */ + wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false); PointerRNA ptr; - WM_operator_properties_create(&ptr, "FILE_OT_directory_new"); + WM_operator_properties_create_ptr(&ptr, ot); RNA_string_set(&ptr, "directory", sfile->params->dir); RNA_boolean_set(&ptr, "open", true); @@ -1286,7 +1287,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); - WM_operator_name_call(C, "FILE_OT_directory_new", WM_OP_INVOKE_DEFAULT, &ptr); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); WM_operator_properties_free(&ptr); } diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index 69789569912..8fad17e1210 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -57,12 +57,13 @@ static void file_panel_cb(bContext *C, void *arg_entry, void *UNUSED(arg_v)) { + wmOperatorType *ot = WM_operatortype_find("FILE_OT_select_bookmark", false); PointerRNA ptr; const char *entry = (char *)arg_entry; - WM_operator_properties_create(&ptr, "FILE_OT_select_bookmark"); + WM_operator_properties_create_ptr(&ptr, ot); RNA_string_set(&ptr, "dir", entry); - WM_operator_name_call(C, "FILE_OT_select_bookmark", WM_OP_INVOKE_REGION_WIN, &ptr); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_REGION_WIN, &ptr); WM_operator_properties_free(&ptr); } diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 81ab276ccc0..afe3f29e9bc 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -281,14 +281,28 @@ int ED_fileselect_layout_numfiles(FileLayout *layout, ARegion *ar) { int numfiles; + /* Values in pixels. + * + * - *_item: size of each (row|col), (including padding) + * - *_view: (x|y) size of the view. + * - *_over: extra pixels, to take into account, when the fit isnt exact + * (needed since you may see the end of the previous column and the beginning of the next). + * + * Could be more clever and take scrolling into account, + * but for now don't bother. + */ if (layout->flag & FILE_LAYOUT_HOR) { - int width = (int)(BLI_rctf_size_x(&ar->v2d.cur) - 2 * layout->tile_border_x); - numfiles = (int)((float)width / (float)layout->tile_w + 0.5f); + const int x_item = layout->tile_w + (2 * layout->tile_border_x); + const int x_view = (int)(BLI_rctf_size_x(&ar->v2d.cur)); + const int x_over = x_item - (x_view % x_item); + numfiles = (int)((float)(x_view + x_over) / (float)(x_item)); return numfiles * layout->rows; } else { - int height = (int)(BLI_rctf_size_y(&ar->v2d.cur) - 2 * layout->tile_border_y); - numfiles = (int)((float)height / (float)layout->tile_h + 0.5f); + const int y_item = layout->tile_h + (2 * layout->tile_border_y); + const int y_view = (int)(BLI_rctf_size_y(&ar->v2d.cur)); + const int y_over = y_item - (y_view % y_item); + numfiles = (int)((float)(y_view + y_over) / (float)(y_item)); return numfiles * layout->columns; } } diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 3a493c0338c..d5be04cff20 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -422,7 +422,7 @@ static void file_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, 0, 0); kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "extend", true); - kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_ALT, 0); + kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_CTRL | KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "extend", true); RNA_boolean_set(kmi->ptr, "fill", true); diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index d1738f3dada..b59030d3c12 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -560,7 +560,7 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar * uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */ uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Bone 1:")); - if (dtar->id && ob1->pose) { + if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) { PointerRNA tar_ptr; RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr); @@ -571,7 +571,7 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar * uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */ uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Bone 2:")); - if (dtar2->id && ob2->pose) { + if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) { PointerRNA tar_ptr; RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr); @@ -598,7 +598,7 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar * uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */ uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone 1:")); - if (dtar->id && ob1->pose) { + if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) { PointerRNA tar_ptr; RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr); @@ -612,7 +612,7 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar * uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */ uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Ob/Bone 2:")); - if (dtar2->id && ob2->pose) { + if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) { PointerRNA tar_ptr; RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr); @@ -639,7 +639,7 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */ uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone:")); - if (dtar->id && ob->pose) { + if (dtar->id && GS(dtar->id->name) == ID_OB && ob->pose) { PointerRNA tar_ptr; RNA_pointer_create(dtar->id, &RNA_Pose, ob->pose, &tar_ptr); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 1f1aac8c456..c8298927f7d 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -1707,7 +1707,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op) */ if (strstr(fcu->rna_path, "rotation_euler") == NULL) continue; - else if (ELEM3(fcu->array_index, 0, 1, 2) == 0) { + else if (ELEM(fcu->array_index, 0, 1, 2) == 0) { BKE_reportf(op->reports, RPT_WARNING, "Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)", (ale->id) ? ale->id->name : TIP_("<No ID>"), fcu->rna_path, fcu->array_index); @@ -1750,7 +1750,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op) /* sanity check: ensure that there are enough F-Curves to work on in this group */ /* TODO: also enforce assumption that there be a full set of keyframes at each position by ensuring that totvert counts are same? */ - if (ELEM3(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) { + if (ELEM(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) { /* report which components are missing */ BKE_reportf(op->reports, RPT_WARNING, "Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'", diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index fbfa9358a22..62b6b59df29 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -167,6 +167,7 @@ static int graphview_cursor_modal(bContext *C, wmOperator *op, const wmEvent *ev case LEFTMOUSE: case RIGHTMOUSE: + case MIDDLEMOUSE: /* we check for either mouse-button to end, as checking for ACTIONMOUSE (which is used to init * the modal op) doesn't work for some reason */ diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 3675282654f..7e90008d8d2 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -843,14 +843,14 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_man uiItemR(sub, imfptr, "color_mode", UI_ITEM_R_EXPAND, IFACE_("Color"), ICON_NONE); /* only display depth setting if multiple depths can be used */ - if ((ELEM7(depth_ok, - R_IMF_CHAN_DEPTH_1, - R_IMF_CHAN_DEPTH_8, - R_IMF_CHAN_DEPTH_10, - R_IMF_CHAN_DEPTH_12, - R_IMF_CHAN_DEPTH_16, - R_IMF_CHAN_DEPTH_24, - R_IMF_CHAN_DEPTH_32)) == 0) + if ((ELEM(depth_ok, + R_IMF_CHAN_DEPTH_1, + R_IMF_CHAN_DEPTH_8, + R_IMF_CHAN_DEPTH_10, + R_IMF_CHAN_DEPTH_12, + R_IMF_CHAN_DEPTH_16, + R_IMF_CHAN_DEPTH_24, + R_IMF_CHAN_DEPTH_32)) == 0) { row = uiLayoutRow(col, false); diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index a2f7d9e7d6c..24b1c54dd9f 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -28,6 +28,7 @@ * \ingroup spimage */ +#include "DNA_brush_types.h" #include "DNA_mask_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -297,44 +298,51 @@ bool ED_space_image_show_render(SpaceImage *sima) bool ED_space_image_show_paint(SpaceImage *sima) { if (ED_space_image_show_render(sima)) - return 0; + return false; return (sima->mode == SI_MODE_PAINT); } +bool ED_space_image_show_texpaint(SpaceImage *sima, Object *ob) +{ + return (ob && ob->type == OB_MESH && + ob->mode == OB_MODE_TEXTURE_PAINT && + !(sima->flag & SI_NO_DRAW_TEXPAINT)); +} + bool ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit) { if (sima && (ED_space_image_show_render(sima) || ED_space_image_show_paint(sima))) - return 0; + return false; if (obedit && obedit->type == OB_MESH) { struct BMEditMesh *em = BKE_editmesh_from_object(obedit); - int ret; + bool ret; ret = EDBM_mtexpoly_check(em); return ret; } - return 0; + return false; } bool ED_space_image_show_uvshadow(SpaceImage *sima, Object *obedit) { if (ED_space_image_show_render(sima)) - return 0; + return false; if (ED_space_image_show_paint(sima)) if (obedit && obedit->type == OB_MESH) { struct BMEditMesh *em = BKE_editmesh_from_object(obedit); - int ret; + bool ret; ret = EDBM_mtexpoly_check(em); - return ret; + return ret && !(sima->flag & SI_NO_DRAW_TEXPAINT); } - return 0; + return false; } /* matches clip function */ @@ -361,6 +369,21 @@ int ED_space_image_maskedit_poll(bContext *C) return false; } +bool ED_space_image_paint_curve(const bContext *C) +{ + SpaceImage *sima = CTX_wm_space_image(C); + + if (sima && sima->mode == SI_MODE_PAINT) { + Brush *br = CTX_data_tool_settings(C)->imapaint.paint.brush; + + if (br && (br->flag & BRUSH_CURVE)) + return true; + } + + return false; +} + + int ED_space_image_maskedit_mask_poll(bContext *C) { if (ED_space_image_maskedit_poll(C)) { diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h index 8e556378803..74a0a18b0c8 100644 --- a/source/blender/editors/space_image/image_intern.h +++ b/source/blender/editors/space_image/image_intern.h @@ -71,6 +71,7 @@ void IMAGE_OT_view_ndof(struct wmOperatorType *ot); void IMAGE_OT_new(struct wmOperatorType *ot); void IMAGE_OT_open(struct wmOperatorType *ot); +void IMAGE_OT_unlink(struct wmOperatorType *ot); void IMAGE_OT_match_movie_length(struct wmOperatorType *ot); void IMAGE_OT_replace(struct wmOperatorType *ot); void IMAGE_OT_reload(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 7c021cf6645..c87e547b6ea 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -48,6 +48,7 @@ #include "BKE_colortools.h" #include "BKE_context.h" +#include "BKE_depsgraph.h" #include "BKE_icons.h" #include "BKE_image.h" #include "BKE_global.h" @@ -564,6 +565,8 @@ static void image_view_zoom_cancel(bContext *C, wmOperator *op) void IMAGE_OT_view_zoom(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "View Zoom"; ot->idname = "IMAGE_OT_view_zoom"; @@ -580,8 +583,9 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot) ot->flag = OPTYPE_BLOCKING | OPTYPE_LOCK_BYPASS; /* properties */ - RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, - "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX); + prop = RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, "Factor", + "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); } /********************** NDOF operator *********************/ @@ -799,6 +803,8 @@ static int image_view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent void IMAGE_OT_view_zoom_in(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "View Zoom In"; ot->idname = "IMAGE_OT_view_zoom_in"; @@ -813,7 +819,9 @@ void IMAGE_OT_view_zoom_in(wmOperatorType *ot) ot->flag = OPTYPE_LOCK_BYPASS; /* properties */ - RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", "Cursor location in screen coordinates", -10.0f, 10.0f); + prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, + "Location", "Cursor location in screen coordinates", -10.0f, 10.0f); + RNA_def_property_flag(prop, PROP_HIDDEN); } static int image_view_zoom_out_exec(bContext *C, wmOperator *op) @@ -844,6 +852,8 @@ static int image_view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent void IMAGE_OT_view_zoom_out(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "View Zoom Out"; ot->idname = "IMAGE_OT_view_zoom_out"; @@ -858,7 +868,9 @@ void IMAGE_OT_view_zoom_out(wmOperatorType *ot) ot->flag = OPTYPE_LOCK_BYPASS; /* properties */ - RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", "Cursor location in screen coordinates", -10.0f, 10.0f); + prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, + "Location", "Cursor location in screen coordinates", -10.0f, 10.0f); + RNA_def_property_flag(prop, PROP_HIDDEN); } /********************** view zoom ratio operator *********************/ @@ -1382,7 +1394,7 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima, /* sanitize all settings */ /* unlikely but just in case */ - if (ELEM3(simopts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) { + if (ELEM(simopts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) { simopts->im_format.planes = R_IMF_PLANES_RGBA; } @@ -1484,9 +1496,12 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI } else { /* TODO, better solution, if a 24bit image is painted onto it may contain alpha */ - if (ibuf->userflags & IB_BITMAPDIRTY) { /* it has been painted onto */ + if ((simopts->im_format.planes == R_IMF_PLANES_RGBA) && + /* it has been painted onto */ + (ibuf->userflags & IB_BITMAPDIRTY)) + { /* checks each pixel, not ideal */ - ibuf->planes = BKE_imbuf_alpha_test(ibuf) ? 32 : 24; + ibuf->planes = BKE_imbuf_alpha_test(ibuf) ? R_IMF_PLANES_RGBA : R_IMF_PLANES_RGB; } } @@ -1866,6 +1881,7 @@ static int image_reload_exec(bContext *C, wmOperator *UNUSED(op)) // XXX other users? BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD); + DAG_id_tag_update(&ima->id, 0); WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); @@ -1921,7 +1937,7 @@ static int image_new_exec(bContext *C, wmOperator *op) gen_type = RNA_enum_get(op->ptr, "generated_type"); RNA_float_get_array(op->ptr, "color", color); alpha = RNA_boolean_get(op->ptr, "alpha"); - + if (!alpha) color[3] = 1.0f; @@ -2001,6 +2017,9 @@ void IMAGE_OT_new(wmOperatorType *ot) RNA_def_enum(ot->srna, "generated_type", image_generated_type_items, IMA_GENTYPE_BLANK, "Generated Type", "Fill the image with a grid for UV map testing"); RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth"); + prop = RNA_def_boolean(ot->srna, "texstencil", 0, "Stencil", "Set Image as stencil"); + RNA_def_property_flag(prop, PROP_HIDDEN); + } #undef IMA_DEF_NAME @@ -2035,7 +2054,7 @@ static int image_invert_exec(bContext *C, wmOperator *op) if (support_undo) { ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, - ED_image_undo_restore, ED_image_undo_free); + ED_image_undo_restore, ED_image_undo_free, NULL); /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles * but better do this right in case someone copies this for a tool that uses partial redraw better */ ED_imapaint_clear_partial_redraw(); @@ -2459,11 +2478,12 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event int point = RNA_enum_get(op->ptr, "point"); if (point == 1) { - curvemapping_set_black_white(curve_mapping, NULL, info->colfp); + curvemapping_set_black_white(curve_mapping, NULL, info->linearcol); } else if (point == 0) { - curvemapping_set_black_white(curve_mapping, info->colfp, NULL); + curvemapping_set_black_white(curve_mapping, info->linearcol, NULL); } + WM_event_add_notifier(C, NC_WINDOW, NULL); } } diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 0fb93ad27ee..375a0ddeac3 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -349,7 +349,7 @@ static void image_keymap(struct wmKeyConfig *keyconf) static int image_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_PATH) - if (ELEM3(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_BLANK)) /* rule might not work? */ + if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_BLANK)) /* rule might not work? */ return 1; return 0; } @@ -633,6 +633,12 @@ static void image_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); /* image paint polls for mode */ + keymap = WM_keymap_find(wm->defaultconf, "Curve", 0, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + + keymap = WM_keymap_find(wm->defaultconf, "Paint Curve", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + keymap = WM_keymap_find(wm->defaultconf, "Image Paint", 0, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); @@ -657,6 +663,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) Object *obact = CTX_data_active_object(C); Object *obedit = CTX_data_edit_object(C); Mask *mask = NULL; + bool curve = false; Scene *scene = CTX_data_scene(C); View2D *v2d = &ar->v2d; //View2DScrollers *scrollers; @@ -702,6 +709,9 @@ 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); } + else if (ED_space_image_paint_curve(C)) { + curve = true; + } ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); @@ -753,6 +763,11 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) draw_image_cursor(ar, sima->cursor); UI_view2d_view_restore(C); } + else if (curve) { + UI_view2d_view_ortho(v2d); + draw_image_cursor(ar, sima->cursor); + UI_view2d_view_restore(C); + } draw_image_cache(C, ar); diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 8664ebf30b7..a0dfb285a1c 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -57,6 +57,7 @@ #include "ED_armature.h" #define MAX_INFO_LEN 512 +#define MAX_INFO_NUM_LEN 16 typedef struct SceneStats { int totvert, totvertsel; @@ -65,11 +66,22 @@ typedef struct SceneStats { int totbone, totbonesel; int totobj, totobjsel; int totlamp, totlampsel; - int tottri, totmesh; + int tottri; char infostr[MAX_INFO_LEN]; } SceneStats; +typedef struct SceneStatsFmt { + /* Totals */ + char totvert[MAX_INFO_NUM_LEN], totvertsel[MAX_INFO_NUM_LEN]; + char totface[MAX_INFO_NUM_LEN], totfacesel[MAX_INFO_NUM_LEN]; + char totedge[MAX_INFO_NUM_LEN], totedgesel[MAX_INFO_NUM_LEN]; + char totbone[MAX_INFO_NUM_LEN], totbonesel[MAX_INFO_NUM_LEN]; + char totobj[MAX_INFO_NUM_LEN], totobjsel[MAX_INFO_NUM_LEN]; + char totlamp[MAX_INFO_NUM_LEN], totlampsel[MAX_INFO_NUM_LEN]; + char tottri[MAX_INFO_NUM_LEN]; +} SceneStatsFmt; + static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) { switch (ob->type) { @@ -79,8 +91,6 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) DerivedMesh *dm = ob->derivedFinal; int totvert, totedge, totface, totloop; - stats->totmesh += totob; - if (dm) { totvert = dm->getNumVerts(dm); totedge = dm->getNumEdges(dm); @@ -367,6 +377,7 @@ static void stats_string(Scene *scene) { #define MAX_INFO_MEM_LEN 64 SceneStats *stats = scene->stats; + SceneStatsFmt stats_fmt; Object *ob = (scene->basact) ? scene->basact->object : NULL; uintptr_t mem_in_use, mmap_in_use; char memstr[MAX_INFO_MEM_LEN]; @@ -376,6 +387,34 @@ static void stats_string(Scene *scene) mem_in_use = MEM_get_memory_in_use(); mmap_in_use = MEM_get_mapped_memory_in_use(); + + /* Generate formatted numbers */ +#define SCENE_STATS_FMT_INT(_id) \ + BLI_str_format_int_grouped(stats_fmt._id, stats->_id) + + SCENE_STATS_FMT_INT(totvert); + SCENE_STATS_FMT_INT(totvertsel); + + SCENE_STATS_FMT_INT(totedge); + SCENE_STATS_FMT_INT(totedgesel); + + SCENE_STATS_FMT_INT(totface); + SCENE_STATS_FMT_INT(totfacesel); + + SCENE_STATS_FMT_INT(totbone); + SCENE_STATS_FMT_INT(totbonesel); + + SCENE_STATS_FMT_INT(totobj); + SCENE_STATS_FMT_INT(totobjsel); + + SCENE_STATS_FMT_INT(totlamp); + SCENE_STATS_FMT_INT(totlampsel); + + SCENE_STATS_FMT_INT(tottri); + +#undef SCENE_STATS_FMT_INT + + /* get memory statistics */ s = memstr; ofs += BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" | Mem:%.2fM"), @@ -394,32 +433,36 @@ static void stats_string(Scene *scene) if (scene->obedit->type == OB_MESH) { ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, - IFACE_("Verts:%d/%d | Edges:%d/%d | Faces:%d/%d | Tris:%d"), - stats->totvertsel, stats->totvert, stats->totedgesel, stats->totedge, - stats->totfacesel, stats->totface, stats->tottri); + IFACE_("Verts:%s/%s | Edges:%s/%s | Faces:%s/%s | Tris:%s"), + stats_fmt.totvertsel, stats_fmt.totvert, stats_fmt.totedgesel, stats_fmt.totedge, + stats_fmt.totfacesel, stats_fmt.totface, stats_fmt.tottri); } else if (scene->obedit->type == OB_ARMATURE) { - ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d/%d | Bones:%d/%d"), stats->totvertsel, - stats->totvert, stats->totbonesel, stats->totbone); + ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s/%s | Bones:%s/%s"), stats_fmt.totvertsel, + stats_fmt.totvert, stats_fmt.totbonesel, stats_fmt.totbone); } else { - ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d/%d"), stats->totvertsel, stats->totvert); + ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s/%s"), stats_fmt.totvertsel, + stats_fmt.totvert); } ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs); } else if (ob && (ob->mode & OB_MODE_POSE)) { - ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%d/%d %s"), - stats->totbonesel, stats->totbone, memstr); + ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%s/%s %s"), + stats_fmt.totbonesel, stats_fmt.totbone, memstr); } else if (stats_is_object_dynamic_topology_sculpt(ob)) { - ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d | Tris:%d"), stats->totvert, stats->tottri); + ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s | Tris:%s"), stats_fmt.totvert, + stats_fmt.tottri); } else { ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, - IFACE_("Verts:%d | Faces:%d | Tris:%d | Objects:%d/%d | Lamps:%d/%d%s"), stats->totvert, - stats->totface, stats->tottri, stats->totobjsel, stats->totobj, stats->totlampsel, - stats->totlamp, memstr); + IFACE_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s | Lamps:%s/%s%s"), + stats_fmt.totvert, stats_fmt.totface, + stats_fmt.tottri, stats_fmt.totobjsel, + stats_fmt.totobj, stats_fmt.totlampsel, + stats_fmt.totlamp, memstr); } if (ob) diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index 40ab4dcecca..4cbfce0f6e9 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -289,7 +289,7 @@ int textview_draw(TextViewContext *tvc, const int draw, int mval[2], void **mous 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; + cdc.console_width = (tvc->winx - (CONSOLE_DRAW_MARGIN * 2)) / cdc.cwidth; /* avoid divide by zero on small windows */ if (cdc.console_width < 1) cdc.console_width = 1; diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index b52d6265800..dd152022762 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -1144,15 +1144,30 @@ static void draw_sensor_message(uiLayout *layout, PointerRNA *ptr) uiItemR(layout, ptr, "subject", 0, NULL, ICON_NONE); } -static void draw_sensor_mouse(uiLayout *layout, PointerRNA *ptr) +static void draw_sensor_mouse(uiLayout *layout, PointerRNA *ptr, bContext *C) { - uiLayout *split; + uiLayout *split, *split2; + PointerRNA main_ptr; split = uiLayoutSplit(layout, 0.8f, false); uiItemR(split, ptr, "mouse_event", 0, NULL, ICON_NONE); - if (RNA_enum_get(ptr, "mouse_event") == BL_SENS_MOUSE_MOUSEOVER_ANY) + if (RNA_enum_get(ptr, "mouse_event") == BL_SENS_MOUSE_MOUSEOVER_ANY) { uiItemR(split, ptr, "use_pulse", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + + split = uiLayoutSplit(layout, 0.3f, false); + uiItemR(split, ptr, "use_material", 0, "", ICON_NONE); + + split2 = uiLayoutSplit(split, 0.7f, false); + if (RNA_enum_get(ptr, "use_material") == SENS_RAY_PROPERTY) { + uiItemR(split2, ptr, "property", 0, "", ICON_NONE); + } + else { + RNA_main_pointer_create(CTX_data_main(C), &main_ptr); + uiItemPointerR(split2, ptr, "material", &main_ptr, "materials", "", ICON_MATERIAL_DATA); + } + uiItemR(split2, ptr, "use_x_ray", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + } } static void draw_sensor_near(uiLayout *layout, PointerRNA *ptr) @@ -1273,7 +1288,7 @@ static void draw_brick_sensor(uiLayout *layout, PointerRNA *ptr, bContext *C) draw_sensor_message(box, ptr); break; case SENS_MOUSE: - draw_sensor_mouse(box, ptr); + draw_sensor_mouse(box, ptr, C); break; case SENS_NEAR: draw_sensor_near(box, ptr); @@ -1720,6 +1735,12 @@ static void draw_actuator_edit_object(uiLayout *layout, PointerRNA *ptr) sub = uiLayoutSplit(split, 0.7f, false); uiItemR(sub, ptr, "time", 0, NULL, ICON_NONE); uiItemR(sub, ptr, "use_3d_tracking", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + + row = uiLayoutRow(layout, false); + uiItemR(row, ptr, "up_axis", 0, NULL, ICON_NONE); + + row = uiLayoutRow(layout, false); + uiItemR(row, ptr, "track_axis", 0, NULL, ICON_NONE); break; case ACT_EDOB_DYNAMICS: if (ob->type != OB_MESH) { @@ -1811,7 +1832,7 @@ static void draw_actuator_motion(uiLayout *layout, PointerRNA *ptr) uiItemR(row, ptr, "offset_rotation", 0, NULL, ICON_NONE); uiItemR(split, ptr, "use_local_rotation", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); - if (ELEM3(physics_type, OB_BODY_TYPE_DYNAMIC, OB_BODY_TYPE_RIGID, OB_BODY_TYPE_SOFT)) { + if (ELEM(physics_type, OB_BODY_TYPE_DYNAMIC, OB_BODY_TYPE_RIGID, OB_BODY_TYPE_SOFT)) { uiItemL(layout, IFACE_("Dynamic Object Settings:"), ICON_NONE); split = uiLayoutSplit(layout, 0.9, false); row = uiLayoutRow(split, false); @@ -1933,6 +1954,7 @@ static void draw_actuator_property(uiLayout *layout, PointerRNA *ptr) switch (RNA_enum_get(ptr, "mode")) { case ACT_PROP_TOGGLE: + case ACT_PROP_LEVEL: break; case ACT_PROP_ADD: uiItemR(layout, ptr, "value", 0, NULL, ICON_NONE); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 73f95870329..86f9bc5d768 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -885,6 +885,11 @@ static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *pt } } +static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "use_tips", 0, NULL, 0); +} + static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRNA *ptr) { uiItemR(layout, ptr, "space", 0, "", 0); @@ -937,30 +942,23 @@ static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), static void node_shader_buts_subsurface(uiLayout *layout, bContext *C, PointerRNA *ptr) { - /* SSS does not work on GPU yet */ + /* SSS only enabled in Experimental Kernel */ 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 && U.compute_device_type != 0)) - uiItemL(layout, IFACE_("SSS not supported on GPU"), ICON_ERROR); + if (cscene.data && + ((U.compute_device_type != USER_COMPUTE_DEVICE_NONE) && + (RNA_enum_get(&cscene, "device") == 1) && + (RNA_enum_get(&cscene, "feature_set") == 0))) + { + uiItemL(layout, IFACE_("Only enabled in experimental GPU kernel"), ICON_ERROR); + } } uiItemR(layout, ptr, "falloff", 0, "", ICON_NONE); } -static void node_shader_buts_volume(uiLayout *layout, bContext *C, PointerRNA *UNUSED(ptr)) -{ - /* Volume 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 && U.compute_device_type != 0)) - uiItemL(layout, IFACE_("Volumes not supported on GPU"), ICON_ERROR); - } -} - static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "component", 0, "", ICON_NONE); @@ -1000,6 +998,16 @@ static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA #endif } +static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *row, *col; + + col = uiLayoutColumn(layout, false); + row = uiLayoutRow(col, true); + uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE); + uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE); +} + /* only once called */ static void node_shader_set_butfunc(bNodeType *ntype) { @@ -1107,12 +1115,6 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_SUBSURFACE_SCATTERING: ntype->draw_buttons = node_shader_buts_subsurface; break; - case SH_NODE_VOLUME_SCATTER: - ntype->draw_buttons = node_shader_buts_volume; - break; - case SH_NODE_VOLUME_ABSORPTION: - ntype->draw_buttons = node_shader_buts_volume; - break; case SH_NODE_BSDF_TOON: ntype->draw_buttons = node_shader_buts_toon; break; @@ -1126,6 +1128,12 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_UVMAP: ntype->draw_buttons = node_shader_buts_uvmap; break; + case SH_NODE_UVALONGSTROKE: + ntype->draw_buttons = node_shader_buts_uvalongstroke; + break; + case SH_NODE_OUTPUT_LINESTYLE: + ntype->draw_buttons = node_buts_output_linestyle; + break; } } @@ -2307,6 +2315,12 @@ static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout), bContext *UNU { } +static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "source", UI_ITEM_R_EXPAND, "", ICON_NONE); + uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE); +} + /* only once called */ static void node_composit_set_butfunc(bNodeType *ntype) { @@ -2531,6 +2545,9 @@ static void node_composit_set_butfunc(bNodeType *ntype) case CMP_NODE_CORNERPIN: ntype->draw_buttons = node_composit_buts_cornerpin; break; + case CMP_NODE_SUNBEAMS: + ntype->draw_buttons = node_composit_buts_sunbeams; + break; } } diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 2dea441c03d..52c1cefbfed 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -138,6 +138,10 @@ void ED_node_tag_update_id(ID *id) DAG_id_tag_update(id, 0); WM_main_add_notifier(NC_TEXTURE | ND_NODES, id); } + else if (id == &ntree->id) { + /* node groups */ + DAG_id_tag_update(id, 0); + } } void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree) diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 1c41ce9d86d..ca13d87d632 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -640,11 +640,11 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) /* tree specific activate calls */ if (ntree->type == NTREE_SHADER) { /* when we select a material, active texture is cleared, for buttons */ - if (node->id && ELEM3(GS(node->id->name), ID_MA, ID_LA, ID_WO)) + if (node->id && ELEM(GS(node->id->name), ID_MA, ID_LA, ID_WO)) nodeClearActiveID(ntree, ID_TE); - if (ELEM4(node->type, SH_NODE_OUTPUT, SH_NODE_OUTPUT_MATERIAL, - SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LAMP)) + if (ELEM(node->type, SH_NODE_OUTPUT, SH_NODE_OUTPUT_MATERIAL, + SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LAMP, SH_NODE_OUTPUT_LINESTYLE)) { bNode *tnode; diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index 39aba921f72..96cc7fb4407 100644 --- a/source/blender/editors/space_node/node_group.c +++ b/source/blender/editors/space_node/node_group.c @@ -200,7 +200,7 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode) * - ngroup (i.e. the source NodeTree) is left unscathed * - temp copy. don't change ID usercount */ - wgroup = ntreeCopyTree_ex(ngroup, false); + wgroup = ntreeCopyTree_ex(ngroup, G.main, false); /* Add the nodes into the ntree */ for (node = wgroup->nodes.first; node; node = nextnode) { diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index ddfbe3bebf2..9eaee60bfce 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -501,6 +501,12 @@ static void node_area_listener(bScreen *sc, ScrArea *sa, wmNotifier *wmn) } } break; + + case NC_LINESTYLE: + if (ED_node_is_shader(snode) && shader_type == SNODE_SHADER_LINESTYLE) { + ED_area_tag_refresh(sa); + } + break; } } @@ -740,6 +746,7 @@ static void node_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegi case NC_TEXTURE: case NC_WORLD: case NC_NODE: + case NC_LINESTYLE: ED_region_tag_redraw(ar); break; case NC_OBJECT: diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 5d6f4b9896c..0db7a90e313 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -638,7 +638,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiButSetFlag(bt, UI_BUT_DRAG_LOCK); layflag++; /* is lay_xor */ - if (ELEM8(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT, + if (ELEM(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT, SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT)) { bt = uiDefIconButBitI(block, TOG, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1, diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 17e1e032bbf..ef621407abd 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -215,15 +215,15 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot) static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, ReportList *reports) { /* can't rename rna datablocks entries or listbases */ - if (ELEM4(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE)) { + if (ELEM(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE)) { /* do nothing */; } - else if (ELEM10(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE, - TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_R_PASS)) + else if (ELEM(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE, + TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_R_PASS)) { BKE_report(reports, RPT_WARNING, "Cannot edit builtin name"); } - else if (ELEM3(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { + else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { BKE_report(reports, RPT_WARNING, "Cannot edit sequence name"); } else if (tselem->id->lib) { @@ -1654,7 +1654,7 @@ static int outliner_parenting_poll(bContext *C) SpaceOops *soops = CTX_wm_space_outliner(C); if (soops) { - return ELEM4(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS); + return ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS); } return false; diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index d7521edd57a..6f5bf712d55 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -948,7 +948,7 @@ static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Sp WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } - else if (ELEM5(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) { + else if (ELEM(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) { WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); } else { // rest of types diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index d1e9b3d34b7..d09ed1a100e 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -1339,7 +1339,7 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S else if (datalevel == TSE_DRIVER_BASE) { /* do nothing... no special ops needed yet */ } - else if (ELEM3(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) { + else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) { /*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/ } else { diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 520cd9a544d..5801dd126e3 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -821,7 +821,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i TreeStoreElem *tselem; ID *id = idv; - if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { + if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { id = ((PointerRNA *)idv)->id.data; if (!id) id = ((PointerRNA *)idv)->data; } @@ -847,10 +847,10 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i te->parent = parent; te->index = index; // for data arays - if (ELEM3(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { + if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { /* pass */ } - else if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { + else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { /* pass */ } else if (type == TSE_ANIM_DATA) { @@ -985,7 +985,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i te->directdata = seq; te->name = seq->strip->stripdata->name; } - else if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { + else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { PointerRNA pptr, propptr, *ptr = (PointerRNA *)idv; PropertyRNA *prop, *iterprop; PropertyType proptype; @@ -1062,7 +1062,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i else if (tot) te->flag |= TE_LAZY_CLOSED; } - else if (ELEM3(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { + else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { tot = RNA_property_array_length(ptr, prop); if (TSELEM_OPEN(tselem, soops)) { diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 41c5b00b381..504d9628d98 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -143,7 +143,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent * UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - if (!ELEM4(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS)) { + if (!ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS)) { return false; } @@ -156,7 +156,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent * switch (te->idcode) { case ID_SCE: - return (ELEM3(tselem->type, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)); + return (ELEM(tselem->type, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)); case ID_OB: return (ELEM(tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE)); /* Other codes to ignore? */ diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 0ab14a15b58..0dff2242b28 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -142,19 +142,21 @@ static void get_seq_color3ubv(Scene *curscene, Sequence *seq, unsigned char col[ case SEQ_TYPE_GLOW: case SEQ_TYPE_MULTICAM: case SEQ_TYPE_ADJUSTMENT: + case SEQ_TYPE_GAUSSIAN_BLUR: UI_GetThemeColor3ubv(TH_SEQ_EFFECT, col); /* slightly offset hue to distinguish different effects */ - if (seq->type == SEQ_TYPE_ADD) rgb_byte_set_hue_float_offset(col, 0.04); - else if (seq->type == SEQ_TYPE_SUB) rgb_byte_set_hue_float_offset(col, 0.08); - else if (seq->type == SEQ_TYPE_MUL) rgb_byte_set_hue_float_offset(col, 0.12); - else if (seq->type == SEQ_TYPE_ALPHAOVER) rgb_byte_set_hue_float_offset(col, 0.16); - else if (seq->type == SEQ_TYPE_ALPHAUNDER) rgb_byte_set_hue_float_offset(col, 0.20); - else if (seq->type == SEQ_TYPE_OVERDROP) rgb_byte_set_hue_float_offset(col, 0.24); - else if (seq->type == SEQ_TYPE_GLOW) rgb_byte_set_hue_float_offset(col, 0.28); - else if (seq->type == SEQ_TYPE_TRANSFORM) rgb_byte_set_hue_float_offset(col, 0.36); - else if (seq->type == SEQ_TYPE_MULTICAM) rgb_byte_set_hue_float_offset(col, 0.32); - else if (seq->type == SEQ_TYPE_ADJUSTMENT) rgb_byte_set_hue_float_offset(col, 0.40); + if (seq->type == SEQ_TYPE_ADD) rgb_byte_set_hue_float_offset(col, 0.04); + else if (seq->type == SEQ_TYPE_SUB) rgb_byte_set_hue_float_offset(col, 0.08); + else if (seq->type == SEQ_TYPE_MUL) rgb_byte_set_hue_float_offset(col, 0.12); + else if (seq->type == SEQ_TYPE_ALPHAOVER) rgb_byte_set_hue_float_offset(col, 0.16); + else if (seq->type == SEQ_TYPE_ALPHAUNDER) rgb_byte_set_hue_float_offset(col, 0.20); + else if (seq->type == SEQ_TYPE_OVERDROP) rgb_byte_set_hue_float_offset(col, 0.24); + else if (seq->type == SEQ_TYPE_GLOW) rgb_byte_set_hue_float_offset(col, 0.28); + else if (seq->type == SEQ_TYPE_TRANSFORM) rgb_byte_set_hue_float_offset(col, 0.36); + else if (seq->type == SEQ_TYPE_MULTICAM) rgb_byte_set_hue_float_offset(col, 0.32); + else if (seq->type == SEQ_TYPE_ADJUSTMENT) rgb_byte_set_hue_float_offset(col, 0.40); + else if (seq->type == SEQ_TYPE_GAUSSIAN_BLUR) rgb_byte_set_hue_float_offset(col, 0.42); break; case SEQ_TYPE_COLOR: diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 3c17b2986ff..9c43d22ae2f 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -86,6 +86,7 @@ EnumPropertyItem sequencer_prop_effect_types[] = { {SEQ_TYPE_SPEED, "SPEED", 0, "Speed", "Color effect strip type"}, {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""}, {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""}, + {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""}, {0, NULL, 0, NULL, NULL} }; @@ -1918,9 +1919,12 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) strip_new = seq_new->strip; strip_new->us = 1; - /* new stripdata */ - se_new = strip_new->stripdata; + /* new stripdata (only one element now!) */ + /* Note this assume all elements (images) have the same dimension, since we only copy the name here. */ + se_new = MEM_reallocN(strip_new->stripdata, sizeof(*se_new)); BLI_strncpy(se_new->name, se->name, sizeof(se_new->name)); + strip_new->stripdata = se_new; + BKE_sequence_calc(scene, seq_new); if (step > 1) { @@ -2055,8 +2059,8 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op) Sequence *seq, *seqm, *next, *last_seq = BKE_sequencer_active_get(scene); int channel_max = 1; - if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) { - BKE_report(op->reports, RPT_ERROR, "Please select all related strips"); + if (BKE_sequence_base_isolated_sel_check(ed->seqbasep, false) == false) { + BKE_report(op->reports, RPT_ERROR, "Please select more than one or all related strips"); return OPERATOR_CANCELLED; } @@ -2763,7 +2767,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) BKE_sequencer_free_clipboard(); - if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) { + if (BKE_sequence_base_isolated_sel_check(ed->seqbasep, true) == false) { BKE_report(op->reports, RPT_ERROR, "Please select all related strips"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 60fc300da1f..df266b0f546 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -165,6 +165,13 @@ enum { SEQ_UNSELECTED }; +enum { + SEQ_SELECT_LR_NONE = 0, + SEQ_SELECT_LR_MOUSE, + SEQ_SELECT_LR_LEFT, + SEQ_SELECT_LR_RIGHT +}; + /* defines used internally */ #define SCE_MARKERS 0 // XXX - dummy diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c index e69a02aa3df..c5e47c3aa3e 100644 --- a/source/blender/editors/space_sequencer/sequencer_ops.c +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -237,12 +237,12 @@ void sequencer_keymap(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); RNA_boolean_set(kmi->ptr, "extend", false); RNA_boolean_set(kmi->ptr, "linked_handle", false); - RNA_boolean_set(kmi->ptr, "left_right", false); + RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE); RNA_boolean_set(kmi->ptr, "linked_time", false); kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "extend", true); RNA_boolean_set(kmi->ptr, "linked_handle", false); - RNA_boolean_set(kmi->ptr, "left_right", false); + RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE); RNA_boolean_set(kmi->ptr, "linked_time", false); @@ -275,27 +275,27 @@ void sequencer_keymap(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "extend", false); RNA_boolean_set(kmi->ptr, "linked_handle", true); - RNA_boolean_set(kmi->ptr, "left_right", false); + RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE); RNA_boolean_set(kmi->ptr, "linked_time", false); kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0); RNA_boolean_set(kmi->ptr, "extend", true); RNA_boolean_set(kmi->ptr, "linked_handle", true); - RNA_boolean_set(kmi->ptr, "left_right", false); + RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE); RNA_boolean_set(kmi->ptr, "linked_time", false); /* match action editor */ kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "extend", false); RNA_boolean_set(kmi->ptr, "linked_handle", false); - RNA_boolean_set(kmi->ptr, "left_right", true); /* grr, these conflict - only use left_right if not over an active seq */ + RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_MOUSE); /* grr, these conflict - only use left_right if not over an active seq */ RNA_boolean_set(kmi->ptr, "linked_time", true); /* adjusted since 2.4 */ kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "extend", true); RNA_boolean_set(kmi->ptr, "linked_handle", false); - RNA_boolean_set(kmi->ptr, "left_right", false); + RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE); RNA_boolean_set(kmi->ptr, "linked_time", true); WM_keymap_add_item(keymap, "SEQUENCER_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index 9826ef10902..83a0de62329 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -314,7 +314,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e const bool extend = RNA_boolean_get(op->ptr, "extend"); const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle"); const bool linked_time = RNA_boolean_get(op->ptr, "linked_time"); - bool left_right = RNA_boolean_get(op->ptr, "left_right"); + int left_right = RNA_enum_get(op->ptr, "left_right"); Sequence *seq, *neighbor, *act_orig; int hand, sel_side; @@ -328,8 +328,8 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e seq = find_nearest_seq(scene, v2d, &hand, event->mval); // XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip - if (seq && linked_time && left_right) - left_right = false; + if (seq && linked_time && (left_right == SEQ_SELECT_LR_MOUSE)) + left_right = SEQ_SELECT_LR_NONE; if (marker) { @@ -348,12 +348,24 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e } } - else if (left_right) { + else if (left_right != SEQ_SELECT_LR_NONE) { /* use different logic for this */ float x; ED_sequencer_deselect_all(scene); - x = UI_view2d_region_to_view_x(v2d, event->mval[0]); - + + switch (left_right) { + case SEQ_SELECT_LR_MOUSE: + x = UI_view2d_region_to_view_x(v2d, event->mval[0]); + break; + + case SEQ_SELECT_LR_LEFT: + x = CFRA - 1; + break; + case SEQ_SELECT_LR_RIGHT: + x = CFRA + 1; + break; + } + SEQP_BEGIN (ed, seq) { if (x < CFRA) { @@ -522,6 +534,14 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e void SEQUENCER_OT_select(wmOperatorType *ot) { + static EnumPropertyItem sequencer_select_left_right_types[] = { + {SEQ_SELECT_LR_NONE, "NONE", 0, "None", "Don't do left-right selection"}, + {SEQ_SELECT_LR_MOUSE, "MOUSE", 0, "Mouse", "Use mouse position for selction"}, + {SEQ_SELECT_LR_LEFT, "LEFT", 0, "Left", "Select left"}, + {SEQ_SELECT_LR_RIGHT, "RIGHT", 0, "Select Right"}, + {0, NULL, 0, NULL, NULL} + }; + /* identifiers */ ot->name = "Activate/Select"; ot->idname = "SEQUENCER_OT_select"; @@ -538,7 +558,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); RNA_def_boolean(ot->srna, "linked_handle", 0, "Linked Handle", "Select handles next to the active strip"); /* for animation this is an enum but atm having an enum isn't useful for us */ - RNA_def_boolean(ot->srna, "left_right", 0, "Left/Right", "Select based on the current frame side the cursor is on"); + RNA_def_enum(ot->srna, "left_right", sequencer_select_left_right_types, 0, "Left/Right", "Select based on the current frame side the cursor is on"); RNA_def_boolean(ot->srna, "linked_time", 0, "Linked Time", "Select other strips at the same time"); } @@ -912,7 +932,7 @@ static EnumPropertyItem sequencer_prop_select_grouped_types[] = { #define SEQ_IS_EFFECT(_seq) ((_seq->type & SEQ_TYPE_EFFECT) != 0) -#define SEQ_USE_DATA(_seq) (ELEM3(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq)) +#define SEQ_USE_DATA(_seq) (ELEM(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq)) static bool select_grouped_type(Editing *ed, Sequence *actseq) { @@ -1035,7 +1055,7 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq) SEQP_BEGIN (ed, seq) { - if (ELEM3(actseq, seq->seq1, seq->seq2, seq->seq3)) { + if (ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) { effects[seq->type] = true; } } diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index a94b73802b2..c0cfaed7867 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -279,24 +279,40 @@ static void sequencer_refresh(const bContext *C, ScrArea *sa) } break; case SEQ_VIEW_SEQUENCE_PREVIEW: - 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; - } - if (ar_preview && (ar_preview->flag & RGN_FLAG_HIDDEN)) { - ar_preview->flag &= ~RGN_FLAG_HIDDEN; - ar_preview->v2d.flag &= ~V2D_IS_INITIALISED; - ar_preview->v2d.cur = ar_preview->v2d.tot; - view_changed = true; - } - if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) { - ar_main->alignment = RGN_ALIGN_NONE; - view_changed = true; - } - if (ar_preview && ar_preview->alignment != RGN_ALIGN_TOP) { - ar_preview->alignment = RGN_ALIGN_TOP; - view_changed = true; + if (ar_main && ar_preview) { + /* Get available height (without DPI correction). */ + const float height = (sa->winy - ED_area_headersize()) / UI_DPI_FAC; + + /* We reuse hidden area's size, allows to find same layout as before if we just switch + * between one 'full window' view and the combined one. This gets lost if we switch to both + * 'full window' views before, though... Better than nothing. */ + if (ar_main->flag & RGN_FLAG_HIDDEN) { + ar_main->flag &= ~RGN_FLAG_HIDDEN; + ar_main->v2d.flag &= ~V2D_IS_INITIALISED; + ar_preview->sizey = (int)(height - ar_main->sizey); + view_changed = true; + } + if (ar_preview->flag & RGN_FLAG_HIDDEN) { + ar_preview->flag &= ~RGN_FLAG_HIDDEN; + ar_preview->v2d.flag &= ~V2D_IS_INITIALISED; + ar_preview->v2d.cur = ar_preview->v2d.tot; + ar_main->sizey = (int)(height - ar_preview->sizey); + view_changed = true; + } + if (ar_main->alignment != RGN_ALIGN_NONE) { + ar_main->alignment = RGN_ALIGN_NONE; + view_changed = true; + } + if (ar_preview->alignment != RGN_ALIGN_TOP) { + ar_preview->alignment = RGN_ALIGN_TOP; + view_changed = true; + } + /* Final check that both preview and main height are reasonable! */ + if (ar_preview->sizey < 10 || ar_main->sizey < 10 || ar_preview->sizey + ar_main->sizey > height) { + ar_preview->sizey = (int)(height * 0.4f + 0.5f); + ar_main->sizey = (int)(height - ar_preview->sizey); + view_changed = true; + } } break; } @@ -339,40 +355,6 @@ static void sequencer_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn } } -/* *********************** sequencer (main) region ************************ */ -/* add handlers, stuff you only do once or on area/region changes */ -static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar) -{ - wmKeyMap *keymap; - ListBase *lb; - - UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); - -// keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0); -// WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - - keymap = WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0); - WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - - /* own keymap */ - keymap = WM_keymap_find(wm->defaultconf, "Sequencer", SPACE_SEQ, 0); - WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - - /* add drop boxes */ - lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); - - WM_event_add_dropbox_handler(&ar->handlers, lb); - -} - -static void sequencer_main_area_draw(const bContext *C, ARegion *ar) -{ -// ScrArea *sa = CTX_wm_area(C); - - /* NLE - strip editing timeline interface */ - draw_timeline_seq(C, ar); -} - /* ************* dropboxes ************* */ static int image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) @@ -396,7 +378,7 @@ static int movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) int hand; if (drag->type == WM_DRAG_PATH) - if (ELEM3(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */ + if (ELEM(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */ if (find_nearest_seq(scene, &ar->v2d, &hand, event->mval) == NULL) return 1; return 0; @@ -439,7 +421,7 @@ static void sequencer_drop_copy(wmDrag *drag, wmDropBox *drop) static void sequencer_dropboxes(void) { ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); - + WM_dropbox_add(lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy); WM_dropbox_add(lb, "SEQUENCER_OT_movie_strip_add", movie_drop_poll, sequencer_drop_copy); WM_dropbox_add(lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy); @@ -469,16 +451,37 @@ static int sequencer_context(const bContext *C, const char *member, bContextData return false; } - +/* *********************** sequencer (main) region ************************ */ /* add handlers, stuff you only do once or on area/region changes */ -static void sequencer_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar) { - ED_region_header_init(ar); + wmKeyMap *keymap; + ListBase *lb; + + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); + +#if 0 + keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); +#endif + + keymap = WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + + /* own keymap */ + keymap = WM_keymap_find(wm->defaultconf, "Sequencer", SPACE_SEQ, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + + /* add drop boxes */ + lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); + + WM_event_add_dropbox_handler(&ar->handlers, lb); } -static void sequencer_header_area_draw(const bContext *C, ARegion *ar) +static void sequencer_main_area_draw(const bContext *C, ARegion *ar) { - ED_region_header(C, ar); + /* NLE - strip editing timeline interface */ + draw_timeline_seq(C, ar); } static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) @@ -512,15 +515,29 @@ static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa } } +/* *********************** header region ************************ */ +/* add handlers, stuff you only do once or on area/region changes */ +static void sequencer_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +{ + ED_region_header_init(ar); +} + +static void sequencer_header_area_draw(const bContext *C, ARegion *ar) +{ + ED_region_header(C, ar); +} + /* *********************** preview region ************************ */ static void sequencer_preview_area_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); - -// keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0); -// WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + +#if 0 + keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); +#endif keymap = WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); @@ -593,7 +610,6 @@ static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED break; } break; - case NC_MASK: if (wmn->action == NA_EDITED) { ED_region_tag_redraw(ar); @@ -654,10 +670,10 @@ void ED_spacetype_sequencer(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype sequencer"); ARegionType *art; - + st->spaceid = SPACE_SEQ; strncpy(st->name, "Sequencer", BKE_ST_MAXNAME); - + st->new = sequencer_new; st->free = sequencer_free; st->init = sequencer_init; @@ -682,13 +698,12 @@ void ED_spacetype_sequencer(void) /* preview */ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); art->regionid = RGN_TYPE_PREVIEW; - art->prefsizey = 240; // XXX art->init = sequencer_preview_area_init; art->draw = sequencer_preview_area_draw; art->listener = sequencer_preview_area_listener; art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL; BLI_addhead(&st->regiontypes, art); - + /* regions: listview/buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); art->regionid = RGN_TYPE_UI; @@ -698,7 +713,7 @@ void ED_spacetype_sequencer(void) art->init = sequencer_buttons_area_init; art->draw = sequencer_buttons_area_draw; BLI_addhead(&st->regiontypes, art); - + sequencer_buttons_register(art); /* regions: header */ @@ -706,13 +721,13 @@ void ED_spacetype_sequencer(void) art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; - + art->init = sequencer_header_area_init; art->draw = sequencer_header_area_draw; art->listener = sequencer_main_area_listener; - + BLI_addhead(&st->regiontypes, art); - + BKE_spacetype_register(st); /* set the sequencer callback when not in background mode */ diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index fbca9bcc04f..1e710b88cad 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -462,10 +462,13 @@ static void text_cursor(wmWindow *win, ScrArea *sa, ARegion *ar) static int text_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { - if (drag->type == WM_DRAG_PATH) - if (ELEM(drag->icon, ICON_FILE_SCRIPT, ICON_FILE_BLANK)) /* rule might not work? */ - return 1; - return 0; + if (drag->type == WM_DRAG_PATH) { + /* rule might not work? */ + if (ELEM(drag->icon, ICON_FILE_SCRIPT, ICON_FILE_TEXT, ICON_FILE_BLANK)) { + return true; + } + } + return false; } static void text_drop_copy(wmDrag *drag, wmDropBox *drop) diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index c91c51ee5a9..480696760d4 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -397,7 +397,8 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w /* skip hidden part of line */ if (skip) { skip--; - fstart = fpos; mstart = mend; + fstart = fpos = end; + mstart = mend; mend = txt_utf8_forward_columns(str + mend, max, &padding) - str; end = (wrap += max - padding); continue; @@ -1459,7 +1460,7 @@ void text_scroll_to_cursor(SpaceText *st, ScrArea *sa) ARegion *ar = NULL; int i, x, winx = 0; - if (ELEM3(NULL, st, st->text, st->text->curl)) return; + if (ELEM(NULL, st, st->text, st->text->curl)) return; text = st->text; diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index fcd6fb3c179..2e3d8d056e8 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -1825,11 +1825,17 @@ static int text_move_cursor(bContext *C, int type, bool select) switch (type) { case LINE_BEGIN: + if (!select) { + txt_sel_clear(text); + } if (st && st->wordwrap && ar) txt_wrap_move_bol(st, ar, select); else txt_move_bol(text, select); break; case LINE_END: + if (!select) { + txt_sel_clear(text); + } if (st && st->wordwrap && ar) txt_wrap_move_eol(st, ar, select); else txt_move_eol(text, select); break; diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index 245cdadc7a2..dfa373f111f 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -67,6 +67,7 @@ #include "view3d_intern.h" +#include "GPU_select.h" /* *************** Armature Drawing - Coloring API ***************************** */ @@ -93,7 +94,7 @@ static void set_pchan_colorset(Object *ob, bPoseChannel *pchan) short color_index = 0; /* sanity check */ - if (ELEM4(NULL, ob, arm, pose, pchan)) { + if (ELEM(NULL, ob, arm, pose, pchan)) { bcolor = NULL; return; } @@ -466,10 +467,10 @@ static const unsigned int bone_octahedral_solid_tris[8][3] = { /* aligned with bone_octahedral_solid_tris */ static const float bone_octahedral_solid_normals[8][3] = { - { 0.70710683f, -0.70710683f, 0.00000000f}, - {-0.00000000f, -0.70710683f, -0.70710683f}, - {-0.70710683f, -0.70710683f, 0.00000000f}, - { 0.00000000f, -0.70710683f, 0.70710683f}, + { M_SQRT1_2, -M_SQRT1_2, 0.00000000f}, + {-0.00000000f, -M_SQRT1_2, -M_SQRT1_2}, + {-M_SQRT1_2, -M_SQRT1_2, 0.00000000f}, + { 0.00000000f, -M_SQRT1_2, M_SQRT1_2}, { 0.99388373f, 0.11043154f, -0.00000000f}, { 0.00000000f, 0.11043154f, -0.99388373f}, {-0.99388373f, 0.11043154f, 0.00000000f}, @@ -551,7 +552,7 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag, /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (id != -1) - glLoadName(id | BONESEL_ROOT); + GPU_select_load_id(id | BONESEL_ROOT); if (dt <= OB_WIRE) { if (armflag & ARM_EDITMODE) { @@ -574,7 +575,7 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag, /* Draw tip point */ if (id != -1) - glLoadName(id | BONESEL_TIP); + GPU_select_load_id(id | BONESEL_TIP); if (dt <= OB_WIRE) { if (armflag & ARM_EDITMODE) { @@ -787,7 +788,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4], /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (id != -1) - glLoadName(id | BONESEL_ROOT); + GPU_select_load_id(id | BONESEL_ROOT); drawcircball(GL_LINE_LOOP, headvec, head, imat); } @@ -799,7 +800,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4], } if (id != -1) - glLoadName(id | BONESEL_TIP); + GPU_select_load_id(id | BONESEL_TIP); drawcircball(GL_LINE_LOOP, tailvec, tail, imat); @@ -830,7 +831,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4], cross_v3_v3v3(norvect, vec, imat[2]); if (id != -1) - glLoadName(id | BONESEL_BONE); + GPU_select_load_id(id | BONESEL_BONE); glBegin(GL_LINES); @@ -907,7 +908,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (id != -1) - glLoadName(id | BONESEL_ROOT); + GPU_select_load_id(id | BONESEL_ROOT); gluSphere(qobj, head, 16, 10); } @@ -918,7 +919,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co } if (id != -1) - glLoadName(id | BONESEL_TIP); + GPU_select_load_id(id | BONESEL_TIP); glTranslatef(0.0f, 0.0f, length); gluSphere(qobj, tail, 16, 10); @@ -939,7 +940,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co if (length > (head + tail)) { if (id != -1) - glLoadName(id | BONESEL_BONE); + GPU_select_load_id(id | BONESEL_BONE); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-1.0f, -1.0f); @@ -1009,7 +1010,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (G.f & G_PICKSEL) { /* no bitmap in selection mode, crashes 3d cards... */ - glLoadName(id | BONESEL_ROOT); + GPU_select_load_id(id | BONESEL_ROOT); glBegin(GL_POINTS); glVertex3f(0.0f, 0.0f, 0.0f); glEnd(); @@ -1021,7 +1022,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned } if (id != -1) - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); glBegin(GL_LINES); glVertex3f(0.0f, 0.0f, 0.0f); @@ -1031,7 +1032,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned /* tip */ if (G.f & G_PICKSEL) { /* no bitmap in selection mode, crashes 3d cards... */ - glLoadName(id | BONESEL_TIP); + GPU_select_load_id(id | BONESEL_TIP); glBegin(GL_POINTS); glVertex3f(0.0f, 1.0f, 0.0f); glEnd(); @@ -1043,7 +1044,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned /* further we send no names */ if (id != -1) - glLoadName(id & 0xFFFF); /* object tag, for bordersel optim */ + GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */ if (armflag & ARM_POSEMODE) set_pchan_glColor(PCHAN_COLOR_LINEBONE, boneflag, constflag); @@ -1161,7 +1162,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl } if (id != -1) { - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); } /* set up solid drawing */ @@ -1266,13 +1267,13 @@ static void draw_wire_bone(const short dt, int armflag, int boneflag, short cons /* this chunk not in object mode */ if (armflag & (ARM_EDITMODE | ARM_POSEMODE)) { if (id != -1) - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); draw_wire_bone_segments(pchan, bbones, length, segments); /* further we send no names */ if (id != -1) - glLoadName(id & 0xFFFF); /* object tag, for bordersel optim */ + GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */ } /* colors for modes */ @@ -1315,7 +1316,7 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag /* now draw the bone itself */ if (id != -1) { - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); } /* wire? */ @@ -1370,7 +1371,7 @@ static void draw_custom_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obje } if (id != -1) { - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); } draw_object_instance(scene, v3d, rv3d, ob, dt, armflag & ARM_POSEMODE); @@ -1812,12 +1813,12 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, index += 0x10000; /* pose bones count in higher 2 bytes only */ } - /* very very confusing... but in object mode, solid draw, we cannot do glLoadName yet, + /* very very confusing... but in object mode, solid draw, we cannot do GPU_select_load_id yet, * stick bones and/or wire custom-shapes are drawn in next loop */ - if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && (draw_wire == false)) { + if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && (draw_wire == false) && index != -1) { /* object tag, for bordersel optim */ - glLoadName(index & 0xFFFF); + GPU_select_load_id(index & 0xFFFF); index = -1; } } @@ -1881,9 +1882,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, index += 0x10000; /* pose bones count in higher 2 bytes only */ } /* stick or wire bones have not been drawn yet so don't clear object selection in this case */ - if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && draw_wire) { + if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && draw_wire && index != -1) { /* object tag, for bordersel optim */ - glLoadName(index & 0xFFFF); + GPU_select_load_id(index & 0xFFFF); index = -1; } } @@ -1926,7 +1927,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, */ if ((do_dashed & 2) && ((bone->flag & BONE_CONNECTED) == 0)) { if (arm->flag & ARM_POSEMODE) { - glLoadName(index & 0xFFFF); /* object tag, for bordersel optim */ + GPU_select_load_id(index & 0xFFFF); /* object tag, for bordersel optim */ UI_ThemeColor(TH_WIRE); } setlinestyle(3); @@ -1946,7 +1947,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, if (constflag & PCHAN_HAS_TARGET) glColor3ub(200, 120, 0); else glColor3ub(200, 200, 50); /* add theme! */ - glLoadName(index & 0xFFFF); + GPU_select_load_id(index & 0xFFFF); pchan_draw_IK_root_lines(pchan, !(do_dashed & 2)); } } @@ -1954,7 +1955,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, if (bone->flag & BONE_SELECTED) { glColor3ub(150, 200, 50); /* add theme! */ - glLoadName(index & 0xFFFF); + GPU_select_load_id(index & 0xFFFF); pchan_draw_IK_root_lines(pchan, !(do_dashed & 2)); } } @@ -2020,7 +2021,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, /* draw DoFs */ if (arm->flag & ARM_POSEMODE) { - if (((base->flag & OB_FROMDUPLI) == 0)) { + if (((base->flag & OB_FROMDUPLI) == 0) && ((v3d->flag & V3D_HIDE_HELPLINES) == 0)) { draw_pose_dofs(ob); } } @@ -2174,7 +2175,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) /* if wire over solid, set offset */ index = -1; - glLoadName(-1); + GPU_select_load_id(-1); if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { if (G.f & G_PICKSEL) index = 0; @@ -2223,7 +2224,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) /* offset to parent */ if (eBone->parent) { UI_ThemeColor(TH_WIRE_EDIT); - glLoadName(-1); /* -1 here is OK! */ + GPU_select_load_id(-1); /* -1 here is OK! */ setlinestyle(3); glBegin(GL_LINES); @@ -2240,7 +2241,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) /* restore */ if (index != -1) { - glLoadName(-1); + GPU_select_load_id(-1); } if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index 75d0f86de57..1d54cb0cff9 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -211,12 +211,16 @@ static Material *give_current_material_or_def(Object *ob, int matnr) static struct TextureDrawState { Object *ob; + Image *stencil; /* texture painting stencil */ + Image *canvas; /* texture painting canvas, for image mode */ bool use_game_mat; int is_lit, is_tex; int color_profile; bool use_backface_culling; unsigned char obcol[4]; -} Gtexdraw = {NULL, false, 0, 0, 0, false, {0, 0, 0, 0}}; + bool is_texpaint; + bool texpaint_material; /* use material slots for texture painting */ +} Gtexdraw = {NULL, NULL, NULL, false, 0, 0, 0, false, {0, 0, 0, 0}, false, false}; static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *ma, struct TextureDrawState gtexdraw) { @@ -228,13 +232,15 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material * static int c_lit; static int c_has_texface; - Object *litob = NULL; /* to get mode to turn off mipmap in painting mode */ int backculled = 1; int alphablend = GPU_BLEND_SOLID; int textured = 0; int lit = 0; int has_texface = texface != NULL; bool need_set_tpage = false; + bool texpaint = ((gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) != 0); + + Image *ima = NULL; if (ma != NULL) { if (ma->mode & MA_TRANSP) { @@ -247,10 +253,10 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material * memset(&c_texface, 0, sizeof(MTFace)); c_badtex = false; c_has_texface = -1; + c_ma = NULL; } else { textured = gtexdraw.is_tex; - litob = gtexdraw.ob; } /* convert number of lights into boolean */ @@ -265,14 +271,19 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material * } } - if (texface) { + if (texface && !texpaint) { textured = textured && (texface->tpage); /* no material, render alpha if texture has depth=32 */ if (!ma && BKE_image_has_alpha(texface->tpage)) alphablend = GPU_BLEND_ALPHA; } - + else if (texpaint && ma) { + if (gtexdraw.texpaint_material) + ima = ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL; + else + ima = gtexdraw.canvas; + } else textured = 0; @@ -286,11 +297,43 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material * /* need to re-set tpage if textured flag changed or existsment of texface changed.. */ need_set_tpage = textured != c_textured || has_texface != c_has_texface; /* ..or if settings inside texface were changed (if texface was used) */ - need_set_tpage |= texface && memcmp(&c_texface, texface, sizeof(c_texface)); + need_set_tpage |= (texpaint && c_ma != ma) || (texface && memcmp(&c_texface, texface, sizeof(c_texface))); if (need_set_tpage) { if (textured) { - c_badtex = !GPU_set_tpage(texface, !(litob->mode & OB_MODE_TEXTURE_PAINT), alphablend); + if (texpaint) { + c_badtex = false; + if (GPU_verify_image(ima, NULL, 0, 1, 0, false)) { + glEnable(GL_TEXTURE_2D); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE); + + glActiveTexture(GL_TEXTURE1); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, ima->bindcode); + glActiveTexture(GL_TEXTURE0); + } + else { + glActiveTexture(GL_TEXTURE1); + glDisable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glActiveTexture(GL_TEXTURE0); + + c_badtex = true; + GPU_clear_tpage(true); + glDisable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } + else { + c_badtex = !GPU_set_tpage(texface, !texpaint, alphablend); + } } else { GPU_set_tpage(NULL, 0, 0); @@ -324,6 +367,7 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material * glDisable(GL_COLOR_MATERIAL); } c_lit = lit; + c_ma = ma; } return c_badtex; @@ -334,6 +378,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O unsigned char obcol[4]; bool is_tex, solidtex; Mesh *me = ob->data; + ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; /* XXX scene->obedit warning */ @@ -363,8 +408,52 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O else is_tex = false; Gtexdraw.ob = ob; + Gtexdraw.stencil = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? imapaint->stencil : NULL; + Gtexdraw.is_texpaint = (ob->mode == OB_MODE_TEXTURE_PAINT); + Gtexdraw.texpaint_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL); + Gtexdraw.canvas = (Gtexdraw.texpaint_material) ? NULL : imapaint->canvas; Gtexdraw.is_tex = is_tex; + /* naughty multitexturing hacks to quickly support stencil + shading + alpha blending + * in new texpaint code. The better solution here would be to support GLSL */ + if (Gtexdraw.is_texpaint) { + glActiveTexture(GL_TEXTURE1); + glEnable(GL_TEXTURE_2D); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); + + /* load the stencil texture here */ + if (Gtexdraw.stencil != NULL) { + glActiveTexture(GL_TEXTURE2); + if (GPU_verify_image(Gtexdraw.stencil, NULL, false, false, false, false)) { + float col[4] = {imapaint->stencil_col[0], imapaint->stencil_col[1], imapaint->stencil_col[2], 1.0f}; + glEnable(GL_TEXTURE_2D); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE); + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, col); + if ((imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) == 0) { + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_ONE_MINUS_SRC_COLOR); + } + else { + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); + } + } + } + glActiveTexture(GL_TEXTURE0); + } + Gtexdraw.color_profile = BKE_scene_check_color_management_enabled(scene); Gtexdraw.use_game_mat = (RE_engines_find(scene->r.engine)->flag & RE_GAME) != 0; Gtexdraw.use_backface_culling = (v3d->flag2 & V3D_BACKFACE_CULLING) != 0; @@ -378,8 +467,31 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O static void draw_textured_end(void) { - /* switch off textures */ - GPU_set_tpage(NULL, 0, 0); + if (Gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) { + glActiveTexture(GL_TEXTURE1); + glDisable(GL_TEXTURE_2D); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBindTexture(GL_TEXTURE_2D, 0); + + if (Gtexdraw.stencil != NULL) { + glActiveTexture(GL_TEXTURE2); + glDisable(GL_TEXTURE_2D); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBindTexture(GL_TEXTURE_2D, 0); + } + glActiveTexture(GL_TEXTURE0); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + /* manual reset, since we don't use tpage */ + glBindTexture(GL_TEXTURE_2D, 0); + /* force switch off textures */ + GPU_clear_tpage(true); + } + else { + /* switch off textures */ + GPU_set_tpage(NULL, 0, 0); + } glShadeModel(GL_FLAT); glDisable(GL_CULL_FACE); @@ -455,7 +567,7 @@ static DMDrawOption draw_tface__set_draw(MTFace *tface, const bool UNUSED(has_mc if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return 0; - if (tface) + if (tface || Gtexdraw.is_texpaint) set_draw_settings_cached(0, tface, ma, Gtexdraw); /* always use color from mcol, as set in update_tface_color_layer */ @@ -769,7 +881,8 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d Object *ob, DerivedMesh *dm, const int draw_flags) { Mesh *me = ob->data; - + DMDrawFlag uvflag = DM_DRAW_USE_ACTIVE_UV; + /* correct for negative scale */ if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW); else glFrontFace(GL_CCW); @@ -779,6 +892,10 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + if (ob->mode & OB_MODE_TEXTURE_PAINT) { + uvflag = DM_DRAW_USE_TEXPAINT_UV; + } + if (ob->mode & OB_MODE_EDIT) { drawEMTFMapped_userData data; @@ -788,7 +905,7 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d data.mf = DM_get_tessface_data_layer(dm, CD_MFACE); data.tf = DM_get_tessface_data_layer(dm, CD_MTFACE); - dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data); + dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data, 0); } else if (draw_flags & DRAW_FACE_SELECT) { if (ob->mode & OB_MODE_WEIGHT_PAINT) @@ -800,15 +917,15 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d userData.mf = DM_get_tessface_data_layer(dm, CD_MFACE); userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE); userData.me = me; - dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions, &userData); + dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions, &userData, uvflag); } } else { if (GPU_buffer_legacy(dm)) { if (draw_flags & DRAW_MODIFIERS_PREVIEW) - dm->drawFacesTex(dm, draw_mcol__set_draw_legacy, NULL, NULL); + dm->drawFacesTex(dm, draw_mcol__set_draw_legacy, NULL, NULL, uvflag); else - dm->drawFacesTex(dm, draw_tface__set_draw_legacy, NULL, NULL); + dm->drawFacesTex(dm, draw_tface__set_draw_legacy, NULL, NULL, uvflag); } else { drawTFace_userData userData; @@ -819,7 +936,7 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE); userData.me = NULL; - dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData); + dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData, uvflag); } } @@ -866,7 +983,7 @@ static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs) int texture_set = 0; /* draw image texture if we find one */ - if (ED_object_get_active_image(data->ob, mat_nr, &ima, &iuser, &node)) { + if (ED_object_get_active_image(data->ob, mat_nr, &ima, &iuser, &node, NULL)) { /* get openl texture */ int mipmap = 1; int bindcode = (ima) ? GPU_verify_image(ima, iuser, 0, 0, mipmap, false) : 0; @@ -951,7 +1068,8 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, /* if not cycles, or preview-modifiers, or drawing matcaps */ if ((draw_flags & DRAW_MODIFIERS_PREVIEW) || (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) || - (BKE_scene_use_new_shading_nodes(scene) == false)) + (BKE_scene_use_new_shading_nodes(scene) == false) || + ((ob->mode & OB_MODE_TEXTURE_PAINT) && ELEM(v3d->drawtype, OB_TEXTURE, OB_SOLID))) { draw_mesh_textured_old(scene, v3d, rv3d, ob, dm, draw_flags); return; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index e51ce652b53..5694f388780 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -86,6 +86,7 @@ #include "GPU_draw.h" #include "GPU_extensions.h" +#include "GPU_select.h" #include "ED_mesh.h" #include "ED_particle.h" @@ -109,7 +110,7 @@ * * Ideally we don't want to evaluate objects from drawing, * but it'll require some major sequencer re-design. So - * for now just fallback to legacy behaior with calling + * for now just fallback to legacy behavior with calling * display ist creating from draw(). */ #define SEQUENCER_DAG_WORKAROUND @@ -301,7 +302,7 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt) if (BKE_scene_use_new_shading_nodes(scene)) return false; - return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID); + return ((scene->gm.matmode == GAME_MAT_GLSL) || (v3d->drawtype == OB_MATERIAL)) && (dt > OB_SOLID); } static bool check_alpha_pass(Base *base) @@ -1585,7 +1586,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D continue; if (dflag & DRAW_PICKING) - glLoadName(base->selcol + (tracknr << 16)); + GPU_select_load_id(base->selcol + (tracknr << 16)); glPushMatrix(); glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); @@ -1736,7 +1737,7 @@ static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, } if (dflag & DRAW_PICKING) - glLoadName(base->selcol); + GPU_select_load_id(base->selcol); } /* flag similar to draw_object() */ @@ -3609,7 +3610,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, draw_dm_vert_normals(em, scene, ob, cageDM); } if (me->drawflag & ME_DRAW_LNORMALS) { - UI_ThemeColor(TH_VNORMAL); + UI_ThemeColor(TH_LNORMAL); draw_dm_loop_normals(em, scene, ob, cageDM); } @@ -4867,7 +4868,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv normalize_v3(imat[1]); } - if (ELEM3(draw_as, PART_DRAW_DOT, PART_DRAW_CROSS, PART_DRAW_LINE) && + if (ELEM(draw_as, PART_DRAW_DOT, PART_DRAW_CROSS, PART_DRAW_LINE) && (part->draw_col > PART_DRAW_COL_MAT)) { create_cdata = 1; @@ -5879,7 +5880,7 @@ static void editnurb_draw_active_nurbs(Nurb *nu) glLineWidth(1); } -static void draw_editnurb(Object *ob, Nurb *nurb, int sel) +static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel) { Nurb *nu; BPoint *bp, *bp1; @@ -5995,8 +5996,9 @@ static void draw_editnurb(Object *ob, Nurb *nurb, int sel) } } -static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, Nurb *nurb, - const char dt, const short dflag, const unsigned char ob_wire_col[4]) +static void draw_editnurb( + Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, Nurb *nurb, + const char dt, const short dflag, const unsigned char ob_wire_col[4]) { ToolSettings *ts = scene->toolsettings; Object *ob = base->object; @@ -6014,6 +6016,11 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col); + /* for shadows only show solid faces */ + if (v3d->flag2 & V3D_RENDER_SHADOW) { + return; + } + if (v3d->zbuf) glDepthFunc(GL_ALWAYS); /* first non-selected and active handles */ @@ -6026,8 +6033,8 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, } index++; } - draw_editnurb(ob, nurb, 0); - draw_editnurb(ob, nurb, 1); + draw_editnurb_splines(ob, nurb, false); + draw_editnurb_splines(ob, nurb, true); /* selected handles */ for (nu = nurb; nu; nu = nu->next) { if (nu->type == CU_BEZIER && (cu->drawflag & CU_HIDE_HANDLES) == 0) @@ -6037,11 +6044,11 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, if (v3d->zbuf) glDepthFunc(GL_LEQUAL); + glColor3ubv(wire_col); + /* direction vectors for 3d curve paths * when at its lowest, don't render normals */ if ((cu->flag & CU_3D) && (ts->normalsize > 0.0015f) && (cu->drawflag & CU_HIDE_NORMALS) == 0) { - - UI_ThemeColor(TH_WIRE_EDIT); for (bl = ob->curve_cache->bev.first, nu = nurb; nu && bl; bl = bl->next, nu = nu->next) { BevPoint *bevp = bl->bevpoints; int nr = bl->nr; @@ -6478,7 +6485,7 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, if (G.f & G_PICKSEL) { ml->selcol1 = code; - glLoadName(code++); + GPU_select_load_id(code++); } } drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad, imat); @@ -6492,7 +6499,7 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, if (G.f & G_PICKSEL) { ml->selcol2 = code; - glLoadName(code++); + GPU_select_load_id(code++); } drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad * atanf(ml->s) / (float)M_PI_2, imat); } @@ -6698,28 +6705,6 @@ static void draw_box(float vec[8][3]) glEnd(); } -/* uses boundbox, function used by Ketsji */ -#if 0 -static void get_local_bounds(Object *ob, float center[3], float size[3]) -{ - BoundBox *bb = BKE_object_boundbox_get(ob); - - if (bb == NULL) { - zero_v3(center); - copy_v3_v3(size, ob->size); - } - else { - size[0] = 0.5 * fabsf(bb->vec[0][0] - bb->vec[4][0]); - size[1] = 0.5 * fabsf(bb->vec[0][1] - bb->vec[2][1]); - size[2] = 0.5 * fabsf(bb->vec[0][2] - bb->vec[1][2]); - - center[0] = (bb->vec[0][0] + bb->vec[4][0]) / 2.0; - center[1] = (bb->vec[0][1] + bb->vec[2][1]) / 2.0; - center[2] = (bb->vec[0][2] + bb->vec[1][2]) / 2.0; - } -} -#endif - static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin) { float size[3], cent[3]; @@ -6727,17 +6712,13 @@ static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin) gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - size[0] = 0.5f * fabsf(bb->vec[0][0] - bb->vec[4][0]); - size[1] = 0.5f * fabsf(bb->vec[0][1] - bb->vec[2][1]); - size[2] = 0.5f * fabsf(bb->vec[0][2] - bb->vec[1][2]); + BKE_boundbox_calc_size_aabb(bb, size); if (around_origin) { zero_v3(cent); } else { - cent[0] = 0.5f * (bb->vec[0][0] + bb->vec[4][0]); - cent[1] = 0.5f * (bb->vec[0][1] + bb->vec[2][1]); - cent[2] = 0.5f * (bb->vec[0][2] + bb->vec[1][2]); + BKE_boundbox_calc_center_aabb(bb, cent); } glPushMatrix(); @@ -6781,7 +6762,7 @@ static void draw_bounding_volume(Object *ob, char type) if (ob->type == OB_MESH) { bb = BKE_mesh_boundbox_get(ob); } - else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { bb = BKE_curve_boundbox_get(ob); } else if (ob->type == OB_MBALL) { @@ -6806,9 +6787,7 @@ static void draw_bounding_volume(Object *ob, char type) if (type == OB_BOUND_BOX) { float vec[8][3], size[3]; - size[0] = 0.5f * fabsf(bb->vec[0][0] - bb->vec[4][0]); - size[1] = 0.5f * fabsf(bb->vec[0][1] - bb->vec[2][1]); - size[2] = 0.5f * fabsf(bb->vec[0][2] - bb->vec[1][2]); + BKE_boundbox_calc_size_aabb(bb, size); vec[0][0] = vec[1][0] = vec[2][0] = vec[3][0] = -size[0]; vec[4][0] = vec[5][0] = vec[6][0] = vec[7][0] = +size[0]; @@ -6838,7 +6817,7 @@ static void drawtexspace(Object *ob) if (ob->type == OB_MESH) { BKE_mesh_texspace_get(ob->data, loc, NULL, size); } - else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { BKE_curve_texspace_get(ob->data, loc, NULL, size); } else if (ob->type == OB_MBALL) { @@ -6876,7 +6855,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); glDepthMask(0); - if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { DerivedMesh *dm = ob->derivedFinal; bool has_faces = false; @@ -6920,7 +6899,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const unsigned char ob_wire_col[4]) { - if (ELEM4(ob->type, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL)) { + if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL)) { if (scene->obedit == ob) { UI_ThemeColor(TH_WIRE_EDIT); @@ -6932,7 +6911,7 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const ED_view3d_polygon_offset(rv3d, 1.0); glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ - if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { if (ED_view3d_boundbox_clip(rv3d, ob->bb)) { if (ob->derivedFinal) { @@ -7123,9 +7102,7 @@ static void draw_rigidbody_shape(Object *ob) switch (ob->rigidbody_object->shape) { case RB_SHAPE_BOX: - size[0] = 0.5f * fabsf(bb->vec[0][0] - bb->vec[4][0]); - size[1] = 0.5f * fabsf(bb->vec[0][1] - bb->vec[2][1]); - size[2] = 0.5f * fabsf(bb->vec[0][2] - bb->vec[1][2]); + BKE_boundbox_calc_size_aabb(bb, size); vec[0][0] = vec[1][0] = vec[2][0] = vec[3][0] = -size[0]; vec[4][0] = vec[5][0] = vec[6][0] = vec[7][0] = +size[0]; @@ -7170,23 +7147,23 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short const bool is_obact = (ob == OBACT); const bool render_override = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0; const bool is_picking = (G.f & G_PICKSEL) != 0; - bool skip_object = false; + const bool has_particles = (ob->particlesystem.first != NULL); bool particle_skip_object = false; /* Draw particles but not their emitter object. */ if (ob != scene->obedit) { if (ob->restrictflag & OB_RESTRICT_VIEW) - skip_object = true; + return; if (render_override) { if (ob->restrictflag & OB_RESTRICT_RENDER) - skip_object = true; + return; - if (ob->transflag & OB_DUPLI) - skip_object = true; /* note: can be reset by particle "draw emitter" below */ + if (!has_particles && (ob->transflag & (OB_DUPLI & ~OB_DUPLIFRAMES))) + return; } } - if (ob->particlesystem.first) { + if (has_particles) { /* XXX particles are not safe for simultaneous threaded render */ if (G.is_rendering) { return; @@ -7199,7 +7176,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short for (psys = ob->particlesystem.first; psys; psys = psys->next) { /* Once we have found a psys which renders its emitter object, we are done. */ if (psys->part->draw & PART_DRAW_EMITTER) { - skip_object = false; particle_skip_object = false; break; } @@ -7207,9 +7183,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short } } - if (skip_object) - return; - /* xray delay? */ if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) { /* don't do xray in particle mode, need the z-buffer */ @@ -7354,7 +7327,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short if (cu->editnurb) { ListBase *nurbs = BKE_curve_editNurbs_get(cu); - drawnurb(scene, v3d, rv3d, base, nurbs->first, dt, dflag, ob_wire_col); + draw_editnurb(scene, v3d, rv3d, base, nurbs->first, dt, dflag, ob_wire_col); } else if (dt == OB_BOUNDBOX) { if ((render_override && (v3d->drawtype >= OB_WIRE)) == 0) { diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 7a4634bf01a..8b76ec3a56d 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -43,7 +43,9 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_depsgraph.h" #include "BKE_icons.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_scene.h" @@ -285,7 +287,7 @@ static void view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar) } } -void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa) +void ED_view3d_shade_update(Main *bmain, Scene *scene, View3D *v3d, ScrArea *sa) { wmWindowManager *wm = bmain->wm.first; @@ -297,6 +299,10 @@ void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa) view3d_stop_render_preview(wm, ar); } } + else if (scene->obedit != NULL && scene->obedit->type == OB_MESH) { + /* Tag mesh to load edit data. */ + DAG_id_tag_update(scene->obedit->data, 0); + } } /* ******************** default callbacks for view3d space ***************** */ @@ -389,7 +395,16 @@ static SpaceLink *view3d_new(const bContext *C) static void view3d_free(SpaceLink *sl) { View3D *vd = (View3D *) sl; + BGpic *bgpic; + for (bgpic = vd->bgpicbase.first; bgpic; bgpic = bgpic->next) { + if (bgpic->source == V3D_BGPIC_IMAGE) { + id_us_min((ID *)bgpic->ima); + } + else if (bgpic->source == V3D_BGPIC_MOVIE) { + id_us_min((ID *)bgpic->clip); + } + } BLI_freelistN(&vd->bgpicbase); if (vd->localvd) MEM_freeN(vd->localvd); @@ -416,6 +431,7 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl) { View3D *v3do = (View3D *)sl; View3D *v3dn = MEM_dupallocN(sl); + BGpic *bgpic; /* clear or remove stuff from old */ @@ -433,8 +449,16 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl) /* copy or clear inside new stuff */ v3dn->defmaterial = NULL; - + BLI_duplicatelist(&v3dn->bgpicbase, &v3do->bgpicbase); + for (bgpic = v3dn->bgpicbase.first; bgpic; bgpic = bgpic->next) { + if (bgpic->source == V3D_BGPIC_IMAGE) { + id_us_plus((ID *)bgpic->ima); + } + else if (bgpic->source == V3D_BGPIC_MOVIE) { + id_us_plus((ID *)bgpic->clip); + } + } v3dn->properties_storage = NULL; @@ -464,6 +488,12 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar) keymap = WM_keymap_find(wm->defaultconf, "Object Mode", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); + keymap = WM_keymap_find(wm->defaultconf, "Paint Curve", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap = WM_keymap_find(wm->defaultconf, "Curve", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + keymap = WM_keymap_find(wm->defaultconf, "Image Paint", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); @@ -654,7 +684,7 @@ static void view3d_dropboxes(void) WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_mesh_drop_poll, view3d_id_path_drop_copy); WM_dropbox_add(lb, "OBJECT_OT_drop_named_image", view3d_ima_empty_drop_poll, view3d_id_path_drop_copy); WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll, view3d_id_path_drop_copy); - WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy); + WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy); } @@ -760,7 +790,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN break; case ND_NLA: case ND_KEYFRAME: - if (ELEM3(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) + if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) ED_region_tag_redraw(ar); break; case ND_ANIMCHAN: @@ -841,14 +871,18 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN switch (wmn->data) { case ND_SHADING: case ND_NODES: + { + Object *ob = OBACT; if ((v3d->drawtype == OB_MATERIAL) || + (ob && (ob->mode == OB_MODE_TEXTURE_PAINT)) || (v3d->drawtype == OB_TEXTURE && - (scene->gm.matmode == GAME_MAT_GLSL || - BKE_scene_use_new_shading_nodes(scene)))) + (scene->gm.matmode == GAME_MAT_GLSL || + BKE_scene_use_new_shading_nodes(scene)))) { ED_region_tag_redraw(ar); } break; + } case ND_SHADING_DRAW: case ND_SHADING_LINKS: ED_region_tag_redraw(ar); @@ -886,7 +920,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN ED_region_tag_redraw(ar); break; case NC_MOVIECLIP: - if (wmn->data == ND_DISPLAY) + if (wmn->data == ND_DISPLAY || wmn->action == NA_EDITED) ED_region_tag_redraw(ar); break; case NC_SPACE: @@ -1011,7 +1045,7 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa break; case ND_NLA: case ND_KEYFRAME: - if (ELEM3(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) + if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) ED_region_tag_redraw(ar); break; } @@ -1080,6 +1114,11 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa if (wmn->data == ND_DATA || wmn->action == NA_EDITED) ED_region_tag_redraw(ar); break; + case NC_IMAGE: + /* Update for the image layers in texture paint. */ + if (wmn->action == NA_EDITED) + ED_region_tag_redraw(ar); + break; } } diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c index e96db2b220f..ee0f3da18b4 100644 --- a/source/blender/editors/space_view3d/view3d_camera_control.c +++ b/source/blender/editors/space_view3d/view3d_camera_control.c @@ -31,9 +31,9 @@ * * Typical view-control usage: * - * - aquire a view-control (#ED_view3d_control_aquire). + * - acquire a view-control (#ED_view3d_control_acquire). * - modify ``rv3d->ofs``, ``rv3d->viewquat``. - * - update the view data (#ED_view3d_control_aquire) - within a loop which draws the viewport. + * - update the view data (#ED_view3d_control_acquire) - within a loop which draws the viewport. * - finish and release the view-control (#ED_view3d_control_release), * either keeping the current view or restoring the initial view. * @@ -138,7 +138,7 @@ Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl) * Creates a #View3DControl handle and sets up * the view for first-person style navigation. */ -struct View3DCameraControl *ED_view3d_cameracontrol_aquire( +struct View3DCameraControl *ED_view3d_cameracontrol_acquire( Scene *scene, View3D *v3d, RegionView3D *rv3d, const bool use_parent_root) { @@ -282,7 +282,7 @@ void ED_view3d_cameracontrol_update( * Release view control. * * \param restore Sets the view state to the values that were set - * before #ED_view3d_control_aquire was called. + * before #ED_view3d_control_acquire was called. */ void ED_view3d_cameracontrol_release( View3DCameraControl *vctrl, diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 03808a82041..be3aaa13818 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -878,7 +878,7 @@ static void draw_selected_name(Scene *scene, Object *ob, rcti *rect) } } } - else if (ELEM3(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) { + else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) { Key *key = NULL; KeyBlock *kb = NULL; @@ -1283,6 +1283,12 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d) { /* do nothing */ } + /* texture paint mode sampling */ + else if (base && (base->object->mode & OB_MODE_TEXTURE_PAINT) && + (v3d->drawtype > OB_WIRE)) + { + /* do nothing */ + } else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) && v3d->drawtype > OB_WIRE && (v3d->flag & V3D_ZBUF_SELECT)) { @@ -1976,6 +1982,7 @@ static void draw_dupli_objects_color( DupliApplyData *apply_data; if (base->object->restrictflag & OB_RESTRICT_VIEW) return; + if ((base->object->restrictflag & OB_RESTRICT_RENDER) && (v3d->flag2 & V3D_RENDER_OVERRIDE)) return; if (dflag & DRAW_CONSTCOLOR) { BLI_assert(color == TH_UNDEFINED); @@ -2503,7 +2510,7 @@ CustomDataMask ED_view3d_datamask(Scene *scene, View3D *v3d) mask |= CD_MASK_ORCO; } else { - if (scene->gm.matmode == GAME_MAT_GLSL) + if (scene->gm.matmode == GAME_MAT_GLSL || v3d->drawtype == OB_MATERIAL) mask |= CD_MASK_ORCO; } } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index e3260dba485..db675b09896 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -78,6 +78,7 @@ #include "ED_view3d.h" #include "ED_sculpt.h" +#include "UI_resources.h" #include "PIL_time.h" /* smoothview */ @@ -307,12 +308,12 @@ static void view3d_boxview_clip(ScrArea *sa) } for (val = 0; val < 8; val++) { - if (ELEM4(val, 0, 3, 4, 7)) + if (ELEM(val, 0, 3, 4, 7)) bb->vec[val][0] = -x1 - ofs[0]; else bb->vec[val][0] = x1 - ofs[0]; - if (ELEM4(val, 0, 1, 4, 5)) + if (ELEM(val, 0, 1, 4, 5)) bb->vec[val][1] = -y1 - ofs[1]; else bb->vec[val][1] = y1 - ofs[1]; @@ -465,11 +466,13 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip) * properties are always being edited, weak */ viewlock = rv3d->viewlock; - if ((viewlock & RV3D_LOCKED) == 0) + if ((viewlock & RV3D_LOCKED) == 0) { + do_clip = (viewlock & RV3D_BOXCLIP) != 0; viewlock = 0; - else if ((viewlock & RV3D_BOXVIEW) == 0) { - viewlock &= ~RV3D_BOXCLIP; + } + else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) { do_clip = true; + viewlock &= ~RV3D_BOXCLIP; } for (; ar; ar = ar->prev) { @@ -648,6 +651,39 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) is_set = true; } + else if (ob == NULL || ob->mode == OB_MODE_OBJECT) { + /* object mode use boundbox centers */ + View3D *v3d = CTX_wm_view3d(C); + Base *base; + unsigned int tot = 0; + float select_center[3]; + + zero_v3(select_center); + for (base = FIRSTBASE; base; base = base->next) { + if (TESTBASE(v3d, base)) { + /* use the boundbox if we can */ + Object *ob = base->object; + + if (ob->bb && !(ob->bb->flag & BOUNDBOX_DIRTY)) { + float cent[3]; + + BKE_boundbox_calc_center_aabb(ob->bb, cent); + + mul_m4_v3(ob->obmat, cent); + add_v3_v3(select_center, cent); + } + else { + add_v3_v3(select_center, ob->obmat[3]); + } + tot++; + } + } + if (tot) { + mul_v3_fl(select_center, 1.0f / (float)tot); + copy_v3_v3(lastofs, select_center); + is_set = true; + } + } else { /* If there's no selection, lastofs is unmodified and last value since static */ is_set = calculateTransformCenter(C, V3D_CENTROID, lastofs, NULL); @@ -1136,7 +1172,7 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event) * * shared with NDOF. */ -static void view3d_ensure_persp(struct View3D *v3d, ARegion *ar) +static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar) { RegionView3D *rv3d = ar->regiondata; const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0; @@ -1144,7 +1180,7 @@ static void view3d_ensure_persp(struct View3D *v3d, ARegion *ar) BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0); if (ED_view3d_camera_lock_check(v3d, rv3d)) - return; + return false; if (rv3d->persp != RV3D_PERSP) { if (rv3d->persp == RV3D_CAMOB) { @@ -1155,7 +1191,10 @@ static void view3d_ensure_persp(struct View3D *v3d, ARegion *ar) else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) { rv3d->persp = RV3D_PERSP; } + return true; } + + return false; } static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -1174,8 +1213,14 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event) } /* switch from camera view when: */ - view3d_ensure_persp(vod->v3d, vod->ar); - + if (view3d_ensure_persp(vod->v3d, vod->ar)) { + /* If we're switching from camera view to the perspective one, + * need to tag viewport update, so camera vuew and borders + * are properly updated. + */ + ED_region_tag_redraw(vod->ar); + } + if (event->type == MOUSEPAN) { /* Rotate direction we keep always same */ if (U.uiflag2 & USER_TRACKPAD_NATURAL) @@ -2070,9 +2115,12 @@ static void viewzoom_apply(ViewOpsData *vod, const int xy[2], const short viewzo { float zfac = 1.0; bool use_cam_zoom; + float dist_range[2]; use_cam_zoom = (vod->rv3d->persp == RV3D_CAMOB) && !(vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)); + ED_view3d_dist_range_get(vod->v3d, dist_range); + if (use_cam_zoom) { float delta; delta = (xy[0] - vod->origx + xy[1] - vod->origy) / 10.0f; @@ -2139,16 +2187,19 @@ static void viewzoom_apply(ViewOpsData *vod, const int xy[2], const short viewzo } if (!use_cam_zoom) { - if (zfac != 1.0f && zfac * vod->rv3d->dist > 0.001f * vod->grid && - zfac * vod->rv3d->dist < 10.0f * vod->far) - { - view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy); + if (zfac != 1.0f) { + const float zfac_min = dist_range[0] / vod->rv3d->dist; + const float zfac_max = dist_range[1] / vod->rv3d->dist; + CLAMP(zfac, zfac_min, zfac_max); + + if (zfac != 1.0f) { + view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy); + } } } /* these limits were in old code too */ - if (vod->rv3d->dist < 0.001f * vod->grid) vod->rv3d->dist = 0.001f * vod->grid; - if (vod->rv3d->dist > 10.0f * vod->far) vod->rv3d->dist = 10.0f * vod->far; + CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]); if (vod->rv3d->viewlock & RV3D_BOXVIEW) view3d_boxview_sync(vod->sa, vod->ar); @@ -2212,6 +2263,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) ScrArea *sa; ARegion *ar; bool use_cam_zoom; + float dist_range[2]; const int delta = RNA_int_get(op->ptr, "delta"); int mx, my; @@ -2235,13 +2287,15 @@ static int viewzoom_exec(bContext *C, wmOperator *op) use_cam_zoom = (rv3d->persp == RV3D_CAMOB) && !(rv3d->is_persp && ED_view3d_camera_lock_check(v3d, rv3d)); + ED_view3d_dist_range_get(v3d, dist_range); + if (delta < 0) { /* this min and max is also in viewmove() */ if (use_cam_zoom) { rv3d->camzoom -= 10.0f; if (rv3d->camzoom < RV3D_CAMZOOM_MIN) rv3d->camzoom = RV3D_CAMZOOM_MIN; } - else if (rv3d->dist < 10.0f * v3d->far) { + else if (rv3d->dist < dist_range[1]) { view_zoom_mouseloc(ar, 1.2f, mx, my); } } @@ -2250,7 +2304,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) rv3d->camzoom += 10.0f; if (rv3d->camzoom > RV3D_CAMZOOM_MAX) rv3d->camzoom = RV3D_CAMZOOM_MAX; } - else if (rv3d->dist > 0.001f * v3d->grid) { + else if (rv3d->dist > dist_range[0]) { view_zoom_mouseloc(ar, 0.83333f, mx, my); } } @@ -2363,6 +2417,8 @@ static void viewzoom_cancel(bContext *C, wmOperator *op) void VIEW3D_OT_zoom(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Zoom View"; ot->description = "Zoom in/out in the view"; @@ -2379,8 +2435,10 @@ void VIEW3D_OT_zoom(wmOperatorType *ot) ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER; RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); - RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX); - RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX); + prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); } @@ -3243,6 +3301,8 @@ static int render_border_exec(bContext *C, wmOperator *op) void VIEW3D_OT_render_border(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Set Render Border"; ot->description = "Set the boundaries of the border render and enable border render"; @@ -3262,7 +3322,8 @@ void VIEW3D_OT_render_border(wmOperatorType *ot) /* rna */ WM_operator_properties_border(ot); - RNA_def_boolean(ot->srna, "camera_only", 0, "Camera Only", "Set render border for camera view and final render only"); + prop = RNA_def_boolean(ot->srna, "camera_only", 0, "Camera Only", "Set render border for camera view and final render only"); + RNA_def_property_flag(prop, PROP_HIDDEN); } /* ********************* Clear render border operator ****************** */ @@ -3326,7 +3387,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) /* Zooms in on a border drawn by the user */ rcti rect; float dvec[3], vb[2], xscale, yscale; - float dist_range_min; + float dist_range[2]; /* SMOOTHVIEW */ float new_dist; @@ -3346,6 +3407,8 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) /* check if zooming in/out view */ gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); + ED_view3d_dist_range_get(v3d, dist_range); + /* Get Z Depths, needed for perspective, nice for ortho */ bgl_get_mats(&mats); ED_view3d_draw_depth(scene, ar, v3d, true); @@ -3394,8 +3457,9 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) new_ofs[2] = -p[2]; new_dist = len_v3(dvec); - dist_range_min = v3d->near * 1.5f; + /* ignore dist_range min */ + dist_range[0] = v3d->near * 1.5f; } else { /* othographic */ /* find the current window width and height */ @@ -3437,9 +3501,6 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) xscale = (BLI_rcti_size_x(&rect) / vb[0]); yscale = (BLI_rcti_size_y(&rect) / vb[1]); new_dist *= max_ff(xscale, yscale); - - /* zoom in as required, or as far as we can go */ - dist_range_min = 0.001f * v3d->grid; } if (gesture_mode == GESTURE_MODAL_OUT) { @@ -3449,9 +3510,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) } /* clamp after because we may have been zooming out */ - if (new_dist < dist_range_min) { - new_dist = dist_range_min; - } + CLAMP(new_dist, dist_range[0], dist_range[1]); ED_view3d_smooth_view(C, v3d, ar, NULL, NULL, new_ofs, NULL, &new_dist, NULL, @@ -3545,13 +3604,13 @@ void VIEW3D_OT_zoom_camera_1_to_1(wmOperatorType *ot) /* ********************* Changing view operator ****************** */ static EnumPropertyItem prop_view_items[] = { + {RV3D_VIEW_LEFT, "LEFT", ICON_TRIA_LEFT, "Left", "View From the Left"}, + {RV3D_VIEW_RIGHT, "RIGHT", ICON_TRIA_RIGHT, "Right", "View From the Right"}, + {RV3D_VIEW_BOTTOM, "BOTTOM", ICON_TRIA_DOWN, "Bottom", "View From the Bottom"}, + {RV3D_VIEW_TOP, "TOP", ICON_TRIA_UP, "Top", "View From the Top"}, {RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"}, {RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"}, - {RV3D_VIEW_LEFT, "LEFT", 0, "Left", "View From the Left"}, - {RV3D_VIEW_RIGHT, "RIGHT", 0, "Right", "View From the Right"}, - {RV3D_VIEW_TOP, "TOP", 0, "Top", "View From the Top"}, - {RV3D_VIEW_BOTTOM, "BOTTOM", 0, "Bottom", "View From the Bottom"}, - {RV3D_VIEW_CAMERA, "CAMERA", 0, "Camera", "View From the Active Camera"}, + {RV3D_VIEW_CAMERA, "CAMERA", ICON_CAMERA_DATA, "Camera", "View From the Active Camera"}, {0, NULL, 0, NULL, NULL} }; @@ -4435,7 +4494,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) } } -static void view3d_cursor3d_update(bContext *C, const int *mval) +void ED_view3d_cursor3d_update(bContext *C, const int mval[2]) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -4449,32 +4508,11 @@ static void view3d_cursor3d_update(bContext *C, const int *mval) WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene); } -static int view3d_cursor3d_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - view3d_cursor3d_update(C, event->mval); - op->customdata = SET_INT_IN_POINTER(event->type); - WM_event_add_modal_handler(C, op); + ED_view3d_cursor3d_update(C, event->mval); - return OPERATOR_RUNNING_MODAL; -} - -static int view3d_cursor3d_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - int event_type = GET_INT_FROM_POINTER(op->customdata); - - if (event->type == event_type) { - return OPERATOR_FINISHED; - } - - switch (event->type) { - case MOUSEMOVE: - view3d_cursor3d_update(C, event->mval); - break; - case LEFTMOUSE: - return OPERATOR_FINISHED; - } - - return OPERATOR_RUNNING_MODAL; + return OPERATOR_FINISHED; } void VIEW3D_OT_cursor3d(wmOperatorType *ot) @@ -4487,7 +4525,6 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot) /* api callbacks */ ot->invoke = view3d_cursor3d_invoke; - ot->modal = view3d_cursor3d_modal; ot->poll = ED_operator_view3d_active; diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index 6afe0ef896f..da77c4f75f7 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -385,7 +385,7 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent fly->zlock = FLY_AXISLOCK_STATE_IDLE; } - fly->v3d_camera_control = ED_view3d_cameracontrol_aquire( + fly->v3d_camera_control = ED_view3d_cameracontrol_acquire( fly->scene, fly->v3d, fly->rv3d, (U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0); diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index e3d0e87066b..a88724a1cdd 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -32,6 +32,7 @@ #include <stdio.h> #include <stdlib.h> +#include "DNA_brush_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" @@ -45,6 +46,7 @@ #include "BKE_depsgraph.h" #include "BKE_main.h" #include "BKE_modifier.h" +#include "BKE_paint.h" #include "BKE_screen.h" #include "BKE_editmesh.h" @@ -308,7 +310,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) /* mode */ if (ob) { modeselect = ob->mode; - is_paint = ELEM4(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT); + is_paint = ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT); } else { modeselect = OB_MODE_OBJECT; @@ -336,8 +338,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); if (obedit == NULL && is_paint) { - - if (ob->mode & OB_MODE_WEIGHT_PAINT) { + if (ob->mode & OB_MODE_ALL_PAINT) { /* Only for Weight Paint. makes no sense in other paint modes. */ row = uiLayoutRow(layout, true); uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 169bc494e1b..84ac4f7d02d 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -233,7 +233,7 @@ void VIEW3D_OT_properties(struct wmOperatorType *ot); void view3d_buttons_register(struct ARegionType *art); /* view3d_camera_control.c */ -struct View3DCameraControl *ED_view3d_cameracontrol_aquire( +struct View3DCameraControl *ED_view3d_cameracontrol_acquire( Scene *scene, View3D *v3d, RegionView3D *rv3d, const bool use_parent_root); void ED_view3d_cameracontrol_update( @@ -285,7 +285,7 @@ void draw_smoke_heat(struct SmokeDomainSettings *domain, struct Object *ob); /* workaround for trivial but noticeable camera bug caused by imprecision * between view border calculation in 2D/3D space, workaround for bug [#28037]. - * without this deifne we get the old behavior which is to try and align them + * without this define we get the old behavior which is to try and align them * both which _mostly_ works fine, but when the camera moves beyond ~1000 in * any direction it starts to fail */ #define VIEW3D_CAMERA_BORDER_HACK diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index c1e42c97c4d..75c1d9dcd22 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -277,7 +277,7 @@ eV3DProjStatus ED_view3d_project_float_object(const ARegion *ar, const float co[ * *************************************************** */ /** - * Caculate a depth value from \a co, use with #ED_view3d_win_to_delta + * Calculate a depth value from \a co, use with #ED_view3d_win_to_delta */ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_flip) { diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 32f063d6154..46ea52054c5 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1147,11 +1147,12 @@ static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int } { + wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_select_menu", false); PointerRNA ptr; - WM_operator_properties_create(&ptr, "VIEW3D_OT_select_menu"); + WM_operator_properties_create_ptr(&ptr, ot); RNA_boolean_set(&ptr, "toggle", toggle); - WM_operator_name_call(C, "VIEW3D_OT_select_menu", WM_OP_INVOKE_DEFAULT, &ptr); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); WM_operator_properties_free(&ptr); } @@ -1193,15 +1194,32 @@ static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, c /* we want a select buffer with bones, if there are... */ /* so check three selection levels and compare */ -static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2]) +static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2], bool *p_do_nearest, bool enumerate) { rcti rect; int offs; short hits15, hits9 = 0, hits5 = 0; bool has_bones15 = false, has_bones9 = false, has_bones5 = false; - + static int last_mval[2] = {-100, -100}; + bool do_nearest = false; + View3D *v3d = vc->v3d; + + /* define if we use solid nearest select or not */ + if (v3d->drawtype > OB_WIRE) { + do_nearest = true; + if (len_manhattan_v2v2_int(mval, last_mval) < 3) { + do_nearest = false; + } + } + copy_v2_v2_int(last_mval, mval); + + if (p_do_nearest) + *p_do_nearest = do_nearest; + + do_nearest = do_nearest && !enumerate; + BLI_rcti_init(&rect, mval[0] - 14, mval[0] + 14, mval[1] - 14, mval[1] + 14); - hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); + hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, do_nearest); if (hits15 == 1) { return selectbuffer_ret_hits_15(buffer, hits15); } @@ -1210,7 +1228,7 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff offs = 4 * hits15; BLI_rcti_init(&rect, mval[0] - 9, mval[0] + 9, mval[1] - 9, mval[1] + 9); - hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect); + hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest); if (hits9 == 1) { return selectbuffer_ret_hits_9(buffer, hits15, hits9); } @@ -1219,7 +1237,7 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff offs += 4 * hits9; BLI_rcti_init(&rect, mval[0] - 5, mval[0] + 5, mval[1] - 5, mval[1] + 5); - hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect); + hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest); if (hits5 == 1) { return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); } @@ -1241,25 +1259,13 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff } /* returns basact */ -static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], - Base *startbase, bool has_bones) +static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, + Base *startbase, bool has_bones, bool do_nearest) { Scene *scene = vc->scene; View3D *v3d = vc->v3d; Base *base, *basact = NULL; - static int lastmval[2] = {-100, -100}; int a; - bool do_nearest = false; - - /* define if we use solid nearest select or not */ - if (v3d->drawtype > OB_WIRE) { - do_nearest = true; - if (ABS(mval[0] - lastmval[0]) < 3 && ABS(mval[1] - lastmval[1]) < 3) { - if (!has_bones) /* hrms, if theres bones we always do nearest */ - do_nearest = false; - } - } - lastmval[0] = mval[0]; lastmval[1] = mval[1]; if (do_nearest) { unsigned int min = 0xFFFFFFFF; @@ -1342,16 +1348,17 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) Base *basact = NULL; unsigned int buffer[4 * MAXPICKBUF]; int hits; + bool do_nearest; /* setup view context for argument to callbacks */ view3d_operator_needs_opengl(C); view3d_set_viewcontext(C, &vc); - hits = mixed_bones_object_selectbuffer(&vc, buffer, mval); + hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, false); if (hits > 0) { const bool has_bones = selectbuffer_has_bones(buffer, hits); - basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, vc.scene->base.first, has_bones); + basact = mouse_select_eval_buffer(&vc, buffer, hits, vc.scene->base.first, has_bones, do_nearest); } return basact; @@ -1438,10 +1445,11 @@ static bool mouse_select(bContext *C, const int mval[2], } else { unsigned int buffer[4 * MAXPICKBUF]; + bool do_nearest; /* if objects have posemode set, the bones are in the same selection buffer */ - hits = mixed_bones_object_selectbuffer(&vc, buffer, mval); + hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, enumerate); if (hits > 0) { /* note: bundles are handling in the same way as bones */ @@ -1452,7 +1460,7 @@ static bool mouse_select(bContext *C, const int mval[2], basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, toggle); } else { - basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, has_bones); + basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest); } if (has_bones && basact) { @@ -1510,7 +1518,7 @@ static bool mouse_select(bContext *C, const int mval[2], if (!changed) { /* fallback to regular object selection if no new bundles were selected, * allows to select object parented to reconstruction object */ - basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, 0); + basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest); } } } @@ -1872,7 +1880,7 @@ static int do_meta_box_select(ViewContext *vc, rcti *rect, bool select, bool ext unsigned int buffer[4 * MAXPICKBUF]; short hits; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect); + hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false); if (extend == false && select) BKE_mball_deselect_all(mb); @@ -1906,7 +1914,7 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool unsigned int buffer[4 * MAXPICKBUF]; short hits; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect); + hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false); /* clear flag we use to detect point was affected */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) @@ -2000,7 +2008,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b /* selection buffer now has bones potentially too, so we add MAXPICKBUF */ vbuffer = MEM_mallocN(4 * (totobj + MAXPICKBUF) * sizeof(unsigned int), "selection buffer"); - hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKBUF), rect); + hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKBUF), rect, false); /* * LOGIC NOTES (theeth): * The buffer and ListBase have the same relative order, which makes the selection diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 716f4b10fae..7d3f7ce282e 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -56,6 +56,7 @@ #include "BIF_glutil.h" #include "GPU_draw.h" +#include "GPU_select.h" #include "WM_api.h" #include "WM_types.h" @@ -273,7 +274,7 @@ void ED_view3d_smooth_view_ex( rv3d->rflag |= RV3D_NAVIGATING; /* not essential but in some cases the caller will tag the area for redraw, - * and in that case we can get a ficker of the 'org' user view but we want to see 'src' */ + * and in that case we can get a flicker of the 'org' user view but we want to see 'src' */ view3d_smooth_view_state_restore(&sms.src, v3d, rv3d); /* keep track of running timer! */ @@ -723,6 +724,13 @@ void ED_view3d_depth_tag_update(RegionView3D *rv3d) rv3d->depths->damaged = true; } +void ED_view3d_dist_range_get(struct View3D *v3d, + float r_dist_range[2]) +{ + r_dist_range[0] = v3d->grid * 0.001f; + r_dist_range[1] = v3d->far * 10.0f; +} + /* copies logic of get_view3d_viewplane(), keep in sync */ bool ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *r_clipsta, float *r_clipend, const bool use_ortho_factor) @@ -955,6 +963,78 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d) } } +static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar, bool use_obedit_skip) +{ + short code = 1; + char dt; + short dtx; + + if (vc->obedit && vc->obedit->type == OB_MBALL) { + draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); + } + else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) { + /* if not drawing sketch, draw bones */ + if (!BDR_drawSketchNames(vc)) { + draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); + } + } + else { + Base *base; + + v3d->xray = true; /* otherwise it postpones drawing */ + for (base = scene->base.first; base; base = base->next) { + if (base->lay & v3d->lay) { + + if ((base->object->restrictflag & OB_RESTRICT_SELECT) || + (use_obedit_skip && (scene->obedit->data == base->object->data))) + { + base->selcol = 0; + } + else { + base->selcol = code; + + if (GPU_select_load_id(code)) { + draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR); + + /* we draw duplicators for selection too */ + if ((base->object->transflag & OB_DUPLI)) { + ListBase *lb; + DupliObject *dob; + Base tbase; + + tbase.flag = OB_FROMDUPLI; + lb = object_duplilist(G.main->eval_ctx, scene, base->object); + + for (dob = lb->first; dob; dob = dob->next) { + float omat[4][4]; + + tbase.object = dob->ob; + copy_m4_m4(omat, dob->ob->obmat); + copy_m4_m4(dob->ob->obmat, dob->mat); + + /* extra service: draw the duplicator in drawtype of parent */ + /* MIN2 for the drawtype to allow bounding box objects in groups for lods */ + dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); + dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx; + + draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR); + + tbase.object->dt = dt; + tbase.object->dtx = dtx; + + copy_m4_m4(dob->ob->obmat, omat); + } + free_object_duplilist(lb); + } + } + code++; + } + } + } + v3d->xray = false; /* restore */ + } +} + /** * \warning be sure to account for a negative return value * This is an error, "Too many objects in select buffer" @@ -962,17 +1042,16 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d) * * \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection. */ -short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input) +short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, bool do_nearest) { Scene *scene = vc->scene; View3D *v3d = vc->v3d; ARegion *ar = vc->ar; - rctf rect; - short code, hits; - char dt; - short dtx; + rctf rect, selrect; + short hits; const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL); - + const bool do_passes = do_nearest && GPU_select_query_check_active(); + G.f |= G_PICKSEL; /* case not a border select */ @@ -985,6 +1064,8 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b else { BLI_rctf_rcti_copy(&rect, input); } + + selrect = rect; view3d_winmatrix_set(ar, v3d, &rect); mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat); @@ -997,78 +1078,24 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b if (vc->rv3d->rflag & RV3D_CLIPPING) ED_view3d_clipping_set(vc->rv3d); - glSelectBuffer(bufsize, (GLuint *)buffer); - glRenderMode(GL_SELECT); - glInitNames(); /* these two calls whatfor? It doesnt work otherwise */ - glPushName(-1); - code = 1; + if (do_passes) + GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0); + else + GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_ALL, 0); + + view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip); + + hits = GPU_select_end(); - if (vc->obedit && vc->obedit->type == OB_MBALL) { - draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); - } - else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) { - /* if not drawing sketch, draw bones */ - if (!BDR_drawSketchNames(vc)) { - draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); - } - } - else { - Base *base; - - v3d->xray = true; /* otherwise it postpones drawing */ - for (base = scene->base.first; base; base = base->next) { - if (base->lay & v3d->lay) { - - if ((base->object->restrictflag & OB_RESTRICT_SELECT) || - (use_obedit_skip && (scene->obedit->data == base->object->data))) - { - base->selcol = 0; - } - else { - base->selcol = code; - glLoadName(code); - draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR); - - /* we draw duplicators for selection too */ - if ((base->object->transflag & OB_DUPLI)) { - ListBase *lb; - DupliObject *dob; - Base tbase; - - tbase.flag = OB_FROMDUPLI; - lb = object_duplilist(G.main->eval_ctx, scene, base->object); - - for (dob = lb->first; dob; dob = dob->next) { - float omat[4][4]; - - tbase.object = dob->ob; - copy_m4_m4(omat, dob->ob->obmat); - copy_m4_m4(dob->ob->obmat, dob->mat); - - /* extra service: draw the duplicator in drawtype of parent */ - /* MIN2 for the drawtype to allow bounding box objects in groups for lods */ - dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); - dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx; - - draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR); - - tbase.object->dt = dt; - tbase.object->dtx = dtx; - - copy_m4_m4(dob->ob->obmat, omat); - } - free_object_duplilist(lb); - } - code++; - } - } - } - v3d->xray = false; /* restore */ + /* second pass, to get the closest object to camera */ + if (do_passes) { + GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits); + + view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip); + + GPU_select_end(); } - - glPopName(); /* see above (pushname) */ - hits = glRenderMode(GL_RENDER); - + G.f &= ~G_PICKSEL; view3d_winmatrix_set(ar, v3d, NULL); mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat); @@ -1285,7 +1312,7 @@ static bool view3d_localview_init( return ok; } -static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmain, ScrArea *sa, const int smooth_viewtx) +static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx) { const bool free = true; ARegion *ar; @@ -1335,7 +1362,7 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai } } - ED_view3d_shade_update(bmain, v3d, sa); + ED_view3d_shade_update(bmain, scene, v3d, sa); } } } @@ -1352,7 +1379,7 @@ static bool view3d_localview_exit( locallay = v3d->lay & 0xFF000000; - restore_localviewdata(wm, win, bmain, sa, smooth_viewtx); + restore_localviewdata(wm, win, bmain, scene, sa, smooth_viewtx); /* for when in other window the layers have changed */ if (v3d->scenelock) v3d->lay = scene->lay; diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 1c3e223f3ed..7bdf39d6768 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -60,10 +60,8 @@ #include "view3d_intern.h" /* own include */ -#define EARTH_GRAVITY 9.80668f /* m/s2 */ - /* prototypes */ -static float getVelocityZeroTime(float velocity); +static float getVelocityZeroTime(const float gravity, const float velocity); /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ enum { @@ -280,7 +278,8 @@ typedef struct WalkInfo { bool is_reversed; /* gravity system */ - eWalkGravityState gravity; + eWalkGravityState gravity_state; + float gravity; /* height to use in walk mode */ float view_height; @@ -360,11 +359,11 @@ static void walk_navigation_mode_set(bContext *C, WalkInfo *walk, eWalkMethod mo { if (mode == WALK_MODE_FREE) { walk->navigation_mode = WALK_MODE_FREE; - walk->gravity = WALK_GRAVITY_STATE_OFF; + walk->gravity_state = WALK_GRAVITY_STATE_OFF; } else { /* WALK_MODE_GRAVITY */ walk->navigation_mode = WALK_MODE_GRAVITY; - walk->gravity = WALK_GRAVITY_STATE_START; + walk->gravity_state = WALK_GRAVITY_STATE_START; } walk_update_header(C, walk); @@ -510,7 +509,14 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->speed = U.walk_navigation.walk_speed; walk->speed_factor = U.walk_navigation.walk_speed_factor; - walk->gravity = WALK_GRAVITY_STATE_OFF; + walk->gravity_state = WALK_GRAVITY_STATE_OFF; + + if ((walk->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)) { + walk->gravity = fabsf(walk->scene->physics_settings.gravity[2]); + } + else { + walk->gravity = 9.80668f; /* m/s2 */ + } walk->is_reversed = ((U.walk_navigation.flag & USER_WALK_MOUSE_REVERSE) != 0); @@ -532,7 +538,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->rv3d->rflag |= RV3D_NAVIGATING; - walk->v3d_camera_control = ED_view3d_cameracontrol_aquire( + walk->v3d_camera_control = ED_view3d_cameracontrol_acquire( walk->scene, walk->v3d, walk->rv3d, (U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0); @@ -755,10 +761,10 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const #define JUMP_SPEED_MIN 1.0f #define JUMP_TIME_MAX 0.2f /* s */ -#define JUMP_SPEED_MAX sqrtf(2.0f * EARTH_GRAVITY * walk->jump_height) +#define JUMP_SPEED_MAX sqrtf(2.0f * walk->gravity * walk->jump_height) case WALK_MODAL_JUMP_STOP: - if (walk->gravity == WALK_GRAVITY_STATE_JUMP) { + if (walk->gravity_state == WALK_GRAVITY_STATE_JUMP) { float t; /* delta time */ @@ -769,21 +775,21 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const walk->speed_jump = JUMP_SPEED_MIN + t * (JUMP_SPEED_MAX - JUMP_SPEED_MIN) / JUMP_TIME_MAX; /* when jumping, duration is how long it takes before we start going down */ - walk->teleport.duration = getVelocityZeroTime(walk->speed_jump); + walk->teleport.duration = getVelocityZeroTime(walk->gravity, walk->speed_jump); /* no more increase of jump speed */ - walk->gravity = WALK_GRAVITY_STATE_ON; + walk->gravity_state = WALK_GRAVITY_STATE_ON; } break; case WALK_MODAL_JUMP: if ((walk->navigation_mode == WALK_MODE_GRAVITY) && - (walk->gravity == WALK_GRAVITY_STATE_OFF) && + (walk->gravity_state == WALK_GRAVITY_STATE_OFF) && (walk->teleport.state == WALK_TELEPORT_STATE_OFF)) { /* no need to check for ground, * walk->gravity wouldn't be off * if we were over a hole */ - walk->gravity = WALK_GRAVITY_STATE_JUMP; + walk->gravity_state = WALK_GRAVITY_STATE_JUMP; walk->speed_jump = JUMP_SPEED_MAX; walk->teleport.initial_time = PIL_check_seconds_timer(); @@ -793,7 +799,7 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const copy_v2_v2(walk->teleport.direction, walk->dvec_prev); /* when jumping, duration is how long it takes before we start going down */ - walk->teleport.duration = getVelocityZeroTime(walk->speed_jump); + walk->teleport.duration = getVelocityZeroTime(walk->gravity, walk->speed_jump); } break; @@ -853,14 +859,14 @@ static void walkMoveCamera(bContext *C, WalkInfo *walk, ED_view3d_cameracontrol_update(walk->v3d_camera_control, true, C, do_rotate, do_translate); } -static float getFreeFallDistance(const float time) +static float getFreeFallDistance(const float gravity, const float time) { - return EARTH_GRAVITY * (time * time) * 0.5f; + return gravity * (time * time) * 0.5f; } -static float getVelocityZeroTime(float velocity) +static float getVelocityZeroTime(const float gravity, const float velocity) { - return velocity / EARTH_GRAVITY; + return velocity / gravity; } static int walkApply(bContext *C, WalkInfo *walk) @@ -910,7 +916,7 @@ static int walkApply(bContext *C, WalkInfo *walk) if ((walk->active_directions) || moffset[0] || moffset[1] || walk->teleport.state == WALK_TELEPORT_STATE_ON || - walk->gravity != WALK_GRAVITY_STATE_OFF) + walk->gravity_state != WALK_GRAVITY_STATE_OFF) { float dvec_tmp[3]; @@ -1000,7 +1006,7 @@ static int walkApply(bContext *C, WalkInfo *walk) /* WASD - 'move' translation code */ if ((walk->active_directions) && - (walk->gravity == WALK_GRAVITY_STATE_OFF)) + (walk->gravity_state == WALK_GRAVITY_STATE_OFF)) { short direction; @@ -1076,7 +1082,7 @@ static int walkApply(bContext *C, WalkInfo *walk) /* stick to the floor */ if (walk->navigation_mode == WALK_MODE_GRAVITY && - ELEM(walk->gravity, + ELEM(walk->gravity_state, WALK_GRAVITY_STATE_OFF, WALK_GRAVITY_STATE_START)) { @@ -1101,13 +1107,13 @@ static int walkApply(bContext *C, WalkInfo *walk) dvec[2] -= difference; /* in case we switched from FREE to GRAVITY too close to the ground */ - if (walk->gravity == WALK_GRAVITY_STATE_START) - walk->gravity = WALK_GRAVITY_STATE_OFF; + if (walk->gravity_state == WALK_GRAVITY_STATE_START) + walk->gravity_state = WALK_GRAVITY_STATE_OFF; } else { /* hijack the teleport variables */ walk->teleport.initial_time = PIL_check_seconds_timer(); - walk->gravity = WALK_GRAVITY_STATE_ON; + walk->gravity_state = WALK_GRAVITY_STATE_ON; walk->teleport.duration = 0.0f; copy_v3_v3(walk->teleport.origin, walk->rv3d->viewinv[3]); @@ -1117,7 +1123,7 @@ static int walkApply(bContext *C, WalkInfo *walk) } /* Falling or jumping) */ - if (ELEM(walk->gravity, WALK_GRAVITY_STATE_ON, WALK_GRAVITY_STATE_JUMP)) { + if (ELEM(walk->gravity_state, WALK_GRAVITY_STATE_ON, WALK_GRAVITY_STATE_JUMP)) { float t; float z_cur, z_new; bool ret; @@ -1130,7 +1136,7 @@ static int walkApply(bContext *C, WalkInfo *walk) copy_v2_v2(dvec, walk->teleport.direction); z_cur = walk->rv3d->viewinv[3][2]; - z_new = walk->teleport.origin[2] - getFreeFallDistance(t) * walk->grid; + z_new = walk->teleport.origin[2] - getFreeFallDistance(walk->gravity, t) * walk->grid; /* jump */ z_new += t * walk->speed_jump * walk->grid; @@ -1148,7 +1154,7 @@ static int walkApply(bContext *C, WalkInfo *walk) if (difference > 0.0f) { /* quit falling, lands at "view_height" from the floor */ dvec[2] -= difference; - walk->gravity = WALK_GRAVITY_STATE_OFF; + walk->gravity_state = WALK_GRAVITY_STATE_OFF; walk->speed_jump = 0.0f; } else { @@ -1334,5 +1340,3 @@ void VIEW3D_OT_walk(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_BLOCKING; } - -#undef EARTH_GRAVITY diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript index f3c8c13647a..4f47062e3a3 100644 --- a/source/blender/editors/transform/SConscript +++ b/source/blender/editors/transform/SConscript @@ -40,6 +40,7 @@ incs = [ '../../ikplugin', '../../makesdna', '../../makesrna', + '../../gpu', '../../windowmanager', ] diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 42cc6b14fd5..9092dbd52dd 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -86,6 +86,9 @@ #include "transform.h" +/* Disabling, since when you type you know what you are doing, and being able to set it to zero is handy. */ +// #define USE_NUM_NO_ZERO + #define MAX_INFO_LEN 256 static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg); @@ -190,9 +193,9 @@ static bool transdata_check_local_center(TransInfo *t, short around) { return ((around == V3D_LOCAL) && ( (t->flag & (T_OBJECT | T_POSE)) || - (t->obedit && ELEM4(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) || + (t->obedit && ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) || (t->spacetype == SPACE_IPO) || - (t->options & (CTX_MOVIECLIP | CTX_MASK))) + (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE))) ); } @@ -263,17 +266,27 @@ static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy) void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy) { if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) { - const float mval_f[2] = {(float)dx, (float)dy}; - ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac); + if (t->options & CTX_PAINT_CURVE) { + r_vec[0] = dx; + r_vec[1] = dy; + } + else { const float mval_f[2] = {(float)dx, (float)dy}; + ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac); + } } else if (t->spacetype == SPACE_IMAGE) { float aspx, aspy; if (t->options & CTX_MASK) { - convertViewVec2D_mask(t->view, r_vec, dx, dy); ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy); } + else if (t->options & CTX_PAINT_CURVE) { + r_vec[0] = dx; + r_vec[1] = dy; + + aspx = aspy = 1.0; + } else { convertViewVec2D(t->view, r_vec, dx, dy); ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy); @@ -351,6 +364,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr adr[0] = v[0]; adr[1] = v[1]; } + else if (t->options & CTX_PAINT_CURVE) { + adr[0] = vec[0]; + adr[1] = vec[1]; + } else { float aspx, aspy, v[2]; @@ -452,7 +469,11 @@ void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV switch (t->spacetype) { case SPACE_VIEW3D: { - if (t->ar->regiontype == RGN_TYPE_WINDOW) { + if (t->options & CTX_PAINT_CURVE) { + adr[0] = vec[0]; + adr[1] = vec[1]; + } + else if (t->ar->regiontype == RGN_TYPE_WINDOW) { /* allow points behind the view [#33643] */ if (ED_view3d_project_float_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) { /* XXX, 2.64 and prior did this, weak! */ @@ -480,7 +501,7 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2]) void applyAspectRatio(TransInfo *t, float vec[2]) { - if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) { + if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION) && !(t->options & CTX_PAINT_CURVE)) { SpaceImage *sima = t->sa->spacedata.first; float aspx, aspy; @@ -557,17 +578,23 @@ void removeAspectRatio(TransInfo *t, float vec[2]) static void viewRedrawForce(const bContext *C, TransInfo *t) { if (t->spacetype == SPACE_VIEW3D) { - /* Do we need more refined tags? */ - if (t->flag & T_POSE) - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); - else - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + if (t->options & CTX_PAINT_CURVE) { + wmWindow *window = CTX_wm_window(C); + WM_paint_cursor_tag_redraw(window, t->ar); + } + else { + /* Do we need more refined tags? */ + if (t->flag & T_POSE) + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + else + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - /* for realtime animation record - send notifiers recognised by animation editors */ - // XXX: is this notifier a lame duck? - if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); - + /* for realtime animation record - send notifiers recognised by animation editors */ + // XXX: is this notifier a lame duck? + if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); + + } } else if (t->spacetype == SPACE_ACTION) { //SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; @@ -593,6 +620,10 @@ static void viewRedrawForce(const bContext *C, TransInfo *t) WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); } + else if (t->options & CTX_PAINT_CURVE) { + wmWindow *window = CTX_wm_window(C); + WM_paint_cursor_tag_redraw(window, t->ar); + } else { // XXX how to deal with lock? SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first; @@ -646,7 +677,7 @@ static void viewRedrawPost(bContext *C, TransInfo *t) allqueue(REDRAWIMAGE, 0); allqueue(REDRAWVIEW3D, 0); } - else if (ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) { + else if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) { allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWACTION, 0); allqueue(REDRAWNLA, 0); @@ -969,7 +1000,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_TRANSLATE: /* only switch when... */ - if (ELEM5(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { + if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { resetTransModal(t); resetTransRestrictions(t); restoreTransObjects(t); @@ -1025,7 +1056,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) case TFM_MODAL_ROTATE: /* only switch when... */ if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) { - if (ELEM6(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { + if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { resetTransModal(t); resetTransRestrictions(t); @@ -1045,7 +1076,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_RESIZE: /* only switch when... */ - if (ELEM5(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { + if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { /* Scale isn't normally very useful after extrude along normals, see T39756 */ if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_MANIP_NORMAL)) { @@ -1308,7 +1339,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case GKEY: /* only switch when... */ - if (ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) { + if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { resetTransModal(t); resetTransRestrictions(t); restoreTransObjects(t); @@ -1320,7 +1351,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case SKEY: /* only switch when... */ - if (ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) { + if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) { resetTransModal(t); resetTransRestrictions(t); restoreTransObjects(t); @@ -1333,7 +1364,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) case RKEY: /* only switch when... */ if (!(t->options & CTX_TEXTURE)) { - if (ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) { + if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) { resetTransModal(t); resetTransRestrictions(t); @@ -1807,23 +1838,25 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar) BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]); - xco = rect.xmax - (int)printable_size[0] - 10; - yco = rect.ymax - (int)printable_size[1] - 10; + xco = (rect.xmax - U.widget_unit) - (int)printable_size[0]; + yco = (rect.ymax - U.widget_unit); /* warning text (to clarify meaning of overlays) * - original color was red to match the icon, but that clashes badly with a less nasty border */ UI_ThemeColorShade(TH_TEXT_HI, -50); #ifdef WITH_INTERNATIONAL - BLF_draw_default(xco, ar->winy - 17, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); + BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); #else - BLF_draw_default_ascii(xco, ar->winy - 17, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); + BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); #endif /* autokey recording icon... */ glEnable(GL_BLEND); - xco -= (ICON_DEFAULT_WIDTH + 2); + xco -= U.widget_unit; + yco -= (int)printable_size[1] / 2; + UI_icon_draw(xco, yco, ICON_REC); glDisable(GL_BLEND); @@ -2064,7 +2097,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve * moded are available from manipulator and doing such check could * lead to keymap conflicts for other modes (see #31584) */ - if (ELEM3(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) { + if (ELEM(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) { wmKeyMapItem *kmi; for (kmi = t->keymap->items.first; kmi; kmi = kmi->next) { @@ -2840,7 +2873,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN * 2]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bend Angle: %s Radius: %s Alt, Clamp %s"), &c[0], &c[NUM_STR_REP_LEN], @@ -3008,7 +3041,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %s %s"), c, t->proptext); } @@ -3084,9 +3117,11 @@ static void initResize(TransInfo *t) t->num.flag |= NUM_AFFECT_ALL; if (!t->obedit) { t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; t->num.val_flag[1] |= NUM_NO_ZERO; t->num.val_flag[2] |= NUM_NO_ZERO; +#endif } t->idx_max = 2; @@ -3107,7 +3142,7 @@ static void headerResize(TransInfo *t, float vec[3], char str[MAX_INFO_LEN]) char tvec[NUM_STR_REP_LEN * 3]; size_t ofs = 0; if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, t->scene->unit.scale_length); + outputNumInput(&(t->num), tvec, &t->scene->unit); } else { BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]); @@ -3376,9 +3411,11 @@ static void initSkinResize(TransInfo *t) t->num.flag |= NUM_AFFECT_ALL; if (!t->obedit) { t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; t->num.val_flag[1] |= NUM_NO_ZERO; t->num.val_flag[2] |= NUM_NO_ZERO; +#endif } t->idx_max = 2; @@ -3519,7 +3556,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %s %s"), c, t->proptext); } @@ -3591,8 +3628,15 @@ static void initRotation(TransInfo *t) if (t->flag & T_2D_EDIT) t->flag |= T_NO_CONSTRAINT; - negate_v3_v3(t->axis, t->viewinv[2]); - normalize_v3(t->axis); + if (t->options & CTX_PAINT_CURVE) { + t->axis[0] = 0.0; + t->axis[1] = 0.0; + t->axis[2] = -1.0; + } + else { + negate_v3_v3(t->axis, t->viewinv[2]); + normalize_v3(t->axis); + } copy_v3_v3(t->axis_orig, t->axis); } @@ -3626,7 +3670,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short if (td->flag & TD_USEQUAT) { - mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(fmat, td->smtx, mat, td->mtx); mat3_to_quat(quat, fmat); // Actual transform if (td->ext->quat) { @@ -3696,7 +3740,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't rotate objects itself */ /* euler or quaternion/axis-angle? */ if (td->ext->rotOrder == ROT_MODE_QUAT) { - mul_serie_m3(fmat, td->ext->r_mtx, mat, td->ext->r_smtx, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx); mat3_to_quat(quat, fmat); /* Actual transform */ @@ -3711,7 +3755,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle); - mul_serie_m3(fmat, td->ext->r_mtx, mat, td->ext->r_smtx, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx); mat3_to_quat(quat, fmat); /* Actual transform */ mul_qt_qtqt(tquat, quat, iquat); @@ -3768,7 +3812,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) { /* can be called for texture space translate for example, then opt out */ if (td->ext->quat) { - mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(fmat, td->smtx, mat, td->mtx); mat3_to_quat(quat, fmat); // Actual transform mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); @@ -3782,7 +3826,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle); - mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(fmat, td->smtx, mat, td->mtx); mat3_to_quat(quat, fmat); // Actual transform mul_qt_qtqt(tquat, quat, iquat); @@ -3876,7 +3920,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext); } @@ -3980,7 +4024,7 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN * 2]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %s %s %s"), &c[0], &c[NUM_STR_REP_LEN], t->proptext); @@ -4082,7 +4126,7 @@ static void headerTranslation(TransInfo *t, float vec[3], char str[MAX_INFO_LEN] float dist; if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, t->scene->unit.scale_length); + outputNumInput(&(t->num), tvec, &t->scene->unit); dist = len_v3(t->num.val); } else { @@ -4330,7 +4374,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), MAX_INFO_LEN - ofs); if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", c); } else { @@ -4425,7 +4469,7 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %s° %s"), &c[0], t->proptext); @@ -4479,7 +4523,9 @@ static void initCurveShrinkFatten(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; +#endif t->flag |= T_NO_CONSTRAINT; } @@ -4501,7 +4547,7 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %s"), c); } else { @@ -4554,7 +4600,9 @@ static void initMaskShrinkFatten(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; +#endif t->flag |= T_NO_CONSTRAINT; } @@ -4577,7 +4625,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %s"), c); } else { @@ -4670,7 +4718,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext); } @@ -4763,7 +4811,7 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); if (weight >= 0.0f) BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%s %s"), c, t->proptext); @@ -4841,7 +4889,7 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); if (crease >= 0.0f) BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%s %s"), c, t->proptext); @@ -4911,7 +4959,7 @@ static void headerBoneSize(TransInfo *t, float vec[3], char str[MAX_INFO_LEN]) { char tvec[NUM_STR_REP_LEN * 3]; if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, t->scene->unit.scale_length); + outputNumInput(&(t->num), tvec, &t->scene->unit); } else { BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]); @@ -5048,7 +5096,7 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %s"), c); } else { @@ -6222,7 +6270,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); if (is_proportional) { BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s"), @@ -6744,7 +6792,7 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), MAX_INFO_LEN - ofs); if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs); } else { @@ -6811,7 +6859,7 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2])) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %s"), &c[0]); } @@ -6885,7 +6933,7 @@ static void applyBakeTime(TransInfo *t, const int mval[2]) if (hasNumInput(&t->num)) { char c[NUM_STR_REP_LEN]; - outputNumInput(&(t->num), c, t->scene->unit.scale_length); + outputNumInput(&(t->num), c, &t->scene->unit); if (time >= 0.0f) BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%s %s"), c, t->proptext); @@ -7096,7 +7144,7 @@ static void headerSeqSlide(TransInfo *t, float val[2], char str[MAX_INFO_LEN]) size_t ofs = 0; if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, t->scene->unit.scale_length); + outputNumInput(&(t->num), tvec, &t->scene->unit); } else { BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]); @@ -7322,7 +7370,7 @@ static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN]) /* if numeric input is active, use results from that, otherwise apply snapping to result */ if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, t->scene->unit.scale_length); + outputNumInput(&(t->num), tvec, &t->scene->unit); } else { const Scene *scene = t->scene; @@ -7486,7 +7534,7 @@ static void headerTimeSlide(TransInfo *t, float sval, char str[MAX_INFO_LEN]) char tvec[NUM_STR_REP_LEN * 3]; if (hasNumInput(&t->num)) { - outputNumInput(&(t->num), tvec, t->scene->unit.scale_length); + outputNumInput(&(t->num), tvec, &t->scene->unit); } else { float minx = *((float *)(t->customData)); @@ -7634,7 +7682,7 @@ static void headerTimeScale(TransInfo *t, char str[MAX_INFO_LEN]) char tvec[NUM_STR_REP_LEN * 3]; if (hasNumInput(&t->num)) - outputNumInput(&(t->num), tvec, t->scene->unit.scale_length); + outputNumInput(&(t->num), tvec, &t->scene->unit); else BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", t->values[0]); @@ -7704,7 +7752,7 @@ bool checkUseAxisMatrix(TransInfo *t) { /* currently only checks for editmode */ if (t->flag & T_EDIT) { - if ((t->around == V3D_LOCAL) && (ELEM4(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE))) { + if ((t->around == V3D_LOCAL) && (ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE))) { /* not all editmode supports axis-matrix */ return true; } diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 0bccf177128..012f9185d8b 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -130,15 +130,15 @@ typedef struct TransDataExtension { // float drotAxis[3]; /* Initial object drotAxis, TODO: not yet implemented */ float dquat[4]; /* Initial object dquat */ float dscale[3]; /* Initial object dscale */ - float *rot; /* Rotation of the data to transform (Faculative) */ + float *rot; /* Rotation of the data to transform */ float irot[3]; /* Initial rotation */ - float *quat; /* Rotation quaternion of the data to transform (Faculative) */ + float *quat; /* Rotation quaternion of the data to transform */ float iquat[4]; /* Initial rotation quaternion */ - float *rotAngle; /* Rotation angle of the data to transform (Faculative) */ + float *rotAngle; /* Rotation angle of the data to transform */ float irotAngle; /* Initial rotation angle */ - float *rotAxis; /* Rotation axis of the data to transform (Faculative) */ + float *rotAxis; /* Rotation axis of the data to transform */ float irotAxis[4]; /* Initial rotation axis */ - float *size; /* Size of the data to transform (Faculative) */ + float *size; /* Size of the data to transform */ float isize[3]; /* Initial size */ float obmat[4][4]; /* Object matrix */ float l_smtx[3][3]; /* use instead of td->smtx, It is the same but without the 'bone->bone_mat', see TD_PBONE_LOCAL_MTX_C */ @@ -532,6 +532,7 @@ void flushTransNodes(TransInfo *t); void flushTransSeq(TransInfo *t); void flushTransTracking(TransInfo *t); void flushTransMasking(TransInfo *t); +void flushTransPaintCurve(TransInfo *t); void restoreBones(TransInfo *t); /*********************** exported from transform_manipulator.c ********** */ diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 79f266df607..d8f17315c01 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -663,7 +663,7 @@ void drawConstraint(TransInfo *t) { TransCon *tc = &(t->con); - if (!ELEM3(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) + if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) return; if (!(tc->mode & CON_APPLY)) return; @@ -756,6 +756,9 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) /* untested - mask aspect is TODO */ ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy); } + else if (t->options & CTX_PAINT_CURVE) { + aspx = aspy = 1.0; + } else { ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy); } diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 9dfd3e568e5..aa215613841 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -33,6 +33,7 @@ #include <math.h> #include "DNA_anim_types.h" +#include "DNA_brush_types.h" #include "DNA_armature_types.h" #include "DNA_lattice_types.h" #include "DNA_mesh_types.h" @@ -80,6 +81,7 @@ #include "BKE_node.h" #include "BKE_object.h" #include "BKE_particle.h" +#include "BKE_paint.h" #include "BKE_pointcache.h" #include "BKE_report.h" #include "BKE_rigidbody.h" @@ -124,8 +126,8 @@ 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))) + (ELEM(t->around, V3D_CENTER, V3D_CENTROID, V3D_ACTIVE)) && + (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) { t->around = V3D_LOCAL; } @@ -282,7 +284,7 @@ static void createTransTexspace(TransInfo *t) } id = ob->data; - if (id == NULL || !ELEM3(GS(id->name), ID_ME, ID_CU, ID_MB)) { + if (id == NULL || !ELEM(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; @@ -584,12 +586,12 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr if (constraints_list_needinv(t, &pchan->constraints)) { copy_m3_m4(tmat, pchan->constinv); invert_m3_m3(cmat, tmat); - mul_serie_m3(td->mtx, pmat, omat, cmat, NULL, NULL, NULL, NULL, NULL); - mul_serie_m3(td->ext->r_mtx, rpmat, omat, cmat, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(td->mtx, cmat, omat, pmat); + mul_m3_series(td->ext->r_mtx, cmat, omat, rpmat); } else { - mul_serie_m3(td->mtx, pmat, omat, NULL, NULL, NULL, NULL, NULL, NULL); - mul_serie_m3(td->ext->r_mtx, rpmat, omat, NULL, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(td->mtx, omat, pmat); + mul_m3_series(td->ext->r_mtx, omat, rpmat); } invert_m3_m3(td->ext->r_smtx, td->ext->r_mtx); } @@ -1279,7 +1281,7 @@ static void createTransArmatureVerts(TransInfo *t) } } - if (mirror && total_mirrored) { + if (mirror) { /* trick to terminate iteration */ bid[total_mirrored].bone = NULL; } @@ -2368,8 +2370,7 @@ static void createTransEditVerts(TransInfo *t) quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]); if (defmats) - mul_serie_m3(mat, mtx, qmat, defmats[a], - NULL, NULL, NULL, NULL, NULL); + mul_m3_series(mat, defmats[a], qmat, mtx); else mul_m3_m3m3(mat, mtx, qmat); } @@ -3707,7 +3708,7 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph * static bool graph_edit_is_translation_mode(TransInfo *t) { - return ELEM4(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE); + return ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE); } static bool graph_edit_use_local_center(TransInfo *t) @@ -4767,12 +4768,12 @@ static bool constraints_list_needinv(TransInfo *t, ListBase *list) if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) { /* (affirmative) returns for specific constraints here... */ /* constraints that require this regardless */ - if (ELEM5(con->type, - CONSTRAINT_TYPE_CHILDOF, - CONSTRAINT_TYPE_FOLLOWPATH, - CONSTRAINT_TYPE_CLAMPTO, - CONSTRAINT_TYPE_OBJECTSOLVER, - CONSTRAINT_TYPE_FOLLOWTRACK)) + if (ELEM(con->type, + CONSTRAINT_TYPE_CHILDOF, + CONSTRAINT_TYPE_FOLLOWPATH, + CONSTRAINT_TYPE_CLAMPTO, + CONSTRAINT_TYPE_OBJECTSOLVER, + CONSTRAINT_TYPE_FOLLOWTRACK)) { return true; } @@ -5848,6 +5849,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t) DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } + else if (t->options & CTX_PAINT_CURVE) { + /* pass */ + } else if ((t->scene->basact) && (ob = t->scene->basact->object) && (ob->mode & OB_MODE_PARTICLE_EDIT) && @@ -7027,6 +7031,173 @@ void flushTransMasking(TransInfo *t) } } +typedef struct TransDataPaintCurve { + PaintCurvePoint *pcp; /* initial curve point */ + char id; +} TransDataPaintCurve; + + +#define PC_IS_ANY_SEL(pc) (((pc)->bez.f1 | (pc)->bez.f2 | (pc)->bez.f3) & SELECT) + +static void PaintCurveConvertHandle(PaintCurvePoint *pcp, int id, TransData2D *td2d, TransDataPaintCurve *tdpc, TransData *td) +{ + BezTriple *bezt = &pcp->bez; + copy_v2_v2(td2d->loc, bezt->vec[id]); + td2d->loc[2] = 0.0f; + td2d->loc2d = bezt->vec[id]; + + td->flag = 0; + td->loc = td2d->loc; + copy_v3_v3(td->center, bezt->vec[1]); + copy_v3_v3(td->iloc, 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); + + tdpc->id = id; + tdpc->pcp = pcp; +} + +static void PaintCurvePointToTransData(PaintCurvePoint *pcp, TransData *td, TransData2D *td2d, TransDataPaintCurve *tdpc) +{ + BezTriple *bezt = &pcp->bez; + + if (pcp->bez.f2 == SELECT) { + int i; + for (i = 0; i < 3; i++) { + copy_v2_v2(td2d->loc, bezt->vec[i]); + td2d->loc[2] = 0.0f; + td2d->loc2d = bezt->vec[i]; + + td->flag = 0; + td->loc = td2d->loc; + copy_v3_v3(td->center, bezt->vec[1]); + copy_v3_v3(td->iloc, 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); + + tdpc->id = i; + tdpc->pcp = pcp; + + td++; + td2d++; + tdpc++; + } + } + else { + if (bezt->f3 & SELECT) { + PaintCurveConvertHandle(pcp, 2, td2d, tdpc, td); + td2d++; + tdpc++; + td++; + } + + if (bezt->f1 & SELECT) { + PaintCurveConvertHandle(pcp, 0, td2d, tdpc, td); + } + } +} + +static void createTransPaintCurveVerts(bContext *C, TransInfo *t) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + PaintCurve *pc; + PaintCurvePoint *pcp; + Brush *br; + TransData *td = NULL; + TransData2D *td2d = NULL; + TransDataPaintCurve *tdpc = NULL; + int i; + int total = 0; + + t->total = 0; + + if (!paint || !paint->brush || !paint->brush->paint_curve) + return; + + br = paint->brush; + pc = br->paint_curve; + + for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) { + if (PC_IS_ANY_SEL(pcp)) { + if (pcp->bez.f2 & SELECT) { + total += 3; + continue; + } + else { + if (pcp->bez.f1 & SELECT) + total++; + if (pcp->bez.f3 & SELECT) + total++; + } + } + } + + if (!total) + return; + + t->total = total; + td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransData2D"); + td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransData"); + tdpc = t->customData = MEM_callocN(t->total * sizeof(TransDataPaintCurve), "TransDataPaintCurve"); + t->flag |= T_FREE_CUSTOMDATA; + + for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) { + if (PC_IS_ANY_SEL(pcp)) { + PaintCurvePointToTransData (pcp, td, td2d, tdpc); + + if (pcp->bez.f2 & SELECT) { + td += 3; + td2d += 3; + tdpc += 3; + } + else { + if (pcp->bez.f1 & SELECT) { + td++; + td2d++; + tdpc++; + } + if (pcp->bez.f3 & SELECT) { + td++; + td2d++; + tdpc++; + } + } + } + } +} + + +void flushTransPaintCurve(TransInfo *t) +{ + int i; + TransData2D *td2d = t->data2d; + TransDataPaintCurve *tdpc = (TransDataPaintCurve *)t->customData; + + for (i = 0; i < t->total; i++, tdpc++, td2d++) { + PaintCurvePoint *pcp = tdpc->pcp; + copy_v2_v2(pcp->bez.vec[tdpc->id], td2d->loc); + } +} + + void createTransData(bContext *C, TransInfo *t) { Scene *scene = t->scene; @@ -7059,6 +7230,10 @@ void createTransData(bContext *C, TransInfo *t) sort_trans_data_dist(t); } } + else if (t->options & CTX_PAINT_CURVE) { + if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) + createTransPaintCurveVerts(C, t); + } else if (t->obedit) { createTransUVs(C, t); if (t->data && (t->flag & T_PROP_EDIT)) { @@ -7165,7 +7340,7 @@ void createTransData(bContext *C, TransInfo *t) // XXX active-layer checking isn't done as that should probably be checked through context instead createTransPose(t, ob); } - else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT)) { + else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) { /* important that ob_armature can be set even when its not selected [#23412] * lines below just check is also visible */ Object *ob_armature = modifiers_isDeformedByArmature(ob); @@ -7190,12 +7365,11 @@ void createTransData(bContext *C, TransInfo *t) sort_trans_data_dist(t); } } - else if (ob && (ob->mode & (OB_MODE_ALL_PAINT))) { - /* sculpt mode and project paint have own undo stack - * transform ops redo clears sculpt/project undo stack. - * - * Could use 'OB_MODE_ALL_PAINT' since there are key conflicts, - * transform + paint isn't well supported. */ + else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) { + if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) { + t->flag |= T_POINTS | T_2D_EDIT; + createTransPaintCurveVerts(C, t); + } } else { createTransObject(C, t); diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 15d1bb75d89..24dc6f6e74b 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -38,6 +38,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" +#include "DNA_brush_types.h" #include "DNA_lattice_types.h" #include "DNA_screen_types.h" #include "DNA_sequence_types.h" @@ -74,6 +75,7 @@ #include "BKE_lattice.h" #include "BKE_nla.h" #include "BKE_context.h" +#include "BKE_paint.h" #include "BKE_sequencer.h" #include "BKE_editmesh.h" #include "BKE_tracking.h" @@ -98,6 +100,7 @@ #include "WM_api.h" #include "UI_resources.h" +#include "UI_view2d.h" #include "transform.h" @@ -262,7 +265,7 @@ static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer) ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL; /* sanity checks */ - if (ELEM3(NULL, scene, id, sad)) + if (ELEM(NULL, scene, id, sad)) return; /* check if we need a new strip if: @@ -653,6 +656,9 @@ static void recalcData_image(TransInfo *t) if (t->options & CTX_MASK) { recalcData_mask_common(t); } + else if (t->options & CTX_PAINT_CURVE) { + flushTransPaintCurve(t); + } else if (t->obedit && t->obedit->type == OB_MESH) { SpaceImage *sima = t->sa->spacedata.first; @@ -817,7 +823,7 @@ static void recalcData_objects(TransInfo *t) } } - if (!ELEM3(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONESIZE)) { + if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONESIZE)) { /* fix roll */ for (i = 0; i < t->total; i++, td++) { if (td->extra) { @@ -965,6 +971,9 @@ void recalcData(TransInfo *t) else if (t->options & CTX_EDGE) { recalcData_objects(t); } + else if (t->options & CTX_PAINT_CURVE) { + flushTransPaintCurve(t); + } else if (t->spacetype == SPACE_IMAGE) { recalcData_image(t); } @@ -1073,6 +1082,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve ARegion *ar = CTX_wm_region(C); ScrArea *sa = CTX_wm_area(C); Object *obedit = CTX_data_edit_object(C); + Object *ob = CTX_data_active_object(C); PropertyRNA *prop; t->scene = sce; @@ -1193,11 +1203,18 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve /* exceptional case */ if (t->around == V3D_LOCAL && (t->settings->selectmode & SCE_SELECT_FACE)) { - if (ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { + if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { t->options |= CTX_NO_PET; } } + if (ob && ob->mode & OB_MODE_ALL_PAINT) { + Paint *p = BKE_paint_get_active_from_context(C); + if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) { + t->options |= CTX_PAINT_CURVE; + } + } + /* initialize UV transform from */ if (op && ((prop = RNA_struct_find_property(op->ptr, "correct_uv")))) { if (RNA_property_is_set(op->ptr, prop)) { @@ -1226,9 +1243,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve else if (sima->mode == SI_MODE_MASK) { t->options |= CTX_MASK; } - else { - /* image not in uv edit, nor in mask mode, can happen for some tools */ + else if (sima->mode == SI_MODE_PAINT) { + Paint *p = &sce->toolsettings->imapaint.paint; + if (p->brush && (p->brush->flag & BRUSH_CURVE)) { + t->options |= CTX_PAINT_CURVE; + } } + /* image not in uv edit, nor in mask mode, can happen for some tools */ } else if (t->spacetype == SPACE_NODE) { // XXX for now, get View2D from the active region @@ -1409,7 +1430,7 @@ void postTrans(bContext *C, TransInfo *t) } if (t->spacetype == SPACE_IMAGE) { - if (t->options & CTX_MASK) { + if (t->options & (CTX_MASK | CTX_PAINT_CURVE)) { /* pass */ } else { @@ -1539,6 +1560,13 @@ void calculateCenterCursor(TransInfo *t, float r_center[3]) invert_m3_m3(imat, mat); mul_m3_v3(imat, r_center); } + else if (t->options & CTX_PAINT_CURVE) { + if (ED_view3d_project_float_global(t->ar, cursor, r_center, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) { + r_center[0] = t->ar->winx / 2.0f; + r_center[1] = t->ar->winy / 2.0f; + } + r_center[2] = 0.0f; + } } void calculateCenterCursor2D(TransInfo *t, float r_center[2]) @@ -1586,6 +1614,12 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2]) r_center[0] = co[0] * aspx; r_center[1] = co[1] * aspy; } + else if (t->options & CTX_PAINT_CURVE) { + if (t->spacetype == SPACE_IMAGE) { + r_center[0] = UI_view2d_view_to_region_x(&t->ar->v2d, cursor[0]); + r_center[1] = UI_view2d_view_to_region_y(&t->ar->v2d, cursor[1]); + } + } else { r_center[0] = cursor[0] * aspx; r_center[1] = cursor[1] * aspy; @@ -1720,6 +1754,14 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) } } } + else if (t->options & CTX_PAINT_CURVE) { + Paint *p = BKE_paint_get_active(t->scene); + Brush *br = p->brush; + PaintCurve *pc = br->paint_curve; + copy_v3_v3(r_center, pc->points[pc->add_index - 1].bez.vec[1]); + r_center[2] = 0.0f; + ok = true; + } else { /* object mode */ Scene *scene = t->scene; diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 36d91c1c630..6441071056f 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -72,6 +72,8 @@ /* local module include */ #include "transform.h" +#include "GPU_select.h" + /* return codes for select, and drawing flags */ #define MAN_TRANS_X (1 << 0) @@ -858,8 +860,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co /* axes */ if (flagx) { if (is_picksel) { - if (flagx & MAN_SCALE_X) glLoadName(MAN_SCALE_X); - else if (flagx & MAN_TRANS_X) glLoadName(MAN_TRANS_X); + if (flagx & MAN_SCALE_X) GPU_select_load_id(MAN_SCALE_X); + else if (flagx & MAN_TRANS_X) GPU_select_load_id(MAN_TRANS_X); } else { manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); @@ -873,8 +875,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co case 1: if (flagy) { if (is_picksel) { - if (flagy & MAN_SCALE_Y) glLoadName(MAN_SCALE_Y); - else if (flagy & MAN_TRANS_Y) glLoadName(MAN_TRANS_Y); + if (flagy & MAN_SCALE_Y) GPU_select_load_id(MAN_SCALE_Y); + else if (flagy & MAN_TRANS_Y) GPU_select_load_id(MAN_TRANS_Y); } else { manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); @@ -888,8 +890,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co case 2: if (flagz) { if (is_picksel) { - if (flagz & MAN_SCALE_Z) glLoadName(MAN_SCALE_Z); - else if (flagz & MAN_TRANS_Z) glLoadName(MAN_TRANS_Z); + if (flagz & MAN_SCALE_Z) GPU_select_load_id(MAN_SCALE_Z); + else if (flagz & MAN_TRANS_Z) GPU_select_load_id(MAN_TRANS_Z); } else { manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); @@ -975,7 +977,7 @@ static void draw_manipulator_rotate( /* Screen aligned trackball rot circle */ if (drawflags & MAN_ROT_T) { - if (is_picksel) glLoadName(MAN_ROT_T); + if (is_picksel) GPU_select_load_id(MAN_ROT_T); else UI_ThemeColor(TH_TRANSFORM); drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat); @@ -983,7 +985,7 @@ static void draw_manipulator_rotate( /* Screen aligned view rot circle */ if (drawflags & MAN_ROT_V) { - if (is_picksel) glLoadName(MAN_ROT_V); + if (is_picksel) GPU_select_load_id(MAN_ROT_V); else UI_ThemeColor(TH_TRANSFORM); drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat); @@ -1062,7 +1064,7 @@ static void draw_manipulator_rotate( /* Z circle */ if (drawflags & MAN_ROT_Z) { preOrthoFront(ortho, matt, 2); - if (is_picksel) glLoadName(MAN_ROT_Z); + if (is_picksel) GPU_select_load_id(MAN_ROT_Z); else manipulator_setcolor(v3d, 'Z', colcode, 255); drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); postOrtho(ortho); @@ -1070,7 +1072,7 @@ static void draw_manipulator_rotate( /* X circle */ if (drawflags & MAN_ROT_X) { preOrthoFront(ortho, matt, 0); - if (is_picksel) glLoadName(MAN_ROT_X); + if (is_picksel) GPU_select_load_id(MAN_ROT_X); else manipulator_setcolor(v3d, 'X', colcode, 255); glRotatef(90.0, 0.0, 1.0, 0.0); drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); @@ -1080,7 +1082,7 @@ static void draw_manipulator_rotate( /* Y circle */ if (drawflags & MAN_ROT_Y) { preOrthoFront(ortho, matt, 1); - if (is_picksel) glLoadName(MAN_ROT_Y); + if (is_picksel) GPU_select_load_id(MAN_ROT_Y); else manipulator_setcolor(v3d, 'Y', colcode, 255); glRotatef(-90.0, 1.0, 0.0, 0.0); drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); @@ -1097,7 +1099,7 @@ static void draw_manipulator_rotate( /* Z circle */ if (drawflags & MAN_ROT_Z) { preOrthoFront(ortho, rv3d->twmat, 2); - if (is_picksel) glLoadName(MAN_ROT_Z); + if (is_picksel) GPU_select_load_id(MAN_ROT_Z); else manipulator_setcolor(v3d, 'Z', colcode, 255); partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); postOrtho(ortho); @@ -1105,7 +1107,7 @@ static void draw_manipulator_rotate( /* X circle */ if (drawflags & MAN_ROT_X) { preOrthoFront(ortho, rv3d->twmat, 0); - if (is_picksel) glLoadName(MAN_ROT_X); + if (is_picksel) GPU_select_load_id(MAN_ROT_X); else manipulator_setcolor(v3d, 'X', colcode, 255); glRotatef(90.0, 0.0, 1.0, 0.0); partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); @@ -1115,7 +1117,7 @@ static void draw_manipulator_rotate( /* Y circle */ if (drawflags & MAN_ROT_Y) { preOrthoFront(ortho, rv3d->twmat, 1); - if (is_picksel) glLoadName(MAN_ROT_Y); + if (is_picksel) GPU_select_load_id(MAN_ROT_Y); else manipulator_setcolor(v3d, 'Y', colcode, 255); glRotatef(-90.0, 1.0, 0.0, 0.0); partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); @@ -1132,7 +1134,7 @@ static void draw_manipulator_rotate( if (drawflags & MAN_ROT_Z) { preOrthoFront(ortho, rv3d->twmat, 2); glPushMatrix(); - if (is_picksel) glLoadName(MAN_ROT_Z); + if (is_picksel) GPU_select_load_id(MAN_ROT_Z); else manipulator_setcolor(v3d, 'Z', colcode, 255); partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64); @@ -1145,7 +1147,7 @@ static void draw_manipulator_rotate( if (drawflags & MAN_ROT_Y) { preOrthoFront(ortho, rv3d->twmat, 1); glPushMatrix(); - if (is_picksel) glLoadName(MAN_ROT_Y); + if (is_picksel) GPU_select_load_id(MAN_ROT_Y); else manipulator_setcolor(v3d, 'Y', colcode, 255); glRotatef(90.0, 1.0, 0.0, 0.0); @@ -1160,7 +1162,7 @@ static void draw_manipulator_rotate( if (drawflags & MAN_ROT_X) { preOrthoFront(ortho, rv3d->twmat, 0); glPushMatrix(); - if (is_picksel) glLoadName(MAN_ROT_X); + if (is_picksel) GPU_select_load_id(MAN_ROT_X); else manipulator_setcolor(v3d, 'X', colcode, 255); glRotatef(-90.0, 0.0, 1.0, 0.0); @@ -1263,7 +1265,7 @@ static void draw_manipulator_scale( int shift = 0; // XXX /* center circle, do not add to selection when shift is pressed (planar constraint) */ - if (is_picksel && shift == 0) glLoadName(MAN_SCALE_C); + if (is_picksel && shift == 0) GPU_select_load_id(MAN_SCALE_C); else manipulator_setcolor(v3d, 'C', colcode, 255); glPushMatrix(); @@ -1304,7 +1306,7 @@ static void draw_manipulator_scale( case 0: /* X cube */ if (drawflags & MAN_SCALE_X) { glTranslatef(dz, 0.0, 0.0); - if (is_picksel) glLoadName(MAN_SCALE_X); + if (is_picksel) GPU_select_load_id(MAN_SCALE_X); else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); drawsolidcube(cusize); glTranslatef(-dz, 0.0, 0.0); @@ -1313,7 +1315,7 @@ static void draw_manipulator_scale( case 1: /* Y cube */ if (drawflags & MAN_SCALE_Y) { glTranslatef(0.0, dz, 0.0); - if (is_picksel) glLoadName(MAN_SCALE_Y); + if (is_picksel) GPU_select_load_id(MAN_SCALE_Y); else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); drawsolidcube(cusize); glTranslatef(0.0, -dz, 0.0); @@ -1322,7 +1324,7 @@ static void draw_manipulator_scale( case 2: /* Z cube */ if (drawflags & MAN_SCALE_Z) { glTranslatef(0.0, 0.0, dz); - if (is_picksel) glLoadName(MAN_SCALE_Z); + if (is_picksel) GPU_select_load_id(MAN_SCALE_Z); else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); drawsolidcube(cusize); glTranslatef(0.0, 0.0, -dz); @@ -1337,7 +1339,7 @@ static void draw_manipulator_scale( if (shift) { glTranslatef(0.0, -dz, 0.0); - glLoadName(MAN_SCALE_C); + GPU_select_load_id(MAN_SCALE_C); glBegin(GL_POINTS); glVertex3f(0.0, 0.0, 0.0); glEnd(); @@ -1399,7 +1401,7 @@ static void draw_manipulator_translate( glDisable(GL_DEPTH_TEST); /* center circle, do not add to selection when shift is pressed (planar constraint) */ - if (is_picksel && shift == 0) glLoadName(MAN_TRANS_C); + if (is_picksel && shift == 0) GPU_select_load_id(MAN_TRANS_C); else manipulator_setcolor(v3d, 'C', colcode, 255); glPushMatrix(); @@ -1412,7 +1414,7 @@ static void draw_manipulator_translate( glMultMatrixf(rv3d->twmat); /* axis */ - glLoadName(-1); + GPU_select_load_id(-1); // translate drawn as last, only axis when no combo with scale, or for ghosting if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) { @@ -1435,7 +1437,7 @@ static void draw_manipulator_translate( case 0: /* Z Cone */ if (drawflags & MAN_TRANS_Z) { glTranslatef(0.0, 0.0, dz); - if (is_picksel) glLoadName(MAN_TRANS_Z); + if (is_picksel) GPU_select_load_id(MAN_TRANS_Z); else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); draw_cone(qobj, cylen, cywid); glTranslatef(0.0, 0.0, -dz); @@ -1444,7 +1446,7 @@ static void draw_manipulator_translate( case 1: /* X Cone */ if (drawflags & MAN_TRANS_X) { glTranslatef(dz, 0.0, 0.0); - if (is_picksel) glLoadName(MAN_TRANS_X); + if (is_picksel) GPU_select_load_id(MAN_TRANS_X); else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); glRotatef(90.0, 0.0, 1.0, 0.0); draw_cone(qobj, cylen, cywid); @@ -1455,7 +1457,7 @@ static void draw_manipulator_translate( case 2: /* Y Cone */ if (drawflags & MAN_TRANS_Y) { glTranslatef(0.0, dz, 0.0); - if (is_picksel) glLoadName(MAN_TRANS_Y); + if (is_picksel) GPU_select_load_id(MAN_TRANS_Y); else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); glRotatef(-90.0, 1.0, 0.0, 0.0); draw_cone(qobj, cylen, cywid); @@ -1503,7 +1505,7 @@ static void draw_manipulator_rotate_cyl( unit_m4(unitmat); - if (is_picksel) glLoadName(MAN_ROT_V); + if (is_picksel) GPU_select_load_id(MAN_ROT_V); UI_ThemeColor(TH_TRANSFORM); drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat); @@ -1556,7 +1558,7 @@ static void draw_manipulator_rotate_cyl( case 0: /* X cylinder */ if (drawflags & MAN_ROT_X) { glTranslatef(1.0, 0.0, 0.0); - if (is_picksel) glLoadName(MAN_ROT_X); + if (is_picksel) GPU_select_load_id(MAN_ROT_X); glRotatef(90.0, 0.0, 1.0, 0.0); manipulator_setcolor(v3d, 'X', colcode, 255); draw_cylinder(qobj, cylen, cywid); @@ -1567,7 +1569,7 @@ static void draw_manipulator_rotate_cyl( case 1: /* Y cylinder */ if (drawflags & MAN_ROT_Y) { glTranslatef(0.0, 1.0, 0.0); - if (is_picksel) glLoadName(MAN_ROT_Y); + if (is_picksel) GPU_select_load_id(MAN_ROT_Y); glRotatef(-90.0, 1.0, 0.0, 0.0); manipulator_setcolor(v3d, 'Y', colcode, 255); draw_cylinder(qobj, cylen, cywid); @@ -1578,7 +1580,7 @@ static void draw_manipulator_rotate_cyl( case 2: /* Z cylinder */ if (drawflags & MAN_ROT_Z) { glTranslatef(0.0, 0.0, 1.0); - if (is_picksel) glLoadName(MAN_ROT_Z); + if (is_picksel) GPU_select_load_id(MAN_ROT_Z); manipulator_setcolor(v3d, 'Z', colcode, 255); draw_cylinder(qobj, cylen, cywid); glTranslatef(0.0, 0.0, -1.0); @@ -1689,10 +1691,11 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl { View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; - rctf rect; + rctf rect, selrect; GLuint buffer[64]; // max 4 items per select, so large enuf short hits; const bool is_picksel = true; + const bool do_passes = GPU_select_query_check_active(); /* XXX check a bit later on this... (ton) */ extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect); @@ -1707,13 +1710,15 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl rect.ymin = mval[1] - hotspot; rect.ymax = mval[1] + hotspot; + selrect = rect; + view3d_winmatrix_set(ar, v3d, &rect); mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); - glSelectBuffer(64, buffer); - glRenderMode(GL_SELECT); - glInitNames(); /* these two calls whatfor? It doesn't work otherwise */ - glPushName(-2); + if (do_passes) + GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0); + else + GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_ALL, 0); /* do the drawing */ if (v3d->twtype & V3D_MANIP_ROTATE) { @@ -1725,8 +1730,23 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl if (v3d->twtype & V3D_MANIP_TRANSLATE) draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); - glPopName(); - hits = glRenderMode(GL_RENDER); + hits = GPU_select_end(); + + if (do_passes) { + GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits); + + /* do the drawing */ + if (v3d->twtype & V3D_MANIP_ROTATE) { + if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); + else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, false, is_picksel); + } + if (v3d->twtype & V3D_MANIP_SCALE) + draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); + if (v3d->twtype & V3D_MANIP_TRANSLATE) + draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); + + GPU_select_end(); + } view3d_winmatrix_set(ar, v3d, NULL); mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 7bdbbf7289d..81e065ee33a 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_mesh_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -49,6 +50,8 @@ #include "UI_resources.h" #include "ED_screen.h" +/* for USE_LOOPSLIDE_HACK only */ +#include "ED_mesh.h" #include "transform.h" @@ -881,6 +884,27 @@ static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot) Transform_Properties(ot, P_SNAP); } +static int edge_bevelweight_exec(bContext *C, wmOperator *op) +{ + Mesh *me = (Mesh *)CTX_data_edit_object(C)->data; + + /* auto-enable bevel edge weight drawing, then chain to common transform code */ + me->drawflag |= ME_DRAWBWEIGHTS; + + return transform_exec(C, op); +} + +static int edge_bevelweight_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Mesh *me = (Mesh *)CTX_data_edit_object(C)->data; + + /* auto-enable bevel edge weight drawing, then chain to common transform code */ + me->drawflag |= ME_DRAWBWEIGHTS; + + return transform_invoke(C, op, event); +} + + static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot) { /* identifiers */ @@ -890,8 +914,8 @@ static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; /* api callbacks */ - ot->invoke = transform_invoke; - ot->exec = transform_exec; + ot->invoke = edge_bevelweight_invoke; + ot->exec = edge_bevelweight_exec; ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_editmesh; diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index ba90926df3b..69d135b8550 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -756,7 +756,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], if (flag) { float tvec[3]; if ((v3d->around == V3D_LOCAL) || - ELEM3(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3)) + ELEM(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); diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 451837fd311..abef2c9fc30 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -117,8 +117,8 @@ int BIF_snappingSupported(Object *obedit) { int status = 0; - if (obedit == NULL || ELEM5(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) /* only support object mesh, armature, curves */ - { + /* only support object mesh, armature, curves */ + if (obedit == NULL || ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) { status = 1; } @@ -337,6 +337,46 @@ void applyProject(TransInfo *t) mul_m3_v3(td->smtx, tvec); add_v3_v3(td->loc, tvec); + + if (t->tsnap.align && (t->flag & T_OBJECT)) { + /* handle alignment as well */ + const float *original_normal; + float axis[3]; + float mat[3][3]; + float angle; + float totmat[3][3], smat[3][3]; + float eul[3], fmat[3][3], quat[4]; + float obmat[3][3]; + + /* In pose mode, we want to align normals with Y axis of bones... */ + original_normal = td->axismtx[2]; + + cross_v3_v3v3(axis, original_normal, no); + angle = saacos(dot_v3v3(original_normal, no)); + + axis_angle_to_quat(quat, axis, angle); + + quat_to_mat3(mat, quat); + + mul_m3_m3m3(totmat, mat, td->mtx); + mul_m3_m3m3(smat, td->smtx, totmat); + + /* calculate the total rotatation in eulers */ + add_v3_v3v3(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */ + eulO_to_mat3(obmat, eul, td->ext->rotOrder); + /* mat = transform, obmat = object rotation */ + mul_m3_m3m3(fmat, smat, obmat); + + mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat); + + /* correct back for delta rot */ + sub_v3_v3v3(eul, eul, td->ext->drot); + + /* and apply */ + copy_v3_v3(td->ext->rot, eul); + + /* TODO support constraints for rotation too? see ElementRotation */ + } } } @@ -505,7 +545,7 @@ static void initSnappingMode(TransInfo *t) /* Edit mode */ if (t->tsnap.applySnap != NULL && // A snapping function actually exist - (obedit != NULL && ELEM5(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs + (obedit != NULL && ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs { /* Exclude editmesh if using proportional edit */ if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) { @@ -588,7 +628,7 @@ void initSnapping(TransInfo *t, wmOperator *op) } /* use scene defaults only when transform is modal */ else if (t->flag & T_MODAL) { - if (ELEM3(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) { + if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) { if (ts->snap_flag & SCE_SNAP) { t->modifiers |= MOD_SNAP; } @@ -658,7 +698,8 @@ static void setSnappingCallback(TransInfo *t) void addSnapPoint(TransInfo *t) { - if (t->tsnap.status & POINT_INIT) { + /* Currently only 3D viewport works for snapping points. */ + if (t->tsnap.status & POINT_INIT && t->spacetype == SPACE_VIEW3D) { TransSnapPoint *p = MEM_callocN(sizeof(TransSnapPoint), "SnapPoint"); t->tsnap.selectedPoint = p; @@ -1492,6 +1533,8 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes const float mval[2], float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth, bool do_bb) { bool retval = false; + const bool do_ray_start_correction = (snap_mode == SCE_SNAP_MODE_FACE && ar && + !((RegionView3D *)ar->regiondata)->is_persp); int totvert = dm->getNumVerts(dm); if (totvert > 0) { @@ -1518,6 +1561,28 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes return retval; } } + else if (do_ray_start_correction) { + /* We *need* a reasonably valid len_diff in this case. + * Use BHVTree to find the closest face from ray_start_local. + */ + BVHTreeFromMesh treeData; + BVHTreeNearest nearest; + len_diff = 0.0f; /* In case BVHTree would fail for some reason... */ + + treeData.em_evil = em; + bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 2, 6); + if (treeData.tree != NULL) { + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + /* Compute and store result. */ + BLI_bvhtree_find_nearest(treeData.tree, ray_start_local, &nearest, + treeData.nearest_callback, &treeData); + if (nearest.index != -1) { + len_diff = sqrtf(nearest.dist_sq); + } + } + free_bvhtree_from_mesh(&treeData); + } switch (snap_mode) { case SCE_SNAP_MODE_FACE: @@ -1529,7 +1594,7 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes * been *inside* boundbox, leading to snap failures (see T38409). * Note also ar might be null (see T38435), in this case we assume ray_start is ok! */ - if (ar && !((RegionView3D *)ar->regiondata)->is_persp) { + if (do_ray_start_correction) { float ray_org_local[3]; copy_v3_v3(ray_org_local, ray_origin); @@ -2383,6 +2448,9 @@ static void applyGridIncrement(TransInfo *t, float *val, int max_index, float fa if (t->options & CTX_MASK) { ED_space_image_get_aspect(t->sa->spacedata.first, asp, asp + 1); } + else if (t->options & CTX_PAINT_CURVE) { + asp[0] = asp[1] = 1.0; + } else { ED_space_image_get_uv_aspect(t->sa->spacedata.first, asp, asp + 1); } diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c index 3bd927e5b25..104b628c25a 100644 --- a/source/blender/editors/util/ed_transverts.c +++ b/source/blender/editors/util/ed_transverts.c @@ -192,7 +192,7 @@ static void set_mapped_co(void *vuserdata, int index, const float co[3], bool ED_transverts_check_obedit(Object *obedit) { - return (ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)); + return (ELEM(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)); } void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const int mode) diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 47fbfbe3eba..56b12fcdcda 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -86,7 +86,7 @@ void ED_editors_init(bContext *C) /* This is called during initialization, so we don't want to store any reports */ ReportList *reports = CTX_wm_reports(C); - int reports_flag_prev = reports->flag &= ~RPT_STORE; + int reports_flag_prev = reports->flag & ~RPT_STORE; SWAP(int, reports->flag, reports_flag_prev); diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c index a618ab8419b..a154f12a786 100644 --- a/source/blender/editors/util/numinput.c +++ b/source/blender/editors/util/numinput.c @@ -33,6 +33,7 @@ #include "BLI_string_cursor_utf8.h" #include "BKE_context.h" +#include "BKE_scene.h" #include "BKE_unit.h" #include "DNA_scene_types.h" @@ -87,7 +88,7 @@ void initNumInput(NumInput *n) } /* str must be NUM_STR_REP_LEN * (idx_max + 1) length. */ -void outputNumInput(NumInput *n, char *str, const float scale_length) +void outputNumInput(NumInput *n, char *str, UnitSettings *unit_settings) { short j; const int ln = NUM_STR_REP_LEN; @@ -98,7 +99,7 @@ void outputNumInput(NumInput *n, char *str, const float scale_length) const short i = (n->flag & NUM_AFFECT_ALL && n->idx != j && !(n->val_flag[j] & NUM_EDITED)) ? 0 : j; /* Use scale_length if needed! */ - const float fac = ELEM3(n->unit_type[j], B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME) ? scale_length : 1.0f; + const float fac = (float)BKE_scene_unit_scale(unit_settings, n->unit_type[j], 1.0); if (n->val_flag[i] & NUM_EDITED) { /* Get the best precision, allows us to draw '10.0001' as '10' instead! */ @@ -189,15 +190,15 @@ bool applyNumInput(NumInput *n, float *vec) if (n->val_flag[i] & NUM_NO_NEGATIVE && val < 0.0f) { val = 0.0f; } - if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) { - val = 0.0001f; - } if (n->val_flag[i] & NUM_NO_FRACTION && val != floorf(val)) { val = floorf(val + 0.5f); if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) { val = 1.0f; } } + else if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) { + val = 0.0001f; + } } vec[j] = val; } @@ -442,6 +443,13 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event) } } + /* Up to this point, if we have a ctrl modifier, skip. + * This allows to still access most of modals' shortcuts even in numinput mode. + */ + if (!updated && event->ctrl) { + return false; + } + if ((!utf8_buf || !utf8_buf[0]) && ascii[0]) { /* Fallback to ascii. */ utf8_buf = ascii; @@ -471,26 +479,24 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event) #ifdef WITH_PYTHON Scene *sce = CTX_data_scene(C); double val; - float fac = 1.0f; char str_unit_convert[NUM_STR_REP_LEN * 6]; /* Should be more than enough! */ const char *default_unit = NULL; + /* Use scale_length if needed! */ + const float fac = (float)BKE_scene_unit_scale(&sce->unit, n->unit_type[idx], 1.0); + /* Make radian default unit when needed. */ if (n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) default_unit = "r"; - /* Use scale_length if needed! */ - if (ELEM3(n->unit_type[idx], B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) - fac /= sce->unit.scale_length; - BLI_strncpy(str_unit_convert, n->str, sizeof(str_unit_convert)); - bUnit_ReplaceString(str_unit_convert, sizeof(str_unit_convert), default_unit, 1.0, + bUnit_ReplaceString(str_unit_convert, sizeof(str_unit_convert), default_unit, fac, n->unit_sys, n->unit_type[idx]); /* Note: with angles, we always get values as radians here... */ if (BPY_button_exec(C, str_unit_convert, &val, false) != -1) { - n->val[idx] = (float)val * fac; + n->val[idx] = (float)val; n->val_flag[idx] &= ~NUM_INVALID; } else { diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index e2f25a2a8ae..8d46d9ac7cf 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -33,6 +33,7 @@ #include <stdlib.h> #include <string.h> +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -48,6 +49,8 @@ #include "BKE_DerivedMesh.h" #include "BKE_editmesh.h" +#include "BKE_material.h" + #include "BKE_scene.h" #include "BIF_gl.h" @@ -403,20 +406,28 @@ static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage) int a; BLI_bitmap *mat_test_array; bool ok = false; + int totcol = 0; if (me->mloopuv == NULL) { return; } - if (ob->totcol == 0) { + if (curimage && ob->totcol == 0) { return; } - mat_test_array = BLI_BITMAP_NEW_ALLOCA(ob->totcol); + totcol = max_ii(ob->totcol, 1); + mat_test_array = BLI_BITMAP_NEW_ALLOCA(totcol); - for (a = 0; a < ob->totcol; a++) { + for (a = 0; a < totcol; a++) { Image *image; - ED_object_get_active_image(ob, a + 1, &image, NULL, NULL); + + /* if no materials, assume a default material with no image */ + if (ob->totcol) + ED_object_get_active_image(ob, a + 1, &image, NULL, NULL, NULL); + else + image = NULL; + if (image == curimage) { BLI_BITMAP_ENABLE(mat_test_array, a); ok = true; @@ -429,7 +440,7 @@ static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage) for (a = me->totpoly; a != 0; a--, mpoly++) { const int mat_nr = mpoly->mat_nr; - if ((mat_nr >= ob->totcol) || + if ((mat_nr >= totcol) || (BLI_BITMAP_TEST(mat_test_array, mat_nr)) == 0) { continue; @@ -471,13 +482,39 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob) { const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); Image *curimage = ED_space_image(sima); + Mesh *me = ob->data; + Material *ma; if (sima->flag & SI_DRAW_OTHER) { draw_uvs_other(scene, ob, curimage, new_shading_nodes); } UI_ThemeColor(TH_UV_SHADOW); - draw_uvs_other_mesh(ob, curimage, new_shading_nodes); + + ma = give_current_material(ob, ob->actcol); + + if (me->mtpoly) { + MPoly *mpoly = me->mpoly; + MLoopUV *mloopuv, *mloopuv_base; + int a, b; + if (!(ma && ma->texpaintslot && ma->texpaintslot[ma->paint_active_slot].uvname && + (mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, ma->texpaintslot[ma->paint_active_slot].uvname)))) + { + mloopuv = me->mloopuv; + } + + mloopuv_base = mloopuv; + + for (a = me->totpoly; a > 0; a--, mpoly++) { + glBegin(GL_LINE_LOOP); + + mloopuv = mloopuv_base + mpoly->loopstart; + for (b = 0; b < mpoly->totloop; b++, mloopuv++) { + glVertex2fv(mloopuv->uv); + } + glEnd(); + } + } } #ifdef USE_EDBM_LOOPTRIS @@ -540,7 +577,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) if (new_shading_nodes) { if (efa_act) { - ED_object_get_active_image(obedit, efa_act->mat_nr + 1, &curimage, NULL, NULL); + ED_object_get_active_image(obedit, efa_act->mat_nr + 1, &curimage, NULL, NULL, NULL); } else { curimage = ima; @@ -911,7 +948,7 @@ void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedi ToolSettings *toolsettings = scene->toolsettings; int show_uvedit, show_uvshadow, show_texpaint_uvshadow; - show_texpaint_uvshadow = (obact && obact->type == OB_MESH && obact->mode == OB_MODE_TEXTURE_PAINT); + show_texpaint_uvshadow = ED_space_image_show_texpaint(sima, obact); show_uvedit = ED_space_image_show_uvedit(sima, obedit); show_uvshadow = ED_space_image_show_uvshadow(sima, obedit); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 6cf34d9f93f..4b341547370 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -137,21 +137,24 @@ static bool is_image_texture_node(bNode *node) } bool ED_object_get_active_image(Object *ob, int mat_nr, - Image **r_ima, ImageUser **r_iuser, bNode **r_node) + Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree) { Material *ma = give_current_material(ob, mat_nr); - bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL; + bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL; + bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL; if (node && is_image_texture_node(node)) { if (r_ima) *r_ima = (Image *)node->id; if (r_iuser) *r_iuser = NULL; if (r_node) *r_node = node; + if (r_ntree) *r_ntree = ntree; return true; } if (r_ima) *r_ima = NULL; if (r_iuser) *r_iuser = NULL; if (r_node) *r_node = node; + if (r_ntree) *r_ntree = ntree; return false; } @@ -3033,7 +3036,8 @@ static void UV_OT_circle_select(wmOperatorType *ot) /* ******************** lasso select operator **************** */ -static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves, const bool select) +static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves, + const bool select, const bool extend) { SpaceImage *sima = CTX_wm_space_image(C); Image *ima = CTX_data_edit_image(C); @@ -3060,6 +3064,10 @@ static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short mo BLI_lasso_boundbox(&rect, mcords, moves); + if (!extend && select) { + uv_select_all_perform(scene, ima, em, SEL_DESELECT); + } + if (use_face_center) { /* Face Center Sel */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BM_elem_flag_disable(efa, BM_ELEM_TAG); @@ -3122,11 +3130,12 @@ static int uv_lasso_select_exec(bContext *C, wmOperator *op) const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); if (mcords) { - bool select; + bool select, extend; bool changed; select = !RNA_boolean_get(op->ptr, "deselect"); - changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, select); + extend = RNA_boolean_get(op->ptr, "extend"); + changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, select, extend); MEM_freeN((void *)mcords); @@ -3827,7 +3836,8 @@ static void UV_OT_reveal(wmOperatorType *ot) static int uv_set_2d_cursor_poll(bContext *C) { return ED_operator_uvedit_space_image(C) || - ED_space_image_maskedit_poll(C); + ED_space_image_maskedit_poll(C) || + ED_space_image_paint_curve(C); } static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 21e7bb00204..335d8e6589e 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -201,7 +201,7 @@ void uvedit_get_aspect(Scene *scene, Object *ob, BMEditMesh *em, float *aspx, fl if (efa) { if (BKE_scene_use_new_shading_nodes(scene)) { - ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL); + ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL); } else { MTexPoly *tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); @@ -938,7 +938,7 @@ static void uv_map_rotation_matrix(float result[4][4], RegionView3D *rv3d, Objec rotup[0][0] = 1.0f / radius; /* calculate transforms*/ - mul_serie_m4(result, rotup, rotside, viewmatrix, rotobj, NULL, NULL, NULL, NULL); + mul_m4_series(result, rotup, rotside, viewmatrix, rotobj); } static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float rotmat[4][4]) diff --git a/source/blender/freestyle/FRS_freestyle.h b/source/blender/freestyle/FRS_freestyle.h index 7be51b37f7a..fc9fc35e410 100644 --- a/source/blender/freestyle/FRS_freestyle.h +++ b/source/blender/freestyle/FRS_freestyle.h @@ -30,8 +30,9 @@ extern "C" { #endif struct Render; +struct Material; struct FreestyleConfig; -struct bContext; +struct FreestyleLineStyle; extern struct Scene *freestyle_scene; extern float freestyle_viewpoint[3]; @@ -57,6 +58,9 @@ void FRS_delete_active_lineset(struct FreestyleConfig *config); void FRS_move_active_lineset_up(struct FreestyleConfig *config); void FRS_move_active_lineset_down(struct FreestyleConfig *config); +/* Testing */ +struct Material *FRS_create_stroke_material(struct Main *bmain, struct FreestyleLineStyle *linestyle); + #ifdef __cplusplus } #endif diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp index dbbc4f77c26..57882cbce0c 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp @@ -449,7 +449,7 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id) return; // We allocate memory for the meshes to be imported - NodeTransform *currentMesh = new NodeTransform; + NodeGroup *currentMesh = new NodeGroup; NodeShape *shape = new NodeShape; unsigned vSize = 3 * 3 * numFaces; @@ -799,10 +799,6 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id) rep->setBBox(bbox); shape->AddRep(rep); - Matrix44r meshMat = Matrix44r::identity(); - currentMesh->setMatrix(meshMat); - currentMesh->Translate(0, 0, 0); - currentMesh->AddChild(shape); _Scene->AddChild(currentMesh); } diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index d47f4e5d910..47b0c9b1e48 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -30,26 +30,35 @@ extern "C" { #include "MEM_guardedalloc.h" +#include "RNA_access.h" + #include "DNA_camera_types.h" #include "DNA_listBase.h" +#include "DNA_linestyle_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_mesh_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" +#include "DNA_scene_types.h" #include "BKE_customdata.h" #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_library.h" /* free_libblock */ -#include "BKE_main.h" /* struct Main */ #include "BKE_material.h" #include "BKE_mesh.h" +#include "BKE_node.h" #include "BKE_object.h" #include "BKE_scene.h" +#include "BLI_ghash.h" +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "RE_pipeline.h" + +#include "render_types.h" } #include <limits.h> @@ -133,6 +142,15 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str // Reset serial mesh ID (used for BlenderStrokeRenderer::NewMesh()) _mesh_id = 0xffffffff; + + // Check if the rendering engine uses new shading nodes + _use_shading_nodes = BKE_scene_use_new_shading_nodes(freestyle_scene); + + // Create a bNodeTree-to-Material hash table + if (_use_shading_nodes) + _nodetree_hash = BLI_ghash_ptr_new("BlenderStrokeRenderer::_nodetree_hash"); + else + _nodetree_hash = NULL; } BlenderStrokeRenderer::~BlenderStrokeRenderer() @@ -186,6 +204,9 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer() lnk = lnk->next; BKE_libblock_free(freestyle_bmain, ma); } + + if (_use_shading_nodes) + BLI_ghash_free(_nodetree_hash, NULL, NULL); } float BlenderStrokeRenderer::get_stroke_vertex_z(void) const @@ -206,55 +227,283 @@ unsigned int BlenderStrokeRenderer::get_stroke_mesh_id(void) const return mesh_id; } -void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const +Material* BlenderStrokeRenderer::GetStrokeShader(Main *bmain, bNodeTree *iNodeTree, bool do_id_user) { - bool has_mat = false; - int a = 0; - - // Look for a good existing material - for (Link *lnk = (Link *)freestyle_bmain->mat.first; lnk; lnk = lnk->next) { - Material *ma = (Material*) lnk; - bool texs_are_good = true; - // as soon as textures differ it's not the right one - for (int a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a] != iStrokeRep->getMTex(a)) { - texs_are_good = false; + Material *ma = BKE_material_add(bmain, "stroke_shader"); + bNodeTree *ntree; + bNode *output_linestyle = NULL; + bNodeSocket *fromsock, *tosock; + PointerRNA fromptr, toptr; + NodeShaderAttribute *storage; + + if (iNodeTree) { + // make a copy of linestyle->nodetree + ntree = ntreeCopyTree_ex(iNodeTree, bmain, do_id_user); + + // find the active Output Line Style node + for (bNode *node = (bNode *)ntree->nodes.first; node; node = node->next) { + if (node->type == SH_NODE_OUTPUT_LINESTYLE && (node->flag & NODE_DO_OUTPUT)) { + output_linestyle = node; break; } } + } + else { + ntree = ntreeAddTree(NULL, "stroke_shader", "ShaderNodeTree"); + } + ma->nodetree = ntree; + ma->use_nodes = 1; + + bNode *input_attr_color = nodeAddStaticNode(NULL, ntree, SH_NODE_ATTRIBUTE); + input_attr_color->locx = 0.0f; + input_attr_color->locy = -200.0f; + storage = (NodeShaderAttribute *)input_attr_color->storage; + BLI_strncpy(storage->name, "Color", sizeof(storage->name)); + + bNode *mix_rgb_color = nodeAddStaticNode(NULL, ntree, SH_NODE_MIX_RGB); + mix_rgb_color->custom1 = MA_RAMP_BLEND; // Mix + mix_rgb_color->locx = 200.0f; + mix_rgb_color->locy = -200.0f; + tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 0); // Fac + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr); + RNA_float_set(&toptr, "default_value", 0.0f); + + bNode *input_attr_alpha = nodeAddStaticNode(NULL, ntree, SH_NODE_ATTRIBUTE); + input_attr_alpha->locx = 400.0f; + input_attr_alpha->locy = 300.0f; + storage = (NodeShaderAttribute *)input_attr_alpha->storage; + BLI_strncpy(storage->name, "Alpha", sizeof(storage->name)); + + bNode *mix_rgb_alpha = nodeAddStaticNode(NULL, ntree, SH_NODE_MIX_RGB); + mix_rgb_alpha->custom1 = MA_RAMP_BLEND; // Mix + mix_rgb_alpha->locx = 600.0f; + mix_rgb_alpha->locy = 300.0f; + tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 0); // Fac + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr); + RNA_float_set(&toptr, "default_value", 0.0f); + + bNode *shader_emission = nodeAddStaticNode(NULL, ntree, SH_NODE_EMISSION); + shader_emission->locx = 400.0f; + shader_emission->locy = -200.0f; + + bNode *input_light_path = nodeAddStaticNode(NULL, ntree, SH_NODE_LIGHT_PATH); + input_light_path->locx = 400.0f; + input_light_path->locy = 100.0f; + + bNode *mix_shader_color = nodeAddStaticNode(NULL, ntree, SH_NODE_MIX_SHADER); + mix_shader_color->locx = 600.0f; + mix_shader_color->locy = -100.0f; + + bNode *shader_transparent = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_TRANSPARENT); + shader_transparent->locx = 600.0f; + shader_transparent->locy = 100.0f; + + bNode *mix_shader_alpha = nodeAddStaticNode(NULL, ntree, SH_NODE_MIX_SHADER); + mix_shader_alpha->locx = 800.0f; + mix_shader_alpha->locy = 100.0f; + + bNode *output_material = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); + output_material->locx = 1000.0f; + output_material->locy = 100.0f; + + fromsock = (bNodeSocket *)BLI_findlink(&input_attr_color->outputs, 0); // Color + tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 1); // Color1 + nodeAddLink(ntree, input_attr_color, fromsock, mix_rgb_color, tosock); + + fromsock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->outputs, 0); // Color + tosock = (bNodeSocket *)BLI_findlink(&shader_emission->inputs, 0); // Color + nodeAddLink(ntree, mix_rgb_color, fromsock, shader_emission, tosock); + + fromsock = (bNodeSocket *)BLI_findlink(&shader_emission->outputs, 0); // Emission + tosock = (bNodeSocket *)BLI_findlink(&mix_shader_color->inputs, 2); // Shader (second) + nodeAddLink(ntree, shader_emission, fromsock, mix_shader_color, tosock); + + fromsock = (bNodeSocket *)BLI_findlink(&input_light_path->outputs, 0); // In Camera Ray + tosock = (bNodeSocket *)BLI_findlink(&mix_shader_color->inputs, 0); // Fac + nodeAddLink(ntree, input_light_path, fromsock, mix_shader_color, tosock); + + fromsock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->outputs, 0); // Color + tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 0); // Fac + nodeAddLink(ntree, mix_rgb_alpha, fromsock, mix_shader_alpha, tosock); + + fromsock = (bNodeSocket *)BLI_findlink(&input_attr_alpha->outputs, 0); // Color + tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 1); // Color1 + nodeAddLink(ntree, input_attr_alpha, fromsock, mix_rgb_alpha, tosock); + + fromsock = (bNodeSocket *)BLI_findlink(&shader_transparent->outputs, 0); // BSDF + tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 1); // Shader (first) + nodeAddLink(ntree, shader_transparent, fromsock, mix_shader_alpha, tosock); + + fromsock = (bNodeSocket *)BLI_findlink(&mix_shader_color->outputs, 0); // Shader + tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 2); // Shader (second) + nodeAddLink(ntree, mix_shader_color, fromsock, mix_shader_alpha, tosock); + + fromsock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->outputs, 0); // Shader + tosock = (bNodeSocket *)BLI_findlink(&output_material->inputs, 0); // Surface + nodeAddLink(ntree, mix_shader_alpha, fromsock, output_material, tosock); + + if (output_linestyle) { + bNodeSocket *outsock; + bNodeLink *link; + + mix_rgb_color->custom1 = output_linestyle->custom1; // blend_type + mix_rgb_color->custom2 = output_linestyle->custom2; // use_clamp + + outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 0); // Color + tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 2); // Color2 + link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock)); + if (link) { + nodeAddLink(ntree, link->fromnode, link->fromsock, mix_rgb_color, tosock); + } + else { + float color[4]; + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, outsock, &fromptr); + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr); + RNA_float_get_array(&fromptr, "default_value", color); + RNA_float_set_array(&toptr, "default_value", color); + } - if (texs_are_good) { - iStrokeRep->setMaterial(ma); - has_mat = true; - break; // if textures are good, no need to search anymore + outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 1); // Color Fac + tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 0); // Fac + link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock)); + if (link) { + nodeAddLink(ntree, link->fromnode, link->fromsock, mix_rgb_color, tosock); + } + else { + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, outsock, &fromptr); + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr); + RNA_float_set(&toptr, "default_value", RNA_float_get(&fromptr, "default_value")); + } + + outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 2); // Alpha + tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 2); // Color2 + link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock)); + if (link) { + nodeAddLink(ntree, link->fromnode, link->fromsock, mix_rgb_alpha, tosock); + } + else { + float color[4]; + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, outsock, &fromptr); + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr); + color[0] = color[1] = color[2] = RNA_float_get(&fromptr, "default_value"); + color[3] = 1.0f; + RNA_float_set_array(&toptr, "default_value", color); + } + + outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 3); // Alpha Fac + tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 0); // Fac + link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock)); + if (link) { + nodeAddLink(ntree, link->fromnode, link->fromsock, mix_rgb_alpha, tosock); + } + else { + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, outsock, &fromptr); + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr); + RNA_float_set(&toptr, "default_value", RNA_float_get(&fromptr, "default_value")); + } + + for (bNode *node = (bNode *)ntree->nodes.first; node; node = node->next) { + if (node->type == SH_NODE_UVALONGSTROKE) { + // UV output of the UV Along Stroke node + bNodeSocket *sock = (bNodeSocket *)BLI_findlink(&node->outputs, 0); + + // add new UV Map node + bNode *input_uvmap = nodeAddStaticNode(NULL, ntree, SH_NODE_UVMAP); + input_uvmap->locx = node->locx - 200.0f; + input_uvmap->locy = node->locy; + NodeShaderUVMap *storage = (NodeShaderUVMap *)input_uvmap->storage; + if (node->custom1 & 1) { // use_tips + BLI_strncpy(storage->uv_map, "along_stroke_tips", sizeof(storage->uv_map)); + } + else { + BLI_strncpy(storage->uv_map, "along_stroke", sizeof(storage->uv_map)); + } + fromsock = (bNodeSocket *)BLI_findlink(&input_uvmap->outputs, 0); // UV + + // replace links from the UV Along Stroke node by links from the UV Map node + for (bNodeLink *link = (bNodeLink *)ntree->links.first; link; link = link->next) { + if (link->fromnode == node && link->fromsock == sock) { + nodeAddLink(ntree, input_uvmap, fromsock, link->tonode, link->tosock); + } + } + nodeRemSocketLinks(ntree, sock); + } } } - // If still no material, create one - if (!has_mat) { - Material *ma = BKE_material_add(freestyle_bmain, "stroke_material"); + nodeSetActive(ntree, output_material); + ntreeUpdateTree(bmain, ntree); - ma->mode |= MA_VERTEXCOLP; - ma->mode |= MA_TRANSP; - ma->mode |= MA_SHLESS; - ma->vcol_alpha = 1; + return ma; +} - // Textures - //for (int a = 0; a < MAX_MTEX; a++) { - while (iStrokeRep->getMTex(a)) { - ma->mtex[a] = (MTex *) iStrokeRep->getMTex(a); +void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const +{ + if (_use_shading_nodes) { + bNodeTree *nt = iStrokeRep->getNodeTree(); + Material *ma = (Material *)BLI_ghash_lookup(_nodetree_hash, nt); + if (!ma) { + ma = BlenderStrokeRenderer::GetStrokeShader(freestyle_bmain, nt, false); + BLI_ghash_insert(_nodetree_hash, nt, ma); + } + + if (strcmp(freestyle_scene->r.engine, "CYCLES") == 0) { + PointerRNA scene_ptr; + RNA_pointer_create(NULL, &RNA_Scene, freestyle_scene, &scene_ptr); + PointerRNA cycles_ptr = RNA_pointer_get(&scene_ptr, "cycles"); + RNA_boolean_set(&cycles_ptr, "film_transparent", 1); + } - // We'll generate both with tips and without tips - // coordinates, on two different UV layers. - if (ma->mtex[a]->texflag & MTEX_TIPS) { - BLI_strncpy(ma->mtex[a]->uvname, "along_stroke_tips", sizeof(ma->mtex[a]->uvname)); + iStrokeRep->setMaterial(ma); + } + else { + bool has_mat = false; + int a = 0; + + // Look for a good existing material + for (Link *lnk = (Link *)freestyle_bmain->mat.first; lnk; lnk = lnk->next) { + Material *ma = (Material*)lnk; + bool texs_are_good = true; + // as soon as textures differ it's not the right one + for (int a = 0; a < MAX_MTEX; a++) { + if (ma->mtex[a] != iStrokeRep->getMTex(a)) { + texs_are_good = false; + break; + } } - else { - BLI_strncpy(ma->mtex[a]->uvname, "along_stroke", sizeof(ma->mtex[a]->uvname)); + + if (texs_are_good) { + iStrokeRep->setMaterial(ma); + has_mat = true; + break; // if textures are good, no need to search anymore } - a++; } - iStrokeRep->setMaterial(ma); + + // If still no material, create one + if (!has_mat) { + Material *ma = BKE_material_add(freestyle_bmain, "stroke_material"); + ma->mode |= MA_VERTEXCOLP; + ma->mode |= MA_TRANSP; + ma->mode |= MA_SHLESS; + ma->vcol_alpha = 1; + + // Textures + while (iStrokeRep->getMTex(a)) { + ma->mtex[a] = (MTex *)iStrokeRep->getMTex(a); + + // We'll generate both with tips and without tips + // coordinates, on two different UV layers. + if (ma->mtex[a]->texflag & MTEX_TIPS) { + BLI_strncpy(ma->mtex[a]->uvname, "along_stroke_tips", sizeof(ma->mtex[a]->uvname)); + } + else { + BLI_strncpy(ma->mtex[a]->uvname, "along_stroke", sizeof(ma->mtex[a]->uvname)); + } + a++; + } + + iStrokeRep->setMaterial(ma); + } } RenderStrokeRepBasic(iStrokeRep); @@ -318,7 +567,7 @@ void BlenderStrokeRenderer::test_strip_visibility(Strip::vertex_container& strip void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const { vector<Strip*>& strips = iStrokeRep->getStrips(); - const bool hasTex = iStrokeRep->getMTex(0) != NULL; + const bool hasTex = iStrokeRep->hasTex(); Strip::vertex_container::iterator v[3]; StrokeVertexRep *svRep[3]; unsigned int vertex_index, edge_index, loop_index; @@ -355,22 +604,35 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const // vertices allocation mesh->totvert = totvert; // visible_faces + visible_segments * 2; - mesh->mvert = (MVert *)CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert); + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert); // edges allocation mesh->totedge = totedge; // visible_faces * 2 + visible_segments; - mesh->medge = (MEdge *)CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge); + CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge); // faces allocation mesh->totpoly = totpoly; // visible_faces; - mesh->mpoly = (MPoly *)CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly); // loops allocation mesh->totloop = totloop; // visible_faces * 3; - mesh->mloop = (MLoop *)CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop); - // colors allocation - mesh->mloopcol = (MLoopCol *)CustomData_add_layer(&mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop); + // uv maps + MLoopUV *loopsuv[2] = { NULL }; + if (hasTex) { + loopsuv[0] = (MLoopUV *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke"); + loopsuv[1] = (MLoopUV *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke_tips"); + + CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke"); + CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke_tips"); + } + + // colors and transparency (the latter represented by grayscale colors) + MLoopCol *colors = (MLoopCol *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop, "Color"); + MLoopCol *transp = (MLoopCol *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop, "Alpha"); + + BKE_mesh_update_customdata_pointers(mesh, true); //////////////////// // Data copy @@ -380,28 +642,6 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const MEdge *edges = mesh->medge; MPoly *polys = mesh->mpoly; MLoop *loops = mesh->mloop; - MLoopCol *colors = mesh->mloopcol; - MLoopUV *loopsuv[2] = {NULL}; - - if (hasTex) { - // First UV layer - CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke"); - CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke"); - CustomData_set_layer_active(&mesh->pdata, CD_MTEXPOLY, 0); - CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 0); - BKE_mesh_update_customdata_pointers(mesh, true); - - loopsuv[0] = mesh->mloopuv; - - // Second UV layer - CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke_tips"); - CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke_tips"); - CustomData_set_layer_active(&mesh->pdata, CD_MTEXPOLY, 1); - CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 1); - BKE_mesh_update_customdata_pointers(mesh, true); - - loopsuv[1] = mesh->mloopuv; - } vertex_index = edge_index = loop_index = 0; @@ -540,7 +780,7 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const } } - // colors + // colors and alpha transparency if (is_odd) { colors[0].r = (short)(255.0f * svRep[2]->color()[0]); colors[0].g = (short)(255.0f * svRep[2]->color()[1]); @@ -556,7 +796,7 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const colors[2].g = (short)(255.0f * svRep[1]->color()[1]); colors[2].b = (short)(255.0f * svRep[1]->color()[2]); colors[2].a = (short)(255.0f * svRep[1]->alpha()); - } + } else { colors[0].r = (short)(255.0f * svRep[2]->color()[0]); colors[0].g = (short)(255.0f * svRep[2]->color()[1]); @@ -573,7 +813,11 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const colors[2].b = (short)(255.0f * svRep[0]->color()[2]); colors[2].a = (short)(255.0f * svRep[0]->alpha()); } + transp[0].r = transp[0].g = transp[0].b = colors[0].a; + transp[1].r = transp[1].g = transp[1].b = colors[1].a; + transp[2].r = transp[2].g = transp[2].b = colors[2].a; colors += 3; + transp += 3; } } // loop over strip vertices } // loop over strips diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h index 0025d48e77f..74e5d321df2 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h @@ -29,12 +29,14 @@ #include "../system/FreestyleConfig.h" extern "C" { -#include "DNA_material_types.h" -#include "DNA_scene_types.h" - -#include "BKE_main.h" - -#include "render_types.h" +struct GHash; +struct Main; +struct Material; +struct Object; +struct Render; +struct Scene; +struct bContext; +struct bNodeTree; } namespace Freestyle { @@ -53,13 +55,18 @@ public: Render *RenderScene(Render *re, bool render); + static Material* GetStrokeShader(Main *bmain, bNodeTree *iNodeTree, bool do_id_user); + protected: Main *freestyle_bmain; Scene *old_scene; Scene *freestyle_scene; + bContext *_context; float _width, _height; float _z, _z_delta; unsigned int _mesh_id; + bool _use_shading_nodes; + struct GHash *_nodetree_hash; float get_stroke_vertex_z(void) const; unsigned int get_stroke_mesh_id(void) const; diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h b/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h index a1fb9fade58..21776396ebc 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h +++ b/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h @@ -29,10 +29,10 @@ #include "../system/PythonInterpreter.h" extern "C" { -#include "BKE_global.h" -#include "BKE_library.h" -#include "BKE_text.h" -#include "BLI_utildefines.h" +#include "BLI_utildefines.h" // BLI_assert() + +struct Scene; +struct Text; } namespace Freestyle { diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp index 9c2b5a4037f..32f49d48ee7 100644 --- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp +++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp @@ -31,6 +31,8 @@ #include "../application/AppView.h" #include "../application/Controller.h" +#include "BlenderStrokeRenderer.h" + using namespace std; using namespace Freestyle; @@ -41,6 +43,7 @@ extern "C" { #include "DNA_camera_types.h" #include "DNA_freestyle_types.h" #include "DNA_group_types.h" +#include "DNA_material_types.h" #include "DNA_text_types.h" #include "BKE_freestyle.h" @@ -730,4 +733,14 @@ void FRS_move_active_lineset_down(FreestyleConfig *config) } } +// Testing + +Material *FRS_create_stroke_material(Main *bmain, struct FreestyleLineStyle *linestyle) +{ + bNodeTree *nt = (linestyle->use_nodes) ? linestyle->nodetree : NULL; + Material *ma = BlenderStrokeRenderer::GetStrokeShader(bmain, nt, true); + ma->id.us = 0; + return ma; +} + } // extern "C" diff --git a/source/blender/freestyle/intern/geometry/Grid.h b/source/blender/freestyle/intern/geometry/Grid.h index c0cab2a05db..c1d04f6b4cc 100644 --- a/source/blender/freestyle/intern/geometry/Grid.h +++ b/source/blender/freestyle/intern/geometry/Grid.h @@ -30,9 +30,7 @@ #include <cstring> // for memset #include <float.h> -#if !defined(_MSC_VER) || _MSC_VER >= 1700 #include <stdint.h> // For SET_UINT_IN_POINTER, i.e. uintptr_t. -#endif #include <vector> #include "Geom.h" diff --git a/source/blender/freestyle/intern/python/BPy_Convert.cpp b/source/blender/freestyle/intern/python/BPy_Convert.cpp index 78c3599b7cd..dbd836bc562 100644 --- a/source/blender/freestyle/intern/python/BPy_Convert.cpp +++ b/source/blender/freestyle/intern/python/BPy_Convert.cpp @@ -387,9 +387,14 @@ PyObject *BPy_IntegrationType_from_IntegrationType(IntegrationType i) PyObject *BPy_CurvePoint_from_CurvePoint(CurvePoint& cp) { PyObject *py_cp = CurvePoint_Type.tp_new(&CurvePoint_Type, 0, 0); - ((BPy_CurvePoint *) py_cp)->cp = &cp; + // CurvePointIterator::operator*() returns a reference of a class data + // member whose value is mutable upon iteration over different CurvePoints. + // It is likely that such a mutable reference is passed to this function, + // so that a new allocated CurvePoint instance is created here to avoid + // nasty bugs (cf. T41464). + ((BPy_CurvePoint *) py_cp)->cp = new CurvePoint(cp); ((BPy_CurvePoint *) py_cp)->py_if0D.if0D = ((BPy_CurvePoint *)py_cp)->cp; - ((BPy_CurvePoint *) py_cp)->py_if0D.borrowed = true; + ((BPy_CurvePoint *) py_cp)->py_if0D.borrowed = false; return py_cp; } diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp index 2cfd3658189..5b8d50eb5eb 100644 --- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp +++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp @@ -60,6 +60,7 @@ extern "C" { #include "FRS_freestyle.h" #include "RNA_access.h" +#include "DNA_scene_types.h" #include "bpy_rna.h" /* pyrna_struct_CreatePyObject() */ static char Freestyle_getCurrentScene___doc__[] = @@ -77,7 +78,7 @@ static PyObject *Freestyle_getCurrentScene(PyObject *self) return NULL; } PointerRNA ptr_scene; - RNA_pointer_create(NULL, &RNA_Scene, freestyle_scene, &ptr_scene); + RNA_pointer_create(&freestyle_scene->id, &RNA_Scene, freestyle_scene, &ptr_scene); return pyrna_struct_CreatePyObject(&ptr_scene); } diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp index 36cdb1b92ff..1ef29792d56 100644 --- a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp +++ b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp @@ -178,6 +178,19 @@ static int CurvePoint_second_svertex_set(BPy_CurvePoint *self, PyObject *value, return 0; } +PyDoc_STRVAR(CurvePoint_fedge_doc, +"Gets the FEdge for the two SVertices that given CurvePoints consists out of.\n" +"A shortcut for CurvePoint.first_svertex.get_fedge(CurvePoint.second_svertex).\n" +"\n" +":type: :class:`FEdge`"); + +static PyObject *CurvePoint_fedge_get(BPy_CurvePoint *self, void *UNUSED(closure)) +{ + SVertex *A = self->cp->A(); + Interface0D *B = (Interface0D *)self->cp->B(); + return Any_BPy_Interface1D_from_Interface1D(*(A->getFEdge(*B))); +} + PyDoc_STRVAR(CurvePoint_t2d_doc, "The 2D interpolation parameter.\n" "\n" @@ -204,6 +217,8 @@ static PyGetSetDef BPy_CurvePoint_getseters[] = { (char *)CurvePoint_first_svertex_doc, NULL}, {(char *)"second_svertex", (getter)CurvePoint_second_svertex_get, (setter)CurvePoint_second_svertex_set, (char *)CurvePoint_second_svertex_doc, NULL}, + {(char *)"fedge", (getter)CurvePoint_fedge_get, NULL, + CurvePoint_fedge_doc, NULL}, {(char *)"t2d", (getter)CurvePoint_t2d_get, (setter)CurvePoint_t2d_set, (char *)CurvePoint_t2d_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp index af9f7198748..6f47ce93ca8 100644 --- a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp +++ b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp @@ -268,7 +268,7 @@ void SVertex_mathutils_register_callback() PyDoc_STRVAR(SVertex_point_3d_doc, "The 3D coordinates of the SVertex.\n" "\n" -":type: mathutils.Vector"); +":type: :class:`mathutils.Vector`"); static PyObject *SVertex_point_3d_get(BPy_SVertex *self, void *UNUSED(closure)) { @@ -291,7 +291,7 @@ static int SVertex_point_3d_set(BPy_SVertex *self, PyObject *value, void *UNUSED PyDoc_STRVAR(SVertex_point_2d_doc, "The projected 3D coordinates of the SVertex.\n" "\n" -":type: mathutils.Vector"); +":type: :class:`mathutils.Vector`"); static PyObject *SVertex_point_2d_get(BPy_SVertex *self, void *UNUSED(closure)) { diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp index faf99e90111..fca4c979bbb 100644 --- a/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp +++ b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp @@ -120,19 +120,14 @@ static PyObject *Interface0DIterator_iternext(BPy_Interface0DIterator *self) self->if0D_it->decrement(); } else { - if (self->if0D_it->isEnd()) { + if (self->if0D_it->atLast() || self->if0D_it->isEnd()) { PyErr_SetNone(PyExc_StopIteration); return NULL; } if (self->at_start) self->at_start = false; - else { + else self->if0D_it->increment(); - if (self->if0D_it->isEnd()) { - PyErr_SetNone(PyExc_StopIteration); - return NULL; - } - } } Interface0D *if0D = self->if0D_it->operator->(); return Any_BPy_Interface0D_from_Interface0D(*if0D); @@ -177,11 +172,24 @@ static PyObject *Interface0DIterator_u_get(BPy_Interface0DIterator *self, void * return PyFloat_FromDouble(self->if0D_it->u()); } +PyDoc_STRVAR(Interface0DIterator_at_last_doc, +"True if the interator points to the last valid element.\n" +"For its counterpart (pointing to the first valid element), use it.is_begin.\n" +"\n" +":type: bool"); + +static PyObject *Interface0DIterator_at_last_get(BPy_Interface0DIterator *self, void *UNUSED(closure)) +{ + return PyBool_from_bool(self->if0D_it->atLast()); +} + static PyGetSetDef BPy_Interface0DIterator_getseters[] = { {(char *)"object", (getter)Interface0DIterator_object_get, (setter)NULL, (char *)Interface0DIterator_object_doc, NULL}, {(char *)"t", (getter)Interface0DIterator_t_get, (setter)NULL, (char *)Interface0DIterator_t_doc, NULL}, {(char *)"u", (getter)Interface0DIterator_u_get, (setter)NULL, (char *)Interface0DIterator_u_doc, NULL}, + {(char *)"at_last", (getter)Interface0DIterator_at_last_get, (setter)NULL, + (char *)Interface0DIterator_at_last_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp index 2906f20be06..18d1b37eb3b 100644 --- a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp +++ b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp @@ -102,8 +102,8 @@ static PyObject *StrokeVertexIterator_iter(BPy_StrokeVertexIterator *self) static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self) { /* Because Freestyle iterators for which it.isEnd() holds true have no valid object - * (referencing it.object in this case leads to a crash), we must check if it.object - * is valid after incrementing, to prevent crashes in Python. + * (they point to the past-the-end element and can't be dereferenced), we have to check + * iterators for validity. * Additionally, the at_start attribute is used to keep Freestyle iterator objects * and Python for loops in sync. */ @@ -115,7 +115,10 @@ static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self) self->sv_it->decrement(); } else { - if (self->sv_it->isEnd()) { + /* if sv_it.isEnd() is true, the iterator can't be incremented. if sv_it.isLast() is true, + * the iterator is currently pointing to the final valid argument. Incrementing it further would + * give a python object that can't be dereferenced. */ + if (self->sv_it->atLast() || self->sv_it->isEnd()) { PyErr_SetNone(PyExc_StopIteration); return NULL; } @@ -123,15 +126,8 @@ static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self) * and don't increment, to keep for-loops in sync */ if (self->at_start) self->at_start = false; - /* after incrementing, check if the iterator is at its end - * exit the loop if it is. not doing so will result in a crash */ - else { + else self->sv_it->increment(); - if (self->sv_it->isEnd()) { - PyErr_SetNone(PyExc_StopIteration); - return NULL; - } - } } StrokeVertex *sv = self->sv_it->operator->(); return BPy_StrokeVertex_from_StrokeVertex(*sv); @@ -194,7 +190,7 @@ static PyObject *StrokeVertexIterator_reversed(BPy_StrokeVertexIterator *self) } static PyMethodDef BPy_StrokeVertexIterator_methods[] = { - {"incremented", (PyCFunction) StrokeVertexIterator_incremented, METH_NOARGS, StrokeVertexIterator_incremented_doc}, + {"incremented", (PyCFunction)StrokeVertexIterator_incremented, METH_NOARGS, StrokeVertexIterator_incremented_doc}, {"decremented", (PyCFunction)StrokeVertexIterator_decremented, METH_NOARGS, StrokeVertexIterator_decremented_doc}, {"reversed", (PyCFunction)StrokeVertexIterator_reversed, METH_NOARGS, StrokeVertexIterator_reversed_doc}, {NULL, NULL, 0, NULL} @@ -239,11 +235,25 @@ static PyObject *StrokeVertexIterator_u_get(BPy_StrokeVertexIterator *self, void return PyFloat_FromDouble(self->sv_it->u()); } +PyDoc_STRVAR(StrokeVertexIterator_at_last_doc, +"True if the interator points to the last valid element.\n" +"For its counterpart (pointing to the first valid element), use it.is_begin.\n" +"\n" +":type: bool"); + +static PyObject *StrokeVertexIterator_at_last_get(BPy_StrokeVertexIterator *self) +{ + return PyBool_from_bool(self->sv_it->atLast()); + +} + static PyGetSetDef BPy_StrokeVertexIterator_getseters[] = { {(char *)"object", (getter)StrokeVertexIterator_object_get, (setter)NULL, (char *)StrokeVertexIterator_object_doc, NULL}, {(char *)"t", (getter)StrokeVertexIterator_t_get, (setter)NULL, (char *)StrokeVertexIterator_t_doc, NULL}, {(char *)"u", (getter)StrokeVertexIterator_u_get, (setter)NULL, (char *)StrokeVertexIterator_u_doc, NULL}, + {(char *)"at_last", (getter)StrokeVertexIterator_at_last_get, (setter)NULL, + (char *)StrokeVertexIterator_at_last_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp index e4476cf9bcf..d879ac53aaa 100644 --- a/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp +++ b/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp @@ -116,7 +116,7 @@ PyDoc_STRVAR(orientedViewEdgeIterator_object_doc, "value) currently pointed to by this iterator. If the boolean value is true,\n" "the ViewEdge is incoming.\n" "\n" -":type: (:class:`directedViewEdge`, bool)"); +":type: (:class:`ViewEdge`, bool)"); static PyObject *orientedViewEdgeIterator_object_get(BPy_orientedViewEdgeIterator *self, void *UNUSED(closure)) { diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.cpp index c8b9d7098e4..379fb7e1b12 100644 --- a/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.cpp +++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.cpp @@ -41,38 +41,46 @@ static char BlenderTextureShader___doc__[] = "\n" "[Texture shader]\n" "\n" -".. method:: __init__(LineStyleTextureSlot)\n" +".. method:: __init__(texture)\n" "\n" " Builds a BlenderTextureShader object.\n" "\n" -" :arg mtex: texture slot to add to stroke shading.\n" -" :type mtex: LineStyleTextureSlot\n" - +" :arg texture: A line style texture slot or a shader node tree to define\n" +" a set of textures.\n" +" :type texture: :class:`LineStyleTextureSlot` or :class:`ShaderNodeTree`\n" "\n" ".. method:: shade(stroke)\n" "\n" -" Assigns a blender texture slot to the stroke shading\n" -" in order to simulate marks.\n" +" Assigns a blender texture slot to the stroke shading in order to\n" +" simulate marks.\n" "\n" " :arg stroke: A Stroke object.\n" " :type stroke: :class:`Stroke`\n"; static int BlenderTextureShader___init__(BPy_BlenderTextureShader *self, PyObject *args, PyObject *kwds) { - static const char *kwlist[] = {"LineStyleTextureSlot", NULL}; - PyObject *py_mtex; + static const char *kwlist[] = {"texture", NULL}; + PyObject *obj; MTex *_mtex; + bNodeTree *_nodetree; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", (char **)kwlist, &py_mtex)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", (char **)kwlist, &obj)) return -1; - - _mtex = (MTex*)PyC_RNA_AsPointer(py_mtex, "LineStyleTextureSlot"); - + _mtex = (MTex *)PyC_RNA_AsPointer(obj, "LineStyleTextureSlot"); if (_mtex) { self->py_ss.ss = new StrokeShaders::BlenderTextureShader(_mtex); + return 0; } - - return 0; + PyErr_Clear(); + _nodetree = (bNodeTree *)PyC_RNA_AsPointer(obj, "ShaderNodeTree"); + if (_nodetree) { + self->py_ss.ss = new StrokeShaders::BlenderTextureShader(_nodetree); + return 0; + } + PyErr_Format(PyExc_TypeError, + "expected either 'LineStyleTextureSlot' or 'ShaderNodeTree', " + "found '%.200s' instead", Py_TYPE(obj)->tp_name); + return -1; } /*-----------------------BPy_BlenderTextureShader type definition ------------------------------*/ diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp index e92913d097e..b7b5eb4162b 100644 --- a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp +++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp @@ -451,7 +451,13 @@ int ColorNoiseShader::shade(Stroke& stroke) const int BlenderTextureShader::shade(Stroke& stroke) const { - return stroke.setMTex(_mtex); + if (_mtex) + return stroke.setMTex(_mtex); + if (_nodeTree) { + stroke.setNodeTree(_nodeTree); + return 0; + } + return -1; } int StrokeTextureStepShader::shade(Stroke& stroke) const diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h index 9186d164e9b..6ac22c5b2d1 100644 --- a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h +++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h @@ -36,7 +36,10 @@ #include "../geometry/Bezier.h" #include "../geometry/Geom.h" +extern "C" { struct MTex; +struct bNodeTree; +} using namespace std; @@ -904,6 +907,7 @@ class BlenderTextureShader : public StrokeShader { private: MTex *_mtex; + bNodeTree *_nodeTree; public: /*! Builds the shader. @@ -913,6 +917,17 @@ public: BlenderTextureShader(MTex *mtex) : StrokeShader() { _mtex = mtex; + _nodeTree = NULL; + } + + /*! Builds the shader. + * \param nodetree + * A node tree (of new shading nodes) to define textures. + */ + BlenderTextureShader(bNodeTree *nodetree) : StrokeShader() + { + _nodeTree = nodetree; + _mtex = NULL; } virtual string getName() const diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp index c85295e72bf..863da069259 100644 --- a/source/blender/freestyle/intern/stroke/Stroke.cpp +++ b/source/blender/freestyle/intern/stroke/Stroke.cpp @@ -31,6 +31,7 @@ #include "StrokeRenderer.h" #include "BKE_global.h" +#include "BKE_node.h" namespace Freestyle { @@ -397,8 +398,8 @@ Stroke::Stroke() for (int a = 0; a < MAX_MTEX; a++) { _mtex[a] = NULL; } + _nodeTree = NULL; _tips = false; - _rep = NULL; } Stroke::Stroke(const Stroke& iBrother) @@ -424,11 +425,8 @@ Stroke::Stroke(const Stroke& iBrother) _mtex[a] = NULL; } } + _nodeTree = iBrother._nodeTree; _tips = iBrother._tips; - if (iBrother._rep) - _rep = new StrokeRep(*(iBrother._rep)); - else - _rep = NULL; } Stroke::~Stroke() @@ -441,10 +439,6 @@ Stroke::~Stroke() } _ViewEdges.clear(); - if (_rep) { - delete _rep; - _rep = NULL; - } } Stroke& Stroke::operator=(const Stroke& iBrother) @@ -462,10 +456,6 @@ Stroke& Stroke::operator=(const Stroke& iBrother) _id = iBrother._id; _ViewEdges = iBrother._ViewEdges; _sampling = iBrother._sampling; - if (_rep) - delete _rep; - if (iBrother._rep) - _rep = new StrokeRep(*(iBrother._rep)); return *this; } @@ -601,11 +591,6 @@ int Stroke::Resample(int iNPoints) _Vertices = newVertices; newVertices.clear(); - if (_rep) { - delete _rep; - _rep = new StrokeRep(this); - } - return 0; } @@ -660,10 +645,6 @@ int Stroke::Resample(float iSampling) _Vertices = newVertices; newVertices.clear(); - if (_rep) { - delete _rep; - _rep = new StrokeRep(this); - } return 0; } @@ -776,16 +757,14 @@ void Stroke::ScaleThickness(float iFactor) void Stroke::Render(const StrokeRenderer *iRenderer) { - if (!_rep) - _rep = new StrokeRep(this); - iRenderer->RenderStrokeRep(_rep); + StrokeRep rep(this); + iRenderer->RenderStrokeRep(&rep); } void Stroke::RenderBasic(const StrokeRenderer *iRenderer) { - if (!_rep) - _rep = new StrokeRep(this); - iRenderer->RenderStrokeRepBasic(_rep); + StrokeRep rep(this); + iRenderer->RenderStrokeRepBasic(&rep); } Stroke::vertex_iterator Stroke::vertices_begin(float sampling) diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h index abbbcc32750..86c667a38b6 100644 --- a/source/blender/freestyle/intern/stroke/Stroke.h +++ b/source/blender/freestyle/intern/stroke/Stroke.h @@ -45,6 +45,8 @@ extern "C" { #include "DNA_material_types.h" + +struct bNodeTree; } #ifndef MAX_MTEX @@ -541,9 +543,9 @@ private: MediumType _mediumType; unsigned int _textureId; MTex *_mtex[MAX_MTEX]; + bNodeTree *_nodeTree; bool _tips; Vec2r _extremityOrientations[2]; // the orientations of the first and last extermity - StrokeRep *_rep; public: /*! default constructor */ @@ -653,10 +655,16 @@ public: return _mtex[idx]; } + /*! Return the shader node tree to define textures. */ + inline bNodeTree *getNodeTree() + { + return _nodeTree; + } + /*! Returns true if this Stroke has textures assigned, false otherwise. */ inline bool hasTex() const { - return _mtex[0] != NULL; + return (_mtex[0] != NULL) || _nodeTree; } /*! Returns true if this Stroke uses a texture with tips, false otherwise. */ @@ -767,6 +775,12 @@ public: return -1; /* no free slots */ } + /*! assigns a node tree (of new shading nodes) to define textures. */ + inline void setNodeTree(bNodeTree *iNodeTree) + { + _nodeTree = iNodeTree; + } + /*! sets the flag telling whether this stroke is using a texture with tips or not. */ inline void setTips(bool iTips) { diff --git a/source/blender/freestyle/intern/stroke/StrokeIterators.h b/source/blender/freestyle/intern/stroke/StrokeIterators.h index a8ec529fbfa..1df9aa2794a 100644 --- a/source/blender/freestyle/intern/stroke/StrokeIterators.h +++ b/source/blender/freestyle/intern/stroke/StrokeIterators.h @@ -171,6 +171,18 @@ public: return _it == _begin; } + /*! Returns true if the pointed StrokeVertex is the final valid StrokeVertex of the Stroke. */ + bool atLast() + { + if (_it == _end) + return false; + + ++_it; + bool result = (_it == _end); + --_it; + return result; + } + /*! Returns true if the pointed StrokeVertex is after the last StrokeVertex of the Stroke. */ bool isEnd() const { diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.cpp b/source/blender/freestyle/intern/stroke/StrokeRep.cpp index 3f39443c4b8..f7857107006 100644 --- a/source/blender/freestyle/intern/stroke/StrokeRep.cpp +++ b/source/blender/freestyle/intern/stroke/StrokeRep.cpp @@ -704,6 +704,8 @@ StrokeRep::StrokeRep() { _stroke = 0; _strokeType = Stroke::OPAQUE_MEDIUM; + _nodeTree = NULL; + _hasTex = false; _textureStep = 1.0; for (int a = 0; a < MAX_MTEX; a++) { _mtex[a] = NULL; @@ -724,6 +726,8 @@ StrokeRep::StrokeRep(Stroke *iStroke) { _stroke = iStroke; _strokeType = iStroke->getMediumType(); + _nodeTree = iStroke->getNodeTree(); + _hasTex = iStroke->hasTex(); _textureId = iStroke->getTextureId(); _textureStep = iStroke->getTextureStep(); for (int a = 0; a < MAX_MTEX; a++) { @@ -757,6 +761,8 @@ StrokeRep::StrokeRep(const StrokeRep& iBrother) _strokeType = iBrother._strokeType; _textureId = iBrother._textureId; _textureStep = iBrother._textureStep; + _nodeTree = iBrother._nodeTree; + _hasTex = iBrother._hasTex; for (int a = 0; a < MAX_MTEX; a++) { if (iBrother._mtex[a]) { _mtex[a] = iBrother._mtex[a]; @@ -808,7 +814,7 @@ void StrokeRep::create() end = true; } if ((!strip.empty()) && (strip.size() > 1)) { - _strips.push_back(new Strip(strip, _stroke->hasTex(), first, end, _textureStep)); + _strips.push_back(new Strip(strip, _hasTex, first, end, _textureStep)); strip.clear(); } first = false; diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.h b/source/blender/freestyle/intern/stroke/StrokeRep.h index 61a456cdf42..ba042eb496d 100644 --- a/source/blender/freestyle/intern/stroke/StrokeRep.h +++ b/source/blender/freestyle/intern/stroke/StrokeRep.h @@ -37,7 +37,8 @@ #endif extern "C" { -#include "DNA_material_types.h" +#include "DNA_material_types.h" // for MAX_MTEX +struct bNodeTree; } namespace Freestyle { @@ -185,7 +186,9 @@ protected: unsigned int _textureId; float _textureStep; MTex *_mtex[MAX_MTEX]; + bNodeTree *_nodeTree; Material *_material; + bool _hasTex; // float _averageTextureAlpha; @@ -222,6 +225,16 @@ public: return _material; } + inline bNodeTree *getNodeTree() const + { + return _nodeTree; + } + + inline bool hasTex() const + { + return _hasTex; + } + inline vector<Strip*>& getStrips() { return _strips; diff --git a/source/blender/freestyle/intern/system/PointerSequence.h b/source/blender/freestyle/intern/system/PointerSequence.h index 32c7898f840..791df90ba9d 100644 --- a/source/blender/freestyle/intern/system/PointerSequence.h +++ b/source/blender/freestyle/intern/system/PointerSequence.h @@ -30,7 +30,7 @@ * PointerSequence * * Produces a wrapped version of a sequence type (std::vector, std::deque, std::list) that will take ownership of - * pointers tht it stores. Those pointers will be deleted in its destructor. + * pointers that it stores. Those pointers will be deleted in its destructor. * * Because the contained pointers are wholly owned by the sequence, you cannot make a copy of the sequence. * Making a copy would result in a double free. diff --git a/source/blender/freestyle/intern/view_map/Interface0D.h b/source/blender/freestyle/intern/view_map/Interface0D.h index 123253bf3e1..da71d7ad949 100644 --- a/source/blender/freestyle/intern/view_map/Interface0D.h +++ b/source/blender/freestyle/intern/view_map/Interface0D.h @@ -302,6 +302,18 @@ public: return _iterator->isEnd(); } + /*! Returns true when the iterator is pointing to the final valid element. */ + virtual bool atLast() const + { + if (_iterator->isEnd()) + return false; + + _iterator->increment(); + bool result = _iterator->isEnd(); + _iterator->decrement(); + return result; + } + /*! operator == . */ bool operator==(const Interface0DIterator& it) const { diff --git a/source/blender/freestyle/intern/view_map/SteerableViewMap.h b/source/blender/freestyle/intern/view_map/SteerableViewMap.h index 0cd5d222621..3a660627776 100644 --- a/source/blender/freestyle/intern/view_map/SteerableViewMap.h +++ b/source/blender/freestyle/intern/view_map/SteerableViewMap.h @@ -54,7 +54,7 @@ class GrayImage; class SteerableViewMap { protected: - // for each vector the list of nbOrientations weigths corresponding to its contributions + // for each vector the list of nbOrientations weights corresponding to its contributions // to the nbOrientations directional maps map<unsigned int, double*> _mapping; unsigned _nbOrientations; @@ -73,7 +73,7 @@ public: virtual void Reset(); /*! Adds a FEdge to steerable VM. - * Returns the nbOrientations weigths corresponding to the FEdge contributions to the nbOrientations + * Returns the nbOrientations weights corresponding to the FEdge contributions to the nbOrientations * directional maps. */ double *AddFEdge(FEdge *iFEdge); diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index f59dd44f169..7d34c4e3829 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -140,7 +140,7 @@ set(SRC GPU_primitives.h GPU_raster.h GPU_safety.h - GPU_select.h + GPU_select.h GPU_sprite.h GPU_state_latch.h GPU_utility.h diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 55325f91c05..ee20919dde3 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -38,11 +38,11 @@ extern "C" { #endif -#ifdef _DEBUG -/*#define DEBUG_VBO(X) printf(X)*/ -#define DEBUG_VBO(X) +#ifdef DEBUG +/* #define DEBUG_VBO(X) printf(X)*/ +# define DEBUG_VBO(X) #else -#define DEBUG_VBO(X) +# define DEBUG_VBO(X) #endif struct BMesh; @@ -138,6 +138,7 @@ void GPU_drawobject_free(struct DerivedMesh *dm); void GPU_vertex_setup(struct DerivedMesh *dm); void GPU_normal_setup(struct DerivedMesh *dm); void GPU_uv_setup(struct DerivedMesh *dm); +void GPU_texpaint_uv_setup(struct DerivedMesh *dm); /* colType is the cddata MCol type to use! */ void GPU_color_setup(struct DerivedMesh *dm, int colType); void GPU_edge_setup(struct DerivedMesh *dm); /* does not mix with other data */ diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index df707685a35..a4ac8424fbc 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -98,7 +98,7 @@ int GPU_get_material_alpha_blend(void); * - passing NULL clears the state again */ int GPU_set_tpage(struct MTFace *tface, int mipmap, int transp); - +void GPU_clear_tpage(bool force); /* Lights * - returns how many lights were enabled * - this affects fixed functions materials and texface, not glsl */ diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h index ddf2601800d..dcb64628f24 100644 --- a/source/blender/gpu/GPU_immediate.h +++ b/source/blender/gpu/GPU_immediate.h @@ -939,23 +939,12 @@ BLI_INLINE void gpuDrawElements(GLenum mode) } - - -void gpu_draw_elements_gl(void); - - - BLI_INLINE void gpuRepeatElements(void) { gpu_draw_elements_gl(); } - -void gpu_draw_range_elements_gl(void); - - - BLI_INLINE void gpuDrawRangeElements(GLenum mode) { GPU_IMMEDIATE->mode = mode; diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h index 6b81ce7b248..9fe1b413a3c 100644 --- a/source/blender/gpu/GPU_select.h +++ b/source/blender/gpu/GPU_select.h @@ -1,6 +1,3 @@ -#ifndef _GPU_SELECT_H_ -#define _GPU_SELECT_H_ - /* * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -18,12 +15,10 @@ * 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. + * The Original Code is Copyright (C) 2014 Blender Foundation. * All rights reserved. * - * The Original Code is: all of this file. - * - * Contributor(s): Jason Wilkins. + * Contributor(s): Antony Riakiotakis. * * ***** END GPL LICENSE BLOCK ***** */ @@ -32,30 +27,37 @@ * \ingroup gpu */ -#include "GPU_glew.h" - - - -#ifdef __cplusplus -extern "C" { -#endif +#ifndef __GPU_SELECT__ +#define __GPU_SELECT__ +#include "GPU_glew.h" +#include "DNA_vec_types.h" /* rcft */ +#include "BLI_sys_types.h" +/* flags for mode of operation */ +enum { + GPU_SELECT_ALL = 1, + GPU_SELECT_NEAREST_FIRST_PASS = 2, + GPU_SELECT_NEAREST_SECOND_PASS = 3, +}; -void GPU_select_buffer(GLsizei size, GLuint* buffer); /* replaces glSelectBuffer(size, buffer) */ +/* initialize and provide buffer for results */ +void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits); -void GPU_select_begin (void); /* replaces glRenderMode(GL_SELECT) */ -GLsizei GPU_select_end (void); /* replaces glRenderMode(GL_RENDER) */ +/* loads a new selection id and ends previous query, if any. In second pass of selection it also returns + * if id has been hit on the first pass already. Thus we can skip drawing un-hit objects IMPORTANT: We rely on the order of object rendering on passes to be + * the same for this to work */ +bool GPU_select_load_id(unsigned int id); -void GPU_select_clear (void); /* replaces glInitNames() */ -void GPU_select_pop (void); /* replaces glPopName() */ -void GPU_select_push (GLuint name); /* replaces glPushName(name) */ -void GPU_select_load (GLuint name); /* replaces glLoadName(name) */ +/* cleanup and flush selection results to buffer. Return number of hits and hits in buffer. + * if dopass is true, we will do a second pass with occlusion queries to get the closest hit */ +unsigned int GPU_select_end(void); +/* does the GPU support occlusion queries? */ +bool GPU_select_query_check_support(void); +/* is occlusion query supported and user activated? */ +bool GPU_select_query_check_active(void); -#ifdef __cplusplus -} #endif -#endif /* _GPU_SELECT_H_ */ diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index e6bac9afdfb..6eda6d35ff3 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -55,7 +55,16 @@ #include "BLI_ghash.h" #include "BLI_threads.h" + #include "bmesh.h" +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_ccg.h" +#include "BKE_DerivedMesh.h" +#include "BKE_paint.h" +#include "BKE_material.h" +#include "BKE_pbvh.h" #include "DNA_meshdata_types.h" #include "DNA_userdef_types.h" @@ -68,15 +77,18 @@ #include <string.h> typedef enum { - GPU_BUFFER_VERTEX_STATE = 1, - GPU_BUFFER_NORMAL_STATE = 2, - GPU_BUFFER_TEXCOORD_STATE = 4, - GPU_BUFFER_COLOR_STATE = 8, - GPU_BUFFER_ELEMENT_STATE = 16, + GPU_BUFFER_VERTEX_STATE = (1 << 0), + GPU_BUFFER_NORMAL_STATE = (1 << 1), + GPU_BUFFER_TEXCOORD_UNIT_0_STATE = (1 << 2), + GPU_BUFFER_TEXCOORD_UNIT_2_STATE = (1 << 3), + GPU_BUFFER_COLOR_STATE = (1 << 4), + GPU_BUFFER_ELEMENT_STATE = (1 << 5), } GPUBufferState; #define MAX_GPU_ATTRIB_DATA 32 +#define BUFFER_OFFSET(n) ((GLubyte *)NULL + (n)) + /* -1 - undefined, 0 - vertex arrays, 1 - VBOs */ static int useVBOs = -1; static GPUBufferState GLStates = 0; @@ -843,6 +855,61 @@ static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int * } } + +static void GPU_buffer_copy_uv_texpaint(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user)) +{ + int start; + int i, totface; + + int totmaterial = dm->totmat; + MTFace **mtface_base; + MTFace *stencil_base; + int stencil; + MFace *mf; + + /* should have been checked for before, reassert */ + BLI_assert(DM_get_tessface_data_layer(dm, CD_MTFACE)); + mf = dm->getTessFaceArray(dm); + mtface_base = MEM_mallocN(totmaterial * sizeof(*mtface_base), "texslots"); + + for (i = 0; i < totmaterial; i++) { + mtface_base[i] = DM_paint_uvlayer_active_get(dm, i); + } + + stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE); + stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil); + + totface = dm->getNumTessFaces(dm); + + for (i = 0; i < totface; i++, mf++) { + int mat_i = mf->mat_nr; + start = index[mat_orig_to_new[mat_i]]; + + /* v1 v2 v3 */ + copy_v2_v2(&varray[start], mtface_base[mat_i][i].uv[0]); + copy_v2_v2(&varray[start + 2], stencil_base[i].uv[0]); + copy_v2_v2(&varray[start + 4], mtface_base[mat_i][i].uv[1]); + copy_v2_v2(&varray[start + 6], stencil_base[i].uv[1]); + copy_v2_v2(&varray[start + 8], mtface_base[mat_i][i].uv[2]); + copy_v2_v2(&varray[start + 10], stencil_base[i].uv[2]); + index[mat_orig_to_new[mat_i]] += 12; + + if (mf->v4) { + /* v3 v4 v1 */ + copy_v2_v2(&varray[start + 12], mtface_base[mat_i][i].uv[2]); + copy_v2_v2(&varray[start + 14], stencil_base[i].uv[2]); + copy_v2_v2(&varray[start + 16], mtface_base[mat_i][i].uv[3]); + copy_v2_v2(&varray[start + 18], stencil_base[i].uv[3]); + copy_v2_v2(&varray[start + 20], mtface_base[mat_i][i].uv[0]); + copy_v2_v2(&varray[start + 22], stencil_base[i].uv[0]); + index[mat_orig_to_new[mat_i]] += 12; + } + } + + MEM_freeN(mtface_base); +} + + static void copy_mcol_uc3(unsigned char *v, unsigned char *col) { v[0] = col[3]; @@ -932,6 +999,7 @@ typedef enum { GPU_BUFFER_NORMAL, GPU_BUFFER_COLOR, GPU_BUFFER_UV, + GPU_BUFFER_UV_TEXPAINT, GPU_BUFFER_EDGE, GPU_BUFFER_UVEDGE, } GPUBufferType; @@ -943,12 +1011,13 @@ typedef struct { } GPUBufferTypeSettings; const GPUBufferTypeSettings gpu_buffer_type_settings[] = { - {GPU_buffer_copy_vertex, GL_ARRAY_BUFFER, 3}, - {GPU_buffer_copy_normal, GL_ARRAY_BUFFER, 3}, - {GPU_buffer_copy_mcol, GL_ARRAY_BUFFER, 3}, - {GPU_buffer_copy_uv, GL_ARRAY_BUFFER, 2}, - {GPU_buffer_copy_edge, GL_ELEMENT_ARRAY_BUFFER, 2}, - {GPU_buffer_copy_uvedge, GL_ELEMENT_ARRAY_BUFFER, 4}, + {GPU_buffer_copy_vertex, GL_ARRAY_BUFFER, 3}, + {GPU_buffer_copy_normal, GL_ARRAY_BUFFER, 3}, + {GPU_buffer_copy_mcol, GL_ARRAY_BUFFER, 3}, + {GPU_buffer_copy_uv, GL_ARRAY_BUFFER, 2}, + {GPU_buffer_copy_uv_texpaint, GL_ARRAY_BUFFER, 4}, + {GPU_buffer_copy_edge, GL_ELEMENT_ARRAY_BUFFER, 2}, + {GPU_buffer_copy_uvedge, GL_ELEMENT_ARRAY_BUFFER, 4}, }; /* get the GPUDrawObject buffer associated with a type */ @@ -963,6 +1032,8 @@ static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBuffer return &gdo->colors; case GPU_BUFFER_UV: return &gdo->uv; + case GPU_BUFFER_UV_TEXPAINT: + return &gdo->uv; case GPU_BUFFER_EDGE: return &gdo->edges; case GPU_BUFFER_UVEDGE: @@ -984,6 +1055,8 @@ static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type) return sizeof(char) * 3 * dm->drawObject->tot_triangle_point; case GPU_BUFFER_UV: return sizeof(float) * 2 * dm->drawObject->tot_triangle_point; + case GPU_BUFFER_UV_TEXPAINT: + return sizeof(float) * 4 * dm->drawObject->tot_triangle_point; case GPU_BUFFER_EDGE: return sizeof(int) * 2 * dm->drawObject->totedge; case GPU_BUFFER_UVEDGE: @@ -1012,7 +1085,7 @@ static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type) if (!(user_data = DM_get_tessface_data_layer(dm, dm->drawObject->colType))) return NULL; } - else if (type == GPU_BUFFER_UV) { + else if (ELEM(type, GPU_BUFFER_UV, GPU_BUFFER_UV_TEXPAINT)) { if (!DM_get_tessface_data_layer(dm, CD_MTFACE)) return NULL; } @@ -1088,9 +1161,35 @@ void GPU_uv_setup(DerivedMesh *dm) glTexCoordPointer(2, GL_FLOAT, 0, dm->drawObject->uv->pointer); } - GLStates |= GPU_BUFFER_TEXCOORD_STATE; + GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE; +} + +void GPU_texpaint_uv_setup(DerivedMesh *dm) +{ + if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UV_TEXPAINT)) + return; + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (useVBOs) { + gpu_glBindBuffer(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0); + glClientActiveTexture(GL_TEXTURE2); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), BUFFER_OFFSET(2 * sizeof(float))); + glClientActiveTexture(GL_TEXTURE0); + } + else { + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), dm->drawObject->uv->pointer); + glClientActiveTexture(GL_TEXTURE2); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)dm->drawObject->uv->pointer + 2 * sizeof(float)); + glClientActiveTexture(GL_TEXTURE0); + } + + GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_2_STATE; } + void GPU_color_setup(DerivedMesh *dm, int colType) { if (!dm->drawObject) { @@ -1248,8 +1347,13 @@ void GPU_buffer_unbind(void) glDisableClientState(GL_VERTEX_ARRAY); if (GLStates & GPU_BUFFER_NORMAL_STATE) glDisableClientState(GL_NORMAL_ARRAY); - if (GLStates & GPU_BUFFER_TEXCOORD_STATE) + if (GLStates & GPU_BUFFER_TEXCOORD_UNIT_0_STATE) + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + if (GLStates & GPU_BUFFER_TEXCOORD_UNIT_2_STATE) { + glClientActiveTexture(GL_TEXTURE2); glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + } if (GLStates & GPU_BUFFER_COLOR_STATE) glDisableClientState(GL_COLOR_ARRAY); if (GLStates & GPU_BUFFER_ELEMENT_STATE) { @@ -1258,8 +1362,8 @@ void GPU_buffer_unbind(void) } } GLStates &= ~(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE | - GPU_BUFFER_TEXCOORD_STATE | GPU_BUFFER_COLOR_STATE | - GPU_BUFFER_ELEMENT_STATE); + GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_2_STATE | + GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE); for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) { if (attribData[i].index != -1) { @@ -2584,11 +2688,17 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, } else if (buffers->use_bmesh) { /* due to dynamc nature of dyntopo, only get first material */ - GSetIterator gs_iter; - BMFace *f; - BLI_gsetIterator_init(&gs_iter, bm_faces); - f = BLI_gsetIterator_getKey(&gs_iter); - GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color); + if (BLI_gset_size(bm_faces) > 0) { + GSetIterator gs_iter; + BMFace *f; + + BLI_gsetIterator_init(&gs_iter, bm_faces); + f = BLI_gsetIterator_getKey(&gs_iter); + GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color); + } + else { + return false; + } } else { const DMFlagMat *flags = &buffers->grid_flag_mats[buffers->grid_indices[0]]; @@ -2596,9 +2706,7 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, GPU_material_diffuse_get(flags->mat_nr + 1, diffuse_color); } - return diffuse_color[0] != buffers->diffuse_color[0] || - diffuse_color[1] != buffers->diffuse_color[1] || - diffuse_color[2] != buffers->diffuse_color[2]; + return !equals_v3v3(diffuse_color, buffers->diffuse_color); } /* release a GPU_PBVH_Buffers id; diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 0440215c774..c9109b96424 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -105,7 +105,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max) /* skip a variable/function name */ while (*str) { - if (ELEM7(*str, ' ', '(', ')', ',', '\t', '\n', '\r')) + if (ELEM(*str, ' ', '(', ')', ',', '\t', '\n', '\r')) break; else { if (token && len < max-1) { @@ -123,7 +123,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max) /* skip the next special characters: * note the missing ')' */ while (*str) { - if (ELEM6(*str, ' ', '(', ',', '\t', '\n', '\r')) + if (ELEM(*str, ' ', '(', ',', '\t', '\n', '\r')) str++; else break; @@ -1417,6 +1417,10 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttri /* failed? */ if (!shader) { + if (fragmentcode) + MEM_freeN(fragmentcode); + if (vertexcode) + MEM_freeN(vertexcode); memset(attribs, 0, sizeof(*attribs)); memset(builtins, 0, sizeof(*builtins)); GPU_nodes_free(nodes); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index dd495657ea1..729146e065b 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -378,9 +378,9 @@ static void blend_func_state_init(void) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } -static void gpu_clear_tpage(void) +void GPU_clear_tpage(bool force) { - if (GTS.lasttface==NULL) + if (GTS.lasttface==NULL && !force) return; GTS.lasttface= NULL; @@ -540,12 +540,16 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo * a high precision format only if it is available */ use_high_bit_depth = true; } + /* we may skip this in high precision, but if not, we need to have a valid buffer here */ + else if (ibuf->userflags & IB_RECT_INVALID) { + IMB_rect_from_float(ibuf); + } /* TODO unneeded when float images are correctly treated as linear always */ if (!is_data) do_color_management = true; - if (ibuf->rect==NULL) + if (ibuf->rect == NULL) IMB_rect_from_float(ibuf); } @@ -876,7 +880,7 @@ int GPU_set_tpage(MTFace *tface, int mipmap, int alphablend) /* check if we need to clear the state */ if (tface==NULL) { - gpu_clear_tpage(); + GPU_clear_tpage(false); return 0; } @@ -1045,21 +1049,14 @@ void GPU_paint_update_image(Image *ima, int x, int y, int w, int h) * which is much quicker for painting */ GLint row_length, skip_pixels, skip_rows; - glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length); - glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels); - glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skip_rows); - /* if color correction is needed, we must update the part that needs updating. */ if (ibuf->rect_float) { - float *buffer = MEM_mallocN(w*h*sizeof(float)*4, "temp_texpaint_float_buf"); + float *buffer = MEM_mallocN(w * h * sizeof(float) * 4, "temp_texpaint_float_buf"); bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0; IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data); - + if (GPU_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) { MEM_freeN(buffer); - glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels); - glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows); BKE_image_release_ibuf(ima, ibuf, NULL); return; } @@ -1084,15 +1081,16 @@ void GPU_paint_update_image(Image *ima, int x, int y, int w, int h) } if (GPU_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels); - glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows); BKE_image_release_ibuf(ima, ibuf, NULL); return; } glBindTexture(GL_TEXTURE_2D, ima->bindcode); + glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length); + glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels); + glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skip_rows); + glPixelStorei(GL_UNPACK_ROW_LENGTH, ibuf->x); glPixelStorei(GL_UNPACK_SKIP_PIXELS, x); glPixelStorei(GL_UNPACK_SKIP_ROWS, y); @@ -1558,7 +1556,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O /* setting 'do_alpha_after = true' indicates this object needs to be * drawn in a second alpha pass for improved blending */ if (do_alpha_after && !GMS.is_alpha_pass) - if (ELEM3(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT)) + if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT)) *do_alpha_after = true; GMS.alphablend[a]= alphablend; diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 6c4d1018272..310b46266d3 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -79,6 +79,8 @@ #include <string.h> +#define MAX_DEFINE_LENGTH 72 + /* Extensions support */ /* extensions used: @@ -992,6 +994,9 @@ bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, char er gpu_glBindFramebuffer(GL_FRAMEBUFFER, fb->object); GG.currentfb = fb->object; + /* Clean glError buffer. */ + while (glGetError() != GL_NO_ERROR) {} + gpu_glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, tex->target, tex->bindcode, 0); @@ -1378,35 +1383,51 @@ static bool print_status(GLuint object, GLboolean is_program, const char* nickna return status; } +static const char *gpu_shader_version(void) +{ + /* turn on glsl 1.30 for bicubic bump mapping and ATI clipping support */ + if (GLEW_VERSION_3_0 && + (GPU_bicubic_bump_support() || GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY))) + { + return "#version 130\n"; + } + + return ""; +} + + static const char *gpu_shader_standard_extensions(void) { /* need this extensions for high quality bump mapping */ - if (GPU_bicubic_bump_support()) { - return "#version 130\n" - "#extension GL_ARB_texture_query_lod: enable\n" - "#define BUMP_BICUBIC\n"; - } + if (GPU_bicubic_bump_support()) + return "#extension GL_ARB_texture_query_lod: enable\n"; return ""; } -static const char *gpu_shader_standard_defines(void) +static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH]) { /* some useful defines to detect GPU type */ - if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) - return "#define GPU_ATI\n"; + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { + strcat(defines, "#define GPU_ATI\n"); + if (GLEW_VERSION_3_0) + strcat(defines, "#define CLIP_WORKAROUND\n"); + } else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) - return "#define GPU_NVIDIA\n"; + strcat(defines, "#define GPU_NVIDIA\n"); else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) - return "#define GPU_INTEL\n"; - - return ""; + strcat(defines, "#define GPU_INTEL\n"); + + if (GPU_bicubic_bump_support()) + strcat(defines, "#define BUMP_BICUBIC\n"); + return; } GPUShader *GPU_shader_create(const char* nickname, const char *vertexcode, const char *fragcode, const char *libcode, const char *defines) { GLint status; GPUShader *shader; + char standard_defines[MAX_DEFINE_LENGTH] = ""; #if 0 int i; @@ -1460,12 +1481,16 @@ GPUShader *GPU_shader_create(const char* nickname, const char *vertexcode, const return NULL; } + gpu_shader_standard_defines(standard_defines); + if (vertexcode) { - const char *source[4]; + const char *source[5]; + /* custom limit, may be too small, beware */ int num_source = 0; + source[num_source++] = gpu_shader_version(); source[num_source++] = gpu_shader_standard_extensions(); - source[num_source++] = gpu_shader_standard_defines(); + source[num_source++] = standard_defines; if (defines) source[num_source++] = defines; if (vertexcode) source[num_source++] = vertexcode; @@ -1482,11 +1507,12 @@ GPUShader *GPU_shader_create(const char* nickname, const char *vertexcode, const } if (fragcode) { - const char *source[5]; + const char *source[6]; int num_source = 0; + source[num_source++] = gpu_shader_version(); source[num_source++] = gpu_shader_standard_extensions(); - source[num_source++] = gpu_shader_standard_defines(); + source[num_source++] = standard_defines; if (defines) source[num_source++] = defines; if (libcode) source[num_source++] = libcode; diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c index dbe480993cb..7f5127408aa 100644 --- a/source/blender/gpu/intern/gpu_immediate.c +++ b/source/blender/gpu/intern/gpu_immediate.c @@ -483,7 +483,7 @@ static GLboolean end_begin(void) GPU_IMMEDIATE->hasOverflowed = GL_TRUE; #endif - if (!ELEM6( + if (!ELEM( GPU_IMMEDIATE->mode, GL_NOOP, GL_LINE_LOOP, diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 9e89f6afd24..4f8ae3ebde8 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -951,6 +951,12 @@ static void texture_rgb_blend(GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *o case MTEX_BLEND_COLOR: GPU_link(mat, "mtex_rgb_color", out, tex, fact, facg, in); break; + case MTEX_SOFT_LIGHT: + GPU_link(mat, "mtex_rgb_soft", out, tex, fact, facg, in); + break; + case MTEX_LIN_LIGHT: + GPU_link(mat, "mtex_rgb_linear", out, tex, fact, facg, in); + break; default: GPU_link(mat, "set_rgb_zero", &in); break; diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c index 583e378c32f..dab468e6733 100644 --- a/source/blender/gpu/intern/gpu_matrix.c +++ b/source/blender/gpu/intern/gpu_matrix.c @@ -79,7 +79,7 @@ static GLenum ms_current_mode; /* Check if we have a good matrix */ -#if WITH_GPU_SAFETY +#ifdef WITH_GPU_SAFETY static void checkmat(GLfloat *m) { diff --git a/source/blender/gpu/intern/gpu_raster.c b/source/blender/gpu/intern/gpu_raster.c index 81a733a54a0..cbda490f980 100644 --- a/source/blender/gpu/intern/gpu_raster.c +++ b/source/blender/gpu/intern/gpu_raster.c @@ -502,7 +502,7 @@ static GLboolean end_begin(void) GPU_IMMEDIATE->hasOverflowed = GL_TRUE; #endif - if (!ELEM6( + if (!ELEM( GPU_IMMEDIATE->mode, GL_NOOP, GL_LINE_LOOP, diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c index 2ae5bc8a742..17fd584a340 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -15,177 +15,237 @@ * 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. + * The Original Code is Copyright (C) 2014 Blender Foundation. * All rights reserved. * - * The Original Code is: all of this file. - * - * Contributor(s): Jason Wilkins. + * Contributor(s): Antony Riakiotakis, Jason Wilkins. * * ***** END GPL LICENSE BLOCK ***** */ -/** \file source/blender/gpu/intern/gpu_select.c +/** \file blender/gpu/intern/gpu_select.c * \ingroup gpu + * + * Interface for accessing gpu-related methods for selection. The semantics will be + * similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility. */ #if WITH_GL_PROFILE_COMPAT #define GPU_MANGLE_DEPRECATED 0 /* Allow use of deprecated OpenGL functions in this file */ #endif -/* my interface */ -#include "intern/gpu_select_intern.h" - -/* my library */ -#include "GPU_safety.h" +#include "GPU_select.h" +#include "GPU_extensions.h" -/* internal */ -#include "intern/gpu_matrix_intern.h" -#include "intern/gpu_aspect_intern.h" - -/* external */ #include "BLI_utildefines.h" - - -static bool IS_SELECT_MODE = false; - - - -void gpu_select_init(void) -{ - IS_SELECT_MODE = false; -} - - - -void gpu_select_exit(void) -{ -} - - - -bool gpu_default_select_begin(const void* UNUSED(object), void* UNUSED(param)) +#include "MEM_guardedalloc.h" + +#include "DNA_userdef_types.h" + +#include <GL/glew.h> + +/* Ad hoc number of queries to allocate to skip doing many glGenQueries */ +#define ALLOC_QUERIES 200 + +typedef struct GPUQueryState { + /* To ignore selection id calls when not initialized */ + bool select_is_active; + /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */ + bool query_issued; + /* array holding the OpenGL query identifiers */ + unsigned int *queries; + /* array holding the id corresponding to each query */ + unsigned int *id; + /* number of queries in *queries and *id */ + unsigned int num_of_queries; + /* index to the next query to start */ + unsigned int active_query; + /* flag to cache user preference for occlusion based selection */ + bool use_gpu_select; + /* cache on initialization */ + unsigned int *buffer; + unsigned int bufsize; + /* mode of operation */ + char mode; + unsigned int index; + int oldhits; +} GPUQueryState; + +static GPUQueryState g_query_state = {0}; + +void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits) { -#if defined(WITH_GPU_PROFILE_COMPAT) - return true; /* nothing to do, allow this pass to start */ -#else - return false; /* not implemented, so cancel this pass before it starts if possible */ -#endif + g_query_state.select_is_active = true; + g_query_state.query_issued = false; + g_query_state.active_query = 0; + g_query_state.use_gpu_select = GPU_select_query_check_active(); + g_query_state.num_of_queries = 0; + g_query_state.bufsize = bufsize; + g_query_state.buffer = buffer; + g_query_state.mode = mode; + g_query_state.index = 0; + g_query_state.oldhits = oldhits; + + if (!g_query_state.use_gpu_select) { + glSelectBuffer( bufsize, (GLuint *)buffer); + glRenderMode(GL_SELECT); + glInitNames(); + glPushName(-1); + } + else { + float viewport[4]; + + g_query_state.num_of_queries = ALLOC_QUERIES; + + g_query_state.queries = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.queries) , "gpu selection queries"); + g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id) , "gpu selection ids"); + glGenQueriesARB(g_query_state.num_of_queries, g_query_state.queries); + + glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT); + /* disable writing to the framebuffer */ + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + /* In order to save some fill rate we minimize the viewport using rect. + * We need to get the region of the scissor so that our geometry doesn't + * get rejected before the depth test. Should probably cull rect against + * scissor for viewport but this is a rare case I think */ + glGetFloatv(GL_SCISSOR_BOX, viewport); + if (!input || input->xmin == input->xmax) { + glViewport(viewport[0], viewport[1], 24, 24); + } + else { + glViewport(viewport[0], viewport[1], (int)(input->xmax - input->xmin), (int)(input->ymax - input->ymin)); + } + + /* occlusion queries operates on fragments that pass tests and since we are interested on all + * objects in the view frustum independently of their order, we need to disable the depth test */ + if (mode == GPU_SELECT_ALL) { + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + } + else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) { + glClear(GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LEQUAL); + } + else if (mode == GPU_SELECT_NEAREST_SECOND_PASS) { + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDepthFunc(GL_EQUAL); + } + } } - - -bool gpu_default_select_end(const void* UNUSED(object), void* UNUSED(param)) +bool GPU_select_load_id(unsigned int id) { - return true; /* only one pass, 'true' means 'done' */ -} - - + /* if no selection mode active, ignore */ + if(!g_query_state.select_is_active) + return true; -bool gpu_default_select_commit(const void* UNUSED(object)) -{ -#if defined(WITH_GPU_PROFILE_COMPAT) - gpu_set_common(NULL); - gpu_glUseProgram(0); - gpu_commit_matrix(); + if (!g_query_state.use_gpu_select) { + glLoadName(id); + } + else { + if (g_query_state.query_issued) { + glEndQueryARB(GL_SAMPLES_PASSED_ARB); + } + /* if required, allocate extra queries */ + if (g_query_state.active_query == g_query_state.num_of_queries) { + g_query_state.num_of_queries += ALLOC_QUERIES; + g_query_state.queries = MEM_reallocN(g_query_state.queries, g_query_state.num_of_queries * sizeof(*g_query_state.queries)); + g_query_state.id = MEM_reallocN(g_query_state.id, g_query_state.num_of_queries * sizeof(*g_query_state.id)); + glGenQueriesARB(ALLOC_QUERIES, &g_query_state.queries[g_query_state.active_query]); + } + + glBeginQueryARB(GL_SAMPLES_PASSED_ARB, g_query_state.queries[g_query_state.active_query]); + g_query_state.id[g_query_state.active_query] = id; + g_query_state.active_query++; + g_query_state.query_issued = true; + + if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS) { + if (g_query_state.buffer[g_query_state.index * 4 + 3] == id) { + g_query_state.index++; + return true; + } + else { + return false; + } + } + } return true; -#else - return false; /* cancel drawing, since select mode isn't implemented */ -#endif } - - -bool gpu_is_select_mode(void) -{ - return IS_SELECT_MODE; -} - - - -void GPU_select_buffer(GLsizei size, GLuint* buffer) +unsigned int GPU_select_end(void) { - GPU_ASSERT(!IS_SELECT_MODE); - - if (!IS_SELECT_MODE) { -#if defined(WITH_GL_PROFILE_COMPAT) - glSelectBuffer(size, buffer); -#endif + unsigned int hits = 0; + if (!g_query_state.use_gpu_select) { + glPopName(); + hits = glRenderMode(GL_RENDER); } -} - - - -void GPU_select_begin(void) -{ - GPU_ASSERT(!gpu_aspect_active()); - GPU_ASSERT(!IS_SELECT_MODE); - - IS_SELECT_MODE = true; - -#if defined(WITH_GL_PROFILE_COMPAT) - glRenderMode(GL_SELECT); -#endif -} - - - -GLsizei GPU_select_end(void) -{ - GPU_ASSERT(!gpu_aspect_active()); - GPU_ASSERT(IS_SELECT_MODE); - - IS_SELECT_MODE = false; - -#if defined(WITH_GL_PROFILE_COMPAT) - return glRenderMode(GL_RENDER); -#else - return 0; -#endif -} - - - -void GPU_select_clear(void) -{ - if (IS_SELECT_MODE) { -#if defined(WITH_GL_PROFILE_COMPAT) - glInitNames(); -#endif + else { + int i; + + if (g_query_state.query_issued) { + glEndQueryARB(GL_SAMPLES_PASSED_ARB); + } + + for (i = 0; i < g_query_state.active_query; i++) { + unsigned int result; + glGetQueryObjectuivARB(g_query_state.queries[i], GL_QUERY_RESULT_ARB, &result); + if (result > 0) { + if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) { + if(hits < g_query_state.bufsize) { + g_query_state.buffer[hits * 4] = 1; + g_query_state.buffer[hits * 4 + 1] = 0xFFFF; + g_query_state.buffer[hits * 4 + 2] = 0xFFFF; + g_query_state.buffer[hits * 4 + 3] = g_query_state.id[i]; + + hits++; + } + else { + hits = -1; + break; + } + } + else { + int j; + /* search in buffer and make selected object first */ + for (j = 0; j < g_query_state.oldhits; j++) { + if (g_query_state.buffer[j * 4 + 3] == g_query_state.id[i]) { + g_query_state.buffer[j * 4 + 1] = 0; + g_query_state.buffer[j * 4 + 2] = 0; + } + } + break; + } + } + } + + glDeleteQueriesARB(g_query_state.num_of_queries, g_query_state.queries); + MEM_freeN(g_query_state.queries); + MEM_freeN(g_query_state.id); + glPopAttrib(); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } -} + g_query_state.select_is_active = false; - -void GPU_select_pop(void) -{ - if (IS_SELECT_MODE) { -#if defined(WITH_GL_PROFILE_COMPAT) - glPopName(); -#endif - } + return hits; } - -void GPU_select_push(GLuint name) +bool GPU_select_query_check_support(void) { - if (IS_SELECT_MODE) { -#if defined(WITH_GL_PROFILE_COMPAT) - glPushName(name); -#endif - } + return GLEW_ARB_occlusion_query; } - -void GPU_select_load(GLuint name) +bool GPU_select_query_check_active(void) { - if (IS_SELECT_MODE) { -#if defined(WITH_GL_PROFILE_COMPAT) - glLoadName(name); -#endif - } + return GLEW_ARB_occlusion_query && + ((U.gpu_select_method == USER_SELECT_USE_OCCLUSION_QUERY) || + ((U.gpu_select_method == USER_SELECT_AUTO) && GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY))); } diff --git a/source/blender/gpu/intern/gpu_utility.c b/source/blender/gpu/intern/gpu_utility.c index 999a44a91c1..285701af1aa 100644 --- a/source/blender/gpu/intern/gpu_utility.c +++ b/source/blender/gpu/intern/gpu_utility.c @@ -57,7 +57,7 @@ const char* gpuErrorString(GLenum err) case GL_OUT_OF_MEMORY: return "Out of Memory"; -#if GL_ARB_imagining +#ifdef GL_ARB_imagining case GL_TABLE_TOO_LARGE: return "Table Too Large"; #endif @@ -102,7 +102,7 @@ const char* gpuErrorSymbol(GLenum err) case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; -#if GL_ARB_imagining +#ifdef GL_ARB_imagining case GL_TABLE_TOO_LARGE: return "GL_TABLE_TOO_LARGE"; #endif diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index d5d0c7ef454..3ba36c11311 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1012,6 +1012,38 @@ void mtex_rgb_color(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i incol.rgb = col.rgb; } +void mtex_rgb_soft(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) +{ + float facm; + + fact *= facg; + facm = 1.0-fact; + + vec3 one = vec3(1.0); + vec3 scr = one - (one - texcol)*(one - outcol); + incol = facm*outcol + fact*((one - texcol)*outcol*texcol + outcol*scr); +} + +void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) +{ + fact *= facg; + + if(texcol.r > 0.5) + incol.r = outcol.r + fact*(2.0*(texcol.r - 0.5)); + else + incol.r = outcol.r + fact*(2.0*(texcol.r) - 1.0); + + if(texcol.g > 0.5) + incol.g = outcol.g + fact*(2.0*(texcol.g - 0.5)); + else + incol.g = outcol.g + fact*(2.0*(texcol.g) - 1.0); + + if(texcol.b > 0.5) + incol.b = outcol.b + fact*(2.0*(texcol.b - 0.5)); + else + incol.b = outcol.b + fact*(2.0*(texcol.b) - 1.0); +} + void mtex_value_vars(inout float fact, float facg, out float facm) { fact *= abs(facg); @@ -1179,7 +1211,12 @@ void mtex_mapping_size(vec3 texco, vec3 size, out vec3 outtexco) void mtex_2d_mapping(vec3 vec, out vec3 outvec) { - outvec = vec3(vec.xy*0.5 + vec2(0.5, 0.5), vec.z); + outvec = vec3(vec.xy*0.5 + vec2(0.5), vec.z); +} + +vec3 mtex_2d_mapping(vec3 vec) +{ + return vec3(vec.xy*0.5 + vec2(0.5), vec.z); } void mtex_image(vec3 texco, sampler2D ima, out float value, out vec4 color) @@ -2257,6 +2294,11 @@ void node_attribute(vec3 attr_uv, out vec4 outcol, out vec3 outvec, out float ou outf = (attr_uv.x + attr_uv.y + attr_uv.z)/3.0; } +void node_uvmap(vec3 attr_uv, out vec3 outvec) +{ + outvec = attr_uv; +} + void node_geometry(vec3 I, vec3 N, mat4 toworld, out vec3 position, out vec3 normal, out vec3 tangent, out vec3 true_normal, out vec3 incoming, out vec3 parametric, @@ -2280,14 +2322,18 @@ void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object, out vec3 camera, out vec3 window, out vec3 reflection) { - generated = attr_orco; + generated = mtex_2d_mapping(attr_orco); normal = normalize((obinvmat*(viewinvmat*vec4(N, 0.0))).xyz); uv = attr_uv; object = (obinvmat*(viewinvmat*vec4(I, 1.0))).xyz; camera = I; - window = gl_FragCoord.xyz; - reflection = reflect(N, I); + vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0); + window = mtex_2d_mapping(projvec.xyz/projvec.w); + vec3 shade_I; + shade_view(I, shade_I); + vec3 view_reflection = reflect(shade_I, normalize(N)); + reflection = (viewinvmat*vec4(view_reflection, 0.0)).xyz; } /* textures */ diff --git a/source/blender/gpu/shaders/gpu_shader_simple_vert.glsl b/source/blender/gpu/shaders/gpu_shader_simple_vert.glsl new file mode 100644 index 00000000000..8ccd0feb5e2 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_simple_vert.glsl @@ -0,0 +1,54 @@ + +#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING) +varying vec3 varying_normal; + +#ifndef USE_SOLID_LIGHTING +varying vec3 varying_position; +#endif +#endif + +#ifdef USE_COLOR +varying vec4 varying_vertex_color; +#endif + +#ifdef USE_TEXTURE +varying vec2 varying_texture_coord; +#endif + +#ifdef CLIP_WORKAROUND +varying float gl_ClipDistance[6]; +#endif + +void main() +{ + vec4 co = gl_ModelViewMatrix * gl_Vertex; + +#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING) + varying_normal = normalize(gl_NormalMatrix * gl_Normal); + +#ifndef USE_SOLID_LIGHTING + varying_position = co.xyz; +#endif +#endif + + gl_Position = gl_ProjectionMatrix * co; + +#ifdef CLIP_WORKAROUND + int i; + for(i = 0; i < 6; i++) + gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]); +#elif !defined(GPU_ATI) + // Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA + // graphic cards, while on ATI it can cause a software fallback. + gl_ClipVertex = co; +#endif + +#ifdef USE_COLOR + varying_vertex_color = gl_Color; +#endif + +#ifdef USE_TEXTURE + varying_texture_coord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).st; +#endif +} + diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl index 159e531eb44..b5d8dcc0f35 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl @@ -2,6 +2,10 @@ varying vec3 varposition; varying vec3 varnormal; +#ifdef CLIP_WORKAROUND +varying float gl_ClipDistance[6]; +#endif + void main() { vec4 co = gl_ModelViewMatrix * gl_Vertex; @@ -10,9 +14,13 @@ void main() varnormal = normalize(gl_NormalMatrix * gl_Normal); gl_Position = gl_ProjectionMatrix * co; -#ifndef GPU_ATI +#ifdef CLIP_WORKAROUND + int i; + for(i = 0; i < 6; i++) + gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]); +#elif !defined(GPU_ATI) // Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA // graphic cards, while on ATI it can cause a software fallback. - gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex; + gl_ClipVertex = co; #endif diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c index 80c508267f3..cd09b56b262 100644 --- a/source/blender/ikplugin/intern/iksolver_plugin.c +++ b/source/blender/ikplugin/intern/iksolver_plugin.c @@ -215,7 +215,7 @@ static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[3][3]) // nr = copy_m4_m3(ikmat, ik_mat); if (pchan->parent) - mul_serie_m4(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat); else mul_m4_m4m4(pchan->pose_mat, pchan->chan_mat, ikmat); @@ -420,7 +420,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree) /* end effector in world space */ copy_m4_m4(end_pose, pchan->pose_mat); copy_v3_v3(end_pose[3], pchan->pose_tail); - mul_serie_m4(world_pose, goalinv, ob->obmat, end_pose, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(world_pose, goalinv, ob->obmat, end_pose); /* blend position */ goalpos[0] = fac * goalpos[0] + mfac * world_pose[3][0]; diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index dbc4100e287..5077ccec256 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -566,7 +566,7 @@ static bool target_callback(const iTaSC::Timestamp& timestamp, const iTaSC::Fram float chanmat[4][4]; copy_m4_m4(chanmat, pchan->pose_mat); copy_v3_v3(chanmat[3], pchan->pose_tail); - mul_serie_m4(restmat, target->owner->obmat, chanmat, target->eeRest, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(restmat, target->owner->obmat, chanmat, target->eeRest); } else { mul_m4_m4m4(restmat, target->owner->obmat, target->eeRest); diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 090e7a66d41..ce6a7eb1c47 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -163,6 +163,22 @@ typedef enum IMB_BlendMode { IMB_BLEND_DARKEN = 5, IMB_BLEND_ERASE_ALPHA = 6, IMB_BLEND_ADD_ALPHA = 7, + IMB_BLEND_OVERLAY = 8, + IMB_BLEND_HARDLIGHT = 9, + IMB_BLEND_COLORBURN = 10, + IMB_BLEND_LINEARBURN = 11, + IMB_BLEND_COLORDODGE = 12, + IMB_BLEND_SCREEN = 13, + IMB_BLEND_SOFTLIGHT = 14, + IMB_BLEND_PINLIGHT = 15, + IMB_BLEND_VIVIDLIGHT = 16, + IMB_BLEND_LINEARLIGHT = 17, + IMB_BLEND_DIFFERENCE = 18, + IMB_BLEND_EXCLUSION = 19, + IMB_BLEND_HUE = 20, + IMB_BLEND_SATURATION = 21, + IMB_BLEND_LUMINOSITY = 22, + IMB_BLEND_COLOR = 23, IMB_BLEND_COPY = 1000, IMB_BLEND_COPY_RGB = 1001, @@ -179,9 +195,9 @@ void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx, void IMB_rectcpy(struct ImBuf *drect, struct ImBuf *srect, int destx, int desty, int srcx, int srcy, int width, int height); void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *obuf, struct ImBuf *sbuf, - unsigned short *dmask, unsigned short *smask, unsigned short mask_max, + unsigned short *dmask, unsigned short *curvemask, unsigned short *mmask, float mask_max, int destx, int desty, int origx, int origy, int srcx, int srcy, - int width, int height, IMB_BlendMode mode); + int width, int height, IMB_BlendMode mode, bool accumulate); /** * diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c index e8cb550fc05..880df0ce5c3 100644 --- a/source/blender/imbuf/intern/cineon/cineonlib.c +++ b/source/blender/imbuf/intern/cineon/cineonlib.c @@ -39,10 +39,6 @@ #include "BLI_fileops.h" #include "BLI_utildefines.h" -#if defined(_MSC_VER) && (_MSC_VER <= 1500) -#include "BLI_math_base.h" -#endif - #include "MEM_guardedalloc.h" /* diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c index 84f80faeacc..626d05b05c5 100644 --- a/source/blender/imbuf/intern/cineon/dpxlib.c +++ b/source/blender/imbuf/intern/cineon/dpxlib.c @@ -39,10 +39,6 @@ #include "BLI_fileops.h" #include "BLI_utildefines.h" -#if defined(_MSC_VER) && (_MSC_VER <= 1500) -#include "BLI_math_base.h" -#endif - #include "MEM_guardedalloc.h" /* diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 696e34e58cb..06dd128137b 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -3044,7 +3044,7 @@ static void update_glsl_display_processor(const ColorManagedViewSettings *view_s global_glsl_state.exposure = view_settings->exposure; global_glsl_state.gamma = view_settings->gamma; - /* We're using curve mapping's address as a acache ID, + /* We're using curve mapping's address as a cache ID, * so we need to make sure re-allocation gives new address here. * We do this by allocating new curve mapping before freeing ol one. */ diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index 9975c58bdd2..03cd5ecd646 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -720,6 +720,7 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w ibuf->channels, IB_PROFILE_SRGB, profile_from, true, w, h, w, ibuf->x); + IMB_buffer_float_unpremultiply(buffer, w, h); /* XXX: need to convert to image buffer's rect space */ IMB_buffer_byte_from_float(rect_byte, buffer, 4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0, diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 2dca3114765..ba1bda640a6 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -48,7 +48,7 @@ extern "C" { // The following prevents a linking error in debug mode for MSVC using the libs in CVS -#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(_DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__) +#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__) _CRTIMP void __cdecl _invalid_parameter_noinfo(void) { } @@ -896,7 +896,7 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa echan->chan_id = name[0]; layname[0] = '\0'; - if (ELEM4(name[0], 'R', 'G', 'B', 'A')) + if (ELEM(name[0], 'R', 'G', 'B', 'A')) strcpy(passname, "Combined"); else if (name[0] == 'Z') strcpy(passname, "Depth"); @@ -927,9 +927,9 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa * * Here we do some magic to distinguish such cases. */ - if (ELEM3(token[1], 'X', 'Y', 'Z') || - ELEM3(token[1], 'R', 'G', 'B') || - ELEM3(token[1], 'U', 'V', 'A')) + if (ELEM(token[1], 'X', 'Y', 'Z') || + ELEM(token[1], 'R', 'G', 'B') || + ELEM(token[1], 'U', 'V', 'A')) { echan->chan_id = token[1]; ok = true; diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index 6df7587ee5c..dd2406e234e 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -65,6 +65,39 @@ void IMB_blend_color_byte(unsigned char dst[4], unsigned char src1[4], unsigned blend_color_erase_alpha_byte(dst, src1, src2); break; case IMB_BLEND_ADD_ALPHA: blend_color_add_alpha_byte(dst, src1, src2); break; + case IMB_BLEND_OVERLAY: + blend_color_overlay_byte(dst, src1, src2); break; + case IMB_BLEND_HARDLIGHT: + blend_color_hardlight_byte(dst, src1, src2); break; + case IMB_BLEND_COLORBURN: + blend_color_burn_byte(dst, src1, src2); break; + case IMB_BLEND_LINEARBURN: + blend_color_linearburn_byte(dst, src1, src2); break; + case IMB_BLEND_COLORDODGE: + blend_color_dodge_byte(dst, src1, src2); break; + case IMB_BLEND_SCREEN: + blend_color_screen_byte(dst, src1, src2); break; + case IMB_BLEND_SOFTLIGHT: + blend_color_softlight_byte(dst, src1, src2); break; + case IMB_BLEND_PINLIGHT: + blend_color_pinlight_byte(dst, src1, src2); break; + case IMB_BLEND_LINEARLIGHT: + blend_color_linearlight_byte(dst, src1, src2); break; + case IMB_BLEND_VIVIDLIGHT: + blend_color_vividlight_byte(dst, src1, src2); break; + case IMB_BLEND_DIFFERENCE: + blend_color_difference_byte(dst, src1, src2); break; + case IMB_BLEND_EXCLUSION: + blend_color_exclusion_byte(dst, src1, src2); break; + case IMB_BLEND_COLOR: + blend_color_color_byte(dst, src1, src2); break; + case IMB_BLEND_HUE: + blend_color_hue_byte(dst, src1, src2); break; + case IMB_BLEND_SATURATION: + blend_color_saturation_byte(dst, src1, src2); break; + case IMB_BLEND_LUMINOSITY: + blend_color_luminosity_byte(dst, src1, src2); break; + default: dst[0] = src1[0]; dst[1] = src1[1]; @@ -93,6 +126,38 @@ void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_Blend blend_color_erase_alpha_float(dst, src1, src2); break; case IMB_BLEND_ADD_ALPHA: blend_color_add_alpha_float(dst, src1, src2); break; + case IMB_BLEND_OVERLAY: + blend_color_overlay_float(dst, src1, src2); break; + case IMB_BLEND_HARDLIGHT: + blend_color_hardlight_float(dst, src1, src2); break; + case IMB_BLEND_COLORBURN: + blend_color_burn_float(dst, src1, src2); break; + case IMB_BLEND_LINEARBURN: + blend_color_linearburn_float(dst, src1, src2); break; + case IMB_BLEND_COLORDODGE: + blend_color_dodge_float(dst, src1, src2); break; + case IMB_BLEND_SCREEN: + blend_color_screen_float(dst, src1, src2); break; + case IMB_BLEND_SOFTLIGHT: + blend_color_softlight_float(dst, src1, src2); break; + case IMB_BLEND_PINLIGHT: + blend_color_pinlight_float(dst, src1, src2); break; + case IMB_BLEND_LINEARLIGHT: + blend_color_linearlight_float(dst, src1, src2); break; + case IMB_BLEND_VIVIDLIGHT: + blend_color_vividlight_float(dst, src1, src2); break; + case IMB_BLEND_DIFFERENCE: + blend_color_difference_float(dst, src1, src2); break; + case IMB_BLEND_EXCLUSION: + blend_color_exclusion_float(dst, src1, src2); break; + case IMB_BLEND_COLOR: + blend_color_color_float(dst, src1, src2); break; + case IMB_BLEND_HUE: + blend_color_hue_float(dst, src1, src2); break; + case IMB_BLEND_SATURATION: + blend_color_saturation_float(dst, src1, src2); break; + case IMB_BLEND_LUMINOSITY: + blend_color_luminosity_float(dst, src1, src2); break; default: dst[0] = src1[0]; dst[1] = src1[1]; @@ -226,22 +291,23 @@ static void imb_rectclip3(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, int *destx, void IMB_rectcpy(ImBuf *dbuf, ImBuf *sbuf, int destx, int desty, int srcx, int srcy, int width, int height) { - IMB_rectblend(dbuf, dbuf, sbuf, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, width, height, IMB_BLEND_COPY); + IMB_rectblend(dbuf, dbuf, sbuf, NULL, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, width, height, IMB_BLEND_COPY, false); } typedef void (*IMB_blend_func)(unsigned char *dst, const unsigned char *src1, const unsigned char *src2); typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2); -void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, - unsigned short *smask, unsigned short mask_max, +void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, unsigned short *curvemask, + unsigned short *texmask, float mask_max, int destx, int desty, int origx, int origy, int srcx, int srcy, int width, int height, - IMB_BlendMode mode) + IMB_BlendMode mode, bool accumulate) { unsigned int *drect = NULL, *orect, *srect = NULL, *dr, *or, *sr; float *drectf = NULL, *orectf, *srectf = NULL, *drf, *orf, *srf; - unsigned short *smaskrect = smask, *smr; + unsigned short *cmaskrect = curvemask, *cmr; unsigned short *dmaskrect = dmask, *dmr; + unsigned short *texmaskrect = texmask, *tmr; int do_float, do_char, srcskip, destskip, origskip, x; IMB_blend_func func = NULL; IMB_blend_func_float func_float = NULL; @@ -277,8 +343,11 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx) * 4; srcskip = sbuf->x; - if (smaskrect) - smaskrect += srcy * sbuf->x + srcx; + if (cmaskrect) + cmaskrect += srcy * sbuf->x + srcx; + + if (texmaskrect) + texmaskrect += srcy * sbuf->x + srcx; } else { srect = drect; @@ -388,6 +457,70 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, func = blend_color_add_alpha_byte; func_float = blend_color_add_alpha_float; break; + case IMB_BLEND_OVERLAY: + func = blend_color_overlay_byte; + func_float = blend_color_overlay_float; + break; + case IMB_BLEND_HARDLIGHT: + func = blend_color_hardlight_byte; + func_float = blend_color_hardlight_float; + break; + case IMB_BLEND_COLORBURN: + func = blend_color_burn_byte; + func_float = blend_color_burn_float; + break; + case IMB_BLEND_LINEARBURN: + func = blend_color_linearburn_byte; + func_float = blend_color_linearburn_float; + break; + case IMB_BLEND_COLORDODGE: + func = blend_color_dodge_byte; + func_float = blend_color_dodge_float; + break; + case IMB_BLEND_SCREEN: + func = blend_color_screen_byte; + func_float = blend_color_screen_float; + break; + case IMB_BLEND_SOFTLIGHT: + func = blend_color_softlight_byte; + func_float = blend_color_softlight_float; + break; + case IMB_BLEND_PINLIGHT: + func = blend_color_pinlight_byte; + func_float = blend_color_pinlight_float; + break; + case IMB_BLEND_LINEARLIGHT: + func = blend_color_linearlight_byte; + func_float = blend_color_linearlight_float; + break; + case IMB_BLEND_VIVIDLIGHT: + func = blend_color_vividlight_byte; + func_float = blend_color_vividlight_float; + break; + case IMB_BLEND_DIFFERENCE: + func = blend_color_difference_byte; + func_float = blend_color_difference_float; + break; + case IMB_BLEND_EXCLUSION: + func = blend_color_exclusion_byte; + func_float = blend_color_exclusion_float; + break; + case IMB_BLEND_COLOR: + func = blend_color_color_byte; + func_float = blend_color_color_float; + break; + case IMB_BLEND_HUE: + func = blend_color_hue_byte; + func_float = blend_color_hue_float; + break; + case IMB_BLEND_SATURATION: + func = blend_color_saturation_byte; + func_float = blend_color_saturation_float; + break; + case IMB_BLEND_LUMINOSITY: + func = blend_color_luminosity_byte; + func_float = blend_color_luminosity_float; + break; default: break; } @@ -399,21 +532,60 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, or = orect; sr = srect; - if (dmaskrect && smaskrect) { + if (cmaskrect) { /* mask accumulation for painting */ - dmr = dmaskrect; - smr = smaskrect; + cmr = cmaskrect; + tmr = texmaskrect; - for (x = width; x > 0; x--, dr++, or++, sr++, dmr++, smr++) { - unsigned char *src = (unsigned char *)sr; + /* destination mask present, do max alpha masking */ + if (dmaskrect) { + dmr = dmaskrect; + for (x = width; x > 0; x--, dr++, or++, sr++, dmr++, cmr++) { + unsigned char *src = (unsigned char *)sr; + float mask_lim = mask_max * (*cmr); - if (src[3] && *smr) { - unsigned short mask = *dmr + (((mask_max - *dmr) * (*smr)) / 65535); + if (texmaskrect) + mask_lim *= ((*tmr++) / 65535.0f); - if (mask > *dmr) { - unsigned char mask_src[4]; + if (src[3] && mask_lim) { + float mask; + + if (accumulate) + mask = *dmr + mask_lim; + else + mask = *dmr + mask_lim - (*dmr * (*cmr / 65535.0f)); + + mask = min_ff(mask, 65535.0); + + if (mask > *dmr) { + unsigned char mask_src[4]; + + *dmr = mask; - *dmr = mask; + mask_src[0] = src[0]; + mask_src[1] = src[1]; + mask_src[2] = src[2]; + mask_src[3] = divide_round_i(src[3] * mask, 65535); + + func((unsigned char *)dr, (unsigned char *)or, mask_src); + } + } + } + dmaskrect += origskip; + } + /* no destination mask buffer, do regular blend with masktexture if present */ + else { + for (x = width; x > 0; x--, dr++, or++, sr++, cmr++) { + unsigned char *src = (unsigned char *)sr; + float mask = (float)mask_max * ((float)(*cmr)); + + if (texmaskrect) + mask *= ((float)(*tmr++) / 65535.0f); + + mask = min_ff(mask, 65535.0); + + if (src[3] && (mask > 0.0f)) { + unsigned char mask_src[4]; mask_src[0] = src[0]; mask_src[1] = src[1]; @@ -425,8 +597,9 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, } } - dmaskrect += origskip; - smaskrect += srcskip; + cmaskrect += srcskip; + if (texmaskrect) + texmaskrect += srcskip; } else { /* regular blending */ @@ -446,28 +619,65 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, orf = orectf; srf = srectf; - if (dmaskrect && smaskrect) { + if (cmaskrect) { /* mask accumulation for painting */ - dmr = dmaskrect; - smr = smaskrect; + cmr = cmaskrect; + tmr = texmaskrect; + + /* destination mask present, do max alpha masking */ + if (dmaskrect) { + dmr = dmaskrect; + for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, dmr++, cmr++) { + float mask_lim = mask_max * (*cmr); + + if (texmaskrect) + mask_lim *= ((*tmr++) / 65535.0f); + + if (srf[3] && mask_lim) { + float mask; + + if (accumulate) + mask = min_ff(*dmr + mask_lim, 65535.0); + else + mask = *dmr + mask_lim - (*dmr * (*cmr / 65535.0f)); + + mask = min_ff(mask, 65535.0); + + if (mask > *dmr) { + float mask_srf[4]; + + *dmr = mask; + mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); + + func_float(drf, orf, mask_srf); + } + } + } + dmaskrect += origskip; + } + /* no destination mask buffer, do regular blend with masktexture if present */ + else { + for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, cmr++) { + float mask = (float)mask_max * ((float)(*cmr)); + + if (texmaskrect) + mask *= ((float)(*tmr++) / 65535.0f); - for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, dmr++, smr++) { - if (srf[3] != 0 && *smr) { - unsigned short mask = *dmr + (((mask_max - *dmr) * (*smr)) / 65535); + mask = min_ff(mask, 65535.0); - if (mask > *dmr) { + if (srf[3] && (mask > 0.0f)) { float mask_srf[4]; - *dmr = mask; - mul_v4_v4fl(mask_srf, srf, mask * (1.0f / 65535.0f)); + mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); func_float(drf, orf, mask_srf); } } } - dmaskrect += origskip; - smaskrect += srcskip; + cmaskrect += srcskip; + if (texmaskrect) + texmaskrect += srcskip; } else { /* regular blending */ diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c index c98b39c826b..e480f06da2b 100644 --- a/source/blender/imbuf/intern/scaling.c +++ b/source/blender/imbuf/intern/scaling.c @@ -33,6 +33,7 @@ #include "BLI_utildefines.h" +#include "BLI_math_base.h" #include "BLI_math_color.h" #include "BLI_math_interp.h" #include "MEM_guardedalloc.h" @@ -51,26 +52,17 @@ /************************************************************************/ -struct ImBuf *IMB_half_x(struct ImBuf *ibuf1) +static void imb_half_x_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1) { - struct ImBuf *ibuf2; uchar *p1, *_p1, *dest; short a, r, g, b; int x, y; float af, rf, gf, bf, *p1f, *_p1f, *destf; bool do_rect, do_float; - if (ibuf1 == NULL) return (NULL); - if (ibuf1->rect == NULL && ibuf1->rect_float == NULL) return (NULL); - do_rect = (ibuf1->rect != NULL); - do_float = (ibuf1->rect_float != NULL); - - if (ibuf1->x <= 1) return(IMB_dupImBuf(ibuf1)); + do_float = (ibuf1->rect_float != NULL && ibuf2->rect_float != NULL); - ibuf2 = IMB_allocImBuf((ibuf1->x) / 2, ibuf1->y, ibuf1->planes, ibuf1->flags); - if (ibuf2 == NULL) return (NULL); - _p1 = (uchar *) ibuf1->rect; dest = (uchar *) ibuf2->rect; @@ -113,9 +105,24 @@ struct ImBuf *IMB_half_x(struct ImBuf *ibuf1) if (do_rect) _p1 += (ibuf1->x << 2); if (do_float) _p1f += (ibuf1->x << 2); } - return (ibuf2); } +struct ImBuf *IMB_half_x(struct ImBuf *ibuf1) +{ + struct ImBuf *ibuf2; + + if (ibuf1 == NULL) return (NULL); + if (ibuf1->rect == NULL && ibuf1->rect_float == NULL) return (NULL); + + if (ibuf1->x <= 1) return(IMB_dupImBuf(ibuf1)); + + ibuf2 = IMB_allocImBuf((ibuf1->x) / 2, ibuf1->y, ibuf1->planes, ibuf1->flags); + if (ibuf2 == NULL) return (NULL); + + imb_half_x_no_alloc(ibuf2, ibuf1); + + return (ibuf2); +} struct ImBuf *IMB_double_fast_x(struct ImBuf *ibuf1) { @@ -170,9 +177,8 @@ struct ImBuf *IMB_double_x(struct ImBuf *ibuf1) } -struct ImBuf *IMB_half_y(struct ImBuf *ibuf1) +static void imb_half_y_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1) { - struct ImBuf *ibuf2; uchar *p1, *p2, *_p1, *dest; short a, r, g, b; int x, y; @@ -181,15 +187,9 @@ struct ImBuf *IMB_half_y(struct ImBuf *ibuf1) p1 = p2 = NULL; p1f = p2f = NULL; - if (ibuf1 == NULL) return (NULL); - if (ibuf1->rect == NULL && ibuf1->rect_float == NULL) return (NULL); - if (ibuf1->y <= 1) return(IMB_dupImBuf(ibuf1)); do_rect = (ibuf1->rect != NULL); - do_float = (ibuf1->rect_float != NULL); - - ibuf2 = IMB_allocImBuf(ibuf1->x, (ibuf1->y) / 2, ibuf1->planes, ibuf1->flags); - if (ibuf2 == NULL) return (NULL); + do_float = (ibuf1->rect_float != NULL && ibuf2->rect_float != NULL); _p1 = (uchar *) ibuf1->rect; dest = (uchar *) ibuf2->rect; @@ -238,6 +238,23 @@ struct ImBuf *IMB_half_y(struct ImBuf *ibuf1) if (do_rect) _p1 += (ibuf1->x << 3); if (do_float) _p1f += (ibuf1->x << 3); } +} + + +struct ImBuf *IMB_half_y(struct ImBuf *ibuf1) +{ + struct ImBuf *ibuf2; + + if (ibuf1 == NULL) return (NULL); + if (ibuf1->rect == NULL && ibuf1->rect_float == NULL) return (NULL); + + if (ibuf1->y <= 1) return(IMB_dupImBuf(ibuf1)); + + ibuf2 = IMB_allocImBuf(ibuf1->x, (ibuf1->y) / 2, ibuf1->planes, ibuf1->flags); + if (ibuf2 == NULL) return (NULL); + + imb_half_y_no_alloc(ibuf2, ibuf1); + return (ibuf2); } @@ -303,24 +320,24 @@ MINLINE void straight_uchar_to_premul_ushort(unsigned short result[4], const uns result[0] = color[0] * alpha; result[1] = color[1] * alpha; result[2] = color[2] * alpha; - result[3] = alpha * 255; + result[3] = alpha * 256; } MINLINE void premul_ushort_to_straight_uchar(unsigned char *result, const unsigned short color[4]) { if (color[3] <= 255) { - result[0] = color[0] / 255; - result[1] = color[1] / 255; - result[2] = color[2] / 255; - result[3] = color[3] / 255; + result[0] = USHORTTOUCHAR(color[0]); + result[1] = USHORTTOUCHAR(color[1]); + result[2] = USHORTTOUCHAR(color[2]); + result[3] = USHORTTOUCHAR(color[3]); } else { - unsigned short alpha = color[3] / 255; + unsigned short alpha = color[3] / 256; - result[0] = color[0] / alpha; - result[1] = color[1] / alpha; - result[2] = color[2] / alpha; - result[3] = alpha; + result[0] = USHORTTOUCHAR(color[0] / alpha * 256); + result[1] = USHORTTOUCHAR(color[1] / alpha * 256); + result[2] = USHORTTOUCHAR(color[2] / alpha * 256); + result[3] = USHORTTOUCHAR(color[3]); } } @@ -335,28 +352,38 @@ void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1) imb_addrectImBuf(ibuf2); } + if (ibuf1->x <= 1) { + imb_half_y_no_alloc(ibuf2, ibuf1); + return; + } + if (ibuf1->y <= 1) { + imb_half_x_no_alloc(ibuf2, ibuf1); + return; + } + if (do_rect) { unsigned char *cp1, *cp2, *dest; cp1 = (unsigned char *) ibuf1->rect; dest = (unsigned char *) ibuf2->rect; + for (y = ibuf2->y; y > 0; y--) { cp2 = cp1 + (ibuf1->x << 2); for (x = ibuf2->x; x > 0; x--) { unsigned short p1i[8], p2i[8], desti[4]; - + straight_uchar_to_premul_ushort(p1i, cp1); straight_uchar_to_premul_ushort(p2i, cp2); straight_uchar_to_premul_ushort(p1i + 4, cp1 + 4); straight_uchar_to_premul_ushort(p2i + 4, cp2 + 4); - + desti[0] = ((unsigned int) p1i[0] + p2i[0] + p1i[4] + p2i[4]) >> 2; desti[1] = ((unsigned int) p1i[1] + p2i[1] + p1i[5] + p2i[5]) >> 2; desti[2] = ((unsigned int) p1i[2] + p2i[2] + p1i[6] + p2i[6]) >> 2; desti[3] = ((unsigned int) p1i[3] + p2i[3] + p1i[7] + p2i[7]) >> 2; - + premul_ushort_to_straight_uchar(dest, desti); - + cp1 += 8; cp2 += 8; dest += 4; @@ -1353,7 +1380,7 @@ static ImBuf *scaleupy(struct ImBuf *ibuf, int newy) val_g += 0.5f; val_r = rect[3]; - nval_r = rect[skipx + 4]; + nval_r = rect[skipx + 3]; diff_r = nval_r - val_r; val_r += 0.5f; diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index b912c3e229a..32100aa2288 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -254,10 +254,6 @@ static int isqtime(const char *name) #ifdef WITH_FFMPEG -#if defined(_MSC_VER) && _MSC_VER < 1800 -#define va_copy(dst, src) ((dst) = (src)) -#endif - /* BLI_vsnprintf in ffmpeg_log_callback() causes invalid warning */ #ifdef __GNUC__ # pragma GCC diagnostic push diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index f429360e1cf..8483e5f08f9 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -168,14 +168,10 @@ typedef struct PreviewImage { #ifdef __BIG_ENDIAN__ /* big endian */ -# define MAKE_ID2(c, d) ( (c)<<8 | (d) ) -# define MOST_SIG_BYTE 0 -# define BBIG_ENDIAN +# define MAKE_ID2(c, d) ((c) << 8 | (d)) #else /* little endian */ -# define MAKE_ID2(c, d) ( (d)<<8 | (c) ) -# define MOST_SIG_BYTE 1 -# define BLITTLE_ENDIAN +# define MAKE_ID2(c, d) ((d) << 8 | (c)) #endif /* ID from database */ @@ -213,6 +209,8 @@ typedef struct PreviewImage { #define ID_MC MAKE_ID2('M', 'C') /* MovieClip */ #define ID_MSK MAKE_ID2('M', 'S') /* Mask */ #define ID_LS MAKE_ID2('L', 'S') /* FreestyleLineStyle */ +#define ID_PAL MAKE_ID2('P', 'L') /* Palette */ +#define ID_PC MAKE_ID2('P', 'C') /* Paint Curve */ /* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */ #define ID_SEQ MAKE_ID2('S', 'Q') @@ -235,7 +233,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, 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 5ab799a75e5..dcde9007cd8 100644 --- a/source/blender/makesdna/DNA_actuator_types.h +++ b/source/blender/makesdna/DNA_actuator_types.h @@ -97,6 +97,8 @@ typedef struct bEditObjectActuator { float mass; short localflag; /* flag for the lin & ang. vel: apply locally */ short dyn_operation; + short upflag, trackflag; /* flag for up axis and track axis */ + int pad; } bEditObjectActuator; typedef struct bSceneActuator { @@ -395,6 +397,7 @@ typedef struct bActuator { #define ACT_PROP_ADD 1 #define ACT_PROP_COPY 2 #define ACT_PROP_TOGGLE 3 +#define ACT_PROP_LEVEL 4 /* constraint flag */ #define ACT_CONST_NONE 0 @@ -439,6 +442,19 @@ typedef struct bActuator { /* editObjectActuator->flag */ #define ACT_TRACK_3D 1 +/* editObjectActuator->upflag */ +#define ACT_TRACK_UP_X 0 +#define ACT_TRACK_UP_Y 1 +#define ACT_TRACK_UP_Z 2 + +/* editObjectActuator->trackflag */ +#define ACT_TRACK_TRAXIS_X 0 +#define ACT_TRACK_TRAXIS_Y 1 +#define ACT_TRACK_TRAXIS_Z 2 +#define ACT_TRACK_TRAXIS_NEGX 3 +#define ACT_TRACK_TRAXIS_NEGY 4 +#define ACT_TRACK_TRAXIS_NEGZ 5 + /* editObjectActuator->flag for replace mesh actuator */ #define ACT_EDOB_REPLACE_MESH_NOGFX 2 /* use for replace mesh actuator */ #define ACT_EDOB_REPLACE_MESH_PHYS 4 diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index 390233a433d..3d0d6b820d7 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -793,6 +793,9 @@ typedef enum eInsertKeyFlags { INSERTKEY_REPLACE = (1<<4), /* only replace an existing keyframe (this overrides INSERTKEY_NEEDED) */ INSERTKEY_XYZ2RGB = (1<<5), /* transform F-Curves should have XYZ->RGB color mode */ INSERTKEY_NO_USERPREF = (1 << 6), /* ignore user-prefs (needed for predictable API use) */ + /* Allow to make a full copy of new key into existing one, if any, instead of 'reusing' existing handles. + * Used by copy/paste code. */ + INSERTKEY_OVERWRITE_FULL = (1<<7), } eInsertKeyFlags; /* ************************************************ */ diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 86fa7058f97..9fbd70419f4 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -35,6 +35,7 @@ #include "DNA_ID.h" #include "DNA_texture_types.h" /* for MTex */ +#include "DNA_curve_types.h" //#ifndef MAX_MTEX // XXX Not used? //#define MAX_MTEX 18 @@ -62,6 +63,9 @@ typedef struct Brush { struct ImBuf *icon_imbuf; PreviewImage *preview; + struct ColorBand *gradient; /* color gradient */ + struct PaintCurve *paint_curve; + char icon_filepath[1024]; /* 1024 = FILE_MAX */ float normal_weight; @@ -71,6 +75,7 @@ typedef struct Brush { float weight; /* brush weight */ int size; /* brush diameter */ int flag; /* general purpose flag */ + int mask_pressure; /* pressure influence for mask */ float jitter; /* jitter the position of the brush */ int jitter_absolute; /* absolute jitter in pixels */ int overlay_flags; @@ -82,10 +87,17 @@ typedef struct Brush { float rgb[3]; /* color */ float alpha; /* opacity */ + float secondary_rgb[3]; /* background color */ + int sculpt_plane; /* the direction of movement for sculpt vertices */ float plane_offset; /* offset for plane brushes (clay, flatten, fill, scrape) */ + float pad; + int gradient_spacing; + int gradient_stroke_mode; /* source for stroke color gradient application */ + int gradient_fill_mode; /* source for fill tool color gradient application */ + char sculpt_tool; /* active sculpt tool */ char vertexpaint_tool; /* active vertex/weight paint blend mode (poorly named) */ char imagepaint_tool; /* active image paint tool */ @@ -100,12 +112,21 @@ typedef struct Brush { float texture_sample_bias; + /* overlay */ int texture_overlay_alpha; int mask_overlay_alpha; int cursor_overlay_alpha; float unprojected_radius; + /* soften/sharpen */ + float sharp_threshold; + int blur_kernel_radius; + int blur_mode; + + /* fill tool */ + float fill_threshold; + float add_col[3]; float sub_col[3]; @@ -116,6 +137,52 @@ typedef struct Brush { float mask_stencil_dimension[2]; } Brush; +typedef struct PaletteColor +{ + struct PaletteColor *next, *prev; + /* two values, one to store rgb, other to store values for sculpt/weight */ + float rgb[3]; + float value; +} PaletteColor; + +typedef struct Palette +{ + ID id; + + /* pointer to individual colours */ + ListBase colors; + ListBase deleted; + + int num_of_colours; + int active_color; +} Palette; + +typedef struct PaintCurvePoint +{ + BezTriple bez; /* bezier handle */ + float pressure; /* pressure on that point */ +} PaintCurvePoint; + +typedef struct PaintCurve +{ + ID id; + PaintCurvePoint *points; /* points of curve */ + int tot_points; + int add_index; /* index where next point will be added */ +} PaintCurve; + +/* Brush.gradient_source */ +typedef enum BrushGradientSourceStroke { + BRUSH_GRADIENT_PRESSURE = 0, /* gradient from pressure */ + BRUSH_GRADIENT_SPACING_REPEAT = 1, /* gradient from spacing */ + BRUSH_GRADIENT_SPACING_CLAMP = 2 /* gradient from spacing */ +} BrushGradientSourceStroke; + +typedef enum BrushGradientSourceFill { + BRUSH_GRADIENT_LINEAR = 0, /* gradient from pressure */ + BRUSH_GRADIENT_RADIAL = 1 /* gradient from spacing */ +} BrushGradientSourceFill; + /* Brush.flag */ typedef enum BrushFlags { BRUSH_AIRBRUSH = (1 << 0), @@ -124,7 +191,7 @@ typedef enum BrushFlags { BRUSH_SIZE_PRESSURE = (1 << 3), BRUSH_JITTER_PRESSURE = (1 << 4), BRUSH_SPACING_PRESSURE = (1 << 5), - // BRUSH_FIXED_TEX = (1 << 6), /* obsolete, use mtex->brush_map_mode = MTEX_MAP_MODE_TILED instead */ + BRUSH_UNUSED = (1 << 6), BRUSH_RAKE = (1 << 7), BRUSH_ANCHORED = (1 << 8), BRUSH_DIR_IN = (1 << 9), @@ -138,7 +205,7 @@ typedef enum BrushFlags { BRUSH_SPACE_ATTEN = (1 << 18), BRUSH_ADAPTIVE_SPACE = (1 << 19), BRUSH_LOCK_SIZE = (1 << 20), -// BRUSH_TEXTURE_OVERLAY = (1 << 21), /* obsolete, use overlay_flags |= BRUSH_OVERLAY_PRIMARY instead */ + BRUSH_USE_GRADIENT = (1 << 21), BRUSH_EDGE_TO_EDGE = (1 << 22), BRUSH_DRAG_DOT = (1 << 23), BRUSH_INVERSE_SMOOTH_PRESSURE = (1 << 24), @@ -146,13 +213,16 @@ typedef enum BrushFlags { BRUSH_PLANE_TRIM = (1 << 26), BRUSH_FRONTFACE = (1 << 27), BRUSH_CUSTOM_ICON = (1 << 28), - - /* temporary flag which sets up automatically for correct brush - * drawing when inverted modal operator is running */ - BRUSH_INVERTED = (1 << 29), - BRUSH_ABSOLUTE_JITTER = (1 << 30) + BRUSH_LINE = (1 << 29), + BRUSH_ABSOLUTE_JITTER = (1 << 30), + BRUSH_CURVE = (1 << 31) } BrushFlags; +typedef enum { + BRUSH_MASK_PRESSURE_RAMP = (1 << 1), + BRUSH_MASK_PRESSURE_CUTOFF = (1 << 2) +} BrushMaskPressureFlags; + /* Brush.overlay_flags */ typedef enum OverlayFlags { BRUSH_OVERLAY_CURSOR = (1), @@ -195,7 +265,9 @@ typedef enum BrushImagePaintTool { PAINT_TOOL_DRAW = 0, PAINT_TOOL_SOFTEN = 1, PAINT_TOOL_SMEAR = 2, - PAINT_TOOL_CLONE = 3 + PAINT_TOOL_CLONE = 3, + PAINT_TOOL_FILL = 4, + PAINT_TOOL_MASK = 5 } BrushImagePaintTool; /* direction that the brush displaces along */ @@ -222,6 +294,12 @@ typedef enum { BRUSH_MASK_SMOOTH = 1 } BrushMaskTool; +/* blur kernel types, Brush.blur_mode */ +typedef enum BlurKernelType { + KERNEL_GAUSSIAN, + KERNEL_BOX +} BlurKernelType; + #define MAX_BRUSH_PIXEL_RADIUS 200 #endif diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index e35e4673684..0277956cac5 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -796,7 +796,8 @@ typedef enum ePivotConstraint_Flag { typedef enum eFollowTrack_Flags { FOLLOWTRACK_ACTIVECLIP = (1<<0), - FOLLOWTRACK_USE_3D_POSITION = (1<<1) + FOLLOWTRACK_USE_3D_POSITION = (1<<1), + FOLLOWTRACK_USE_UNDISTORTION = (1<<2) } eFollowTrack_Flags; typedef enum eFollowTrack_FrameMethod { diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index d638d20c6a5..87496fb491f 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -72,7 +72,7 @@ typedef struct Path { # # typedef struct BevPoint { - float vec[3], alfa, radius, weight; + float vec[3], alfa, radius, weight, offset; float sina, cosa; /* 2D Only */ float dir[3], tan[3], quat[4]; /* 3D Only */ short split_tag, dupe_tag; @@ -86,6 +86,8 @@ typedef struct BevList { int nr, dupe_nr; int poly, hole; int charidx; + int *segbevcount; + float *seglen; /* over-alloc */ BevPoint bevpoints[0]; @@ -291,7 +293,7 @@ typedef struct Curve { #define CU_PATH_RADIUS 4096 /* make use of the path radius if this is enabled (default for new curves) */ #define CU_DEFORM_FILL 8192 /* fill 2d curve after deformation */ #define CU_FILL_CAPS 16384 /* fill bevel caps */ -#define CU_MAP_TAPER 32768 /* map taper object to bevelled area */ +#define CU_MAP_TAPER 32768 /* map taper object to beveled area */ /* twist mode */ #define CU_TWIST_Z_UP 0 diff --git a/source/blender/makesdna/DNA_linestyle_types.h b/source/blender/makesdna/DNA_linestyle_types.h index b90aaa7da8c..bac03b4efd7 100644 --- a/source/blender/makesdna/DNA_linestyle_types.h +++ b/source/blender/makesdna/DNA_linestyle_types.h @@ -432,7 +432,7 @@ typedef struct FreestyleLineStyle { unsigned short split_dash2, split_gap2; unsigned short split_dash3, split_gap3; int sort_key, integration_type; - float texstep; + float texstep; short texact, pr_texture; short use_nodes, pad; unsigned short dash1, gap1, dash2, gap2, dash3, gap3; diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 5fda38f52a1..3f94a9cfebb 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -41,6 +41,7 @@ #endif struct MTex; +struct Image; struct ColorBand; struct Group; struct bNodeTree; @@ -82,6 +83,13 @@ typedef struct GameSettings { int pad1; } GameSettings; +typedef struct TexPaintSlot { + struct Image *ima; /* image to be painted on */ + char *uvname; /* customdata index for uv layer, MAX_NAME*/ + int index; /* index for mtex slot in material for blender internal */ + int pad; +} TexPaintSlot; + typedef struct Material { ID id; struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */ @@ -182,8 +190,15 @@ typedef struct Material { float line_col[4]; short line_priority; short vcol_alpha; - int pad4; + /* texture painting */ + short paint_active_slot; + short paint_clone_slot; + short tot_slots; + short pad4[3]; + + struct TexPaintSlot *texpaintslot; /* cached slot for painting. Make sure to recalculate before use + * with refresh_texpaint_image_cache */ ListBase gpumaterial; /* runtime */ } Material; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 7c5846e5819..47782bb3ae1 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -308,6 +308,9 @@ typedef struct BevelModifierData { short val_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 */ + short mat; /* material index if >= 0, else material inherited from surrounding faces */ + short pad; + int pad2; float profile; /* controls profile shape (0->1, .5 is round) */ /* if the MOD_BEVEL_ANGLE is set, this will be how "sharp" an edge must be before it gets beveled */ float bevel_angle; @@ -837,6 +840,7 @@ enum { MOD_SOLIDIFY_VGROUP_INV = (1 << 3), MOD_SOLIDIFY_RIM_MATERIAL = (1 << 4), /* deprecated, used in do_versions */ MOD_SOLIDIFY_FLIP = (1 << 5), + MOD_SOLIDIFY_NOSHELL = (1 << 6), }; #if (DNA_DEPRECATED_GCC_POISON == 1) diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index b13353609c6..e0d25e763d4 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -852,6 +852,12 @@ typedef struct NodeShaderUVMap { char uv_map[64]; } NodeShaderUVMap; +typedef struct NodeSunBeams { + float source[2]; + + float ray_length; +} NodeSunBeams; + /* script node mode */ #define NODE_SCRIPT_INTERNAL 0 #define NODE_SCRIPT_EXTERNAL 1 diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 2e3cd878900..0bcc6bfd70e 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -127,7 +127,7 @@ typedef struct Object { struct Object *proxy, *proxy_group, *proxy_from; struct Ipo *ipo DNA_DEPRECATED; /* old animation system, deprecated for 2.5 */ /* struct Path *path; */ - struct BoundBox *bb; + struct BoundBox *bb; /* axis aligned boundbox (in localspace) */ struct bAction *action DNA_DEPRECATED; // XXX deprecated... old animation system struct bAction *poselib; struct bPose *pose; /* pose data, armature objects only */ @@ -188,6 +188,7 @@ typedef struct Object { char scavisflag; /* more display settings for game logic */ char depsflag; + /* dupli-frame settings */ int dupon, dupoff, dupsta, dupend; int pad; @@ -361,13 +362,13 @@ enum { #define OB_TYPE_SUPPORT_VGROUP(_type) \ (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)) + (ELEM(_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)) + (ELEM(_type, OB_MESH, OB_SURF, OB_CURVE, OB_LATTICE)) /* is this ID type used as object data */ #define OB_DATA_SUPPORT_ID(_id_type) \ - (ELEM8(_id_type, ID_ME, ID_CU, ID_MB, ID_LA, ID_SPK, ID_CA, ID_LT, ID_AR)) + (ELEM(_id_type, ID_ME, ID_CU, ID_MB, ID_LA, ID_SPK, ID_CA, ID_LT, ID_AR)) #define OB_DATA_SUPPORT_ID_CASE \ ID_ME: case ID_CU: case ID_MB: case ID_LA: case ID_SPK: case ID_CA: case ID_LT: case ID_AR diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 6cf2b338308..c8b8e4d52a4 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -811,7 +811,8 @@ typedef struct TimeMarker { /* Paint Tool Base */ typedef struct Paint { struct Brush *brush; - + struct Palette *palette; + /* WM Paint cursor */ void *paint_cursor; unsigned char paint_cursor_col[4]; @@ -840,9 +841,14 @@ typedef struct ImagePaintSettings { short seam_bleed, normal_angle; short screen_grab_size[2]; /* capture size for re-projection */ - int pad1; + int mode; /* mode used for texture painting */ - void *paintcursor; /* wm handle */ + void *paintcursor; /* wm handle */ + struct Image *stencil; /* workaround until we support true layer masks */ + struct Image *clone; /* clone layer for image mode for projective texture painting */ + struct Image *canvas; /* canvas when the explicit system is used for painting */ + float stencil_col[3]; + float pad1; } ImagePaintSettings; /* ------------------------------------------- */ @@ -966,6 +972,11 @@ typedef struct UnifiedPaintSettings { /* unified brush weight, [0, 1] */ float weight; + /* unified brush color */ + float rgb[3]; + /* unified brush secondary color */ + float secondary_rgb[3]; + /* user preferences for sculpt and paint */ int flag; @@ -973,7 +984,6 @@ typedef struct UnifiedPaintSettings { /* record movement of mouse so that rake can start at an intuitive angle */ float last_rake[2]; - int pad; float brush_rotation; @@ -981,7 +991,14 @@ typedef struct UnifiedPaintSettings { * all data below are used to communicate with cursor drawing and tex sampling * *********************************************************************************/ int draw_anchored; - int anchored_size; + int anchored_size; + + char draw_inverted; + char pad3[7]; + + float overlap_factor; /* normalization factor due to accumulated value of curve along spacing. + * Calculated when brush spacing changes to dampen strength of stroke + * if space attenuation is used*/ float anchored_initial_mouse[2]; /* check is there an ongoing stroke right now */ @@ -1001,15 +1018,16 @@ typedef struct UnifiedPaintSettings { struct ColorSpace *colorspace; /* radius of brush, premultiplied with pressure. - * In case of anchored brushes contains that radius */ + * In case of anchored brushes contains the anchored radius */ float pixel_radius; - int pad2; + int pad4; } UnifiedPaintSettings; typedef enum { UNIFIED_PAINT_SIZE = (1 << 0), UNIFIED_PAINT_ALPHA = (1 << 1), UNIFIED_PAINT_WEIGHT = (1 << 5), + UNIFIED_PAINT_COLOR = (1 << 6), /* only used if unified size is enabled, mirrors the brush flags * BRUSH_LOCK_SIZE and BRUSH_SIZE_PRESSURE */ @@ -1620,8 +1638,8 @@ typedef enum eVGroupSelect { #define SCE_FRAME_DROP (1<<3) - /* return flag BKE_scene_base_iter_next function */ -#define F_ERROR -1 + /* return flag BKE_scene_base_iter_next functions */ +/* #define F_ERROR -1 */ /* UNUSED */ #define F_START 0 #define F_SCENE 1 #define F_DUPLI 3 @@ -1647,7 +1665,7 @@ enum { typedef enum { PAINT_SHOW_BRUSH = (1 << 0), PAINT_FAST_NAVIGATE = (1 << 1), - PAINT_SHOW_BRUSH_ON_SURFACE = (1 << 2), + PAINT_SHOW_BRUSH_ON_SURFACE = (1 << 2) } PaintFlags; /* Paint.symmetry_flags @@ -1692,6 +1710,11 @@ typedef enum SculptFlags { SCULPT_DYNTOPO_DETAIL_CONSTANT = (1 << 13) } SculptFlags; +typedef enum ImagePaintMode { + IMAGEPAINT_MODE_MATERIAL, /* detect texture paint slots from the material */ + IMAGEPAINT_MODE_IMAGE, /* select texture paint image directly */ +} ImagePaintMode; + #if (DNA_DEPRECATED_GCC_POISON == 1) #pragma GCC poison SCULPT_SYMM_X SCULPT_SYMM_Y SCULPT_SYMM_Z SCULPT_SYMMETRY_FEATHER #endif diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 38d3c2786ce..8a900c3946e 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -271,12 +271,12 @@ typedef struct ARegion { // #define WIN_EQUAL 3 // UNUSED /* area->flag */ -#define HEADER_NO_PULLDOWN 1 -#define AREA_FLAG_DRAWJOINTO 2 -#define AREA_FLAG_DRAWJOINFROM 4 -#define AREA_TEMP_INFO 8 -#define AREA_FLAG_DRAWSPLIT_H 16 -#define AREA_FLAG_DRAWSPLIT_V 32 +#define HEADER_NO_PULLDOWN (1 << 0) +#define AREA_FLAG_DRAWJOINTO (1 << 1) +#define AREA_FLAG_DRAWJOINFROM (1 << 2) +#define AREA_TEMP_INFO (1 << 3) +#define AREA_FLAG_DRAWSPLIT_H (1 << 4) +#define AREA_FLAG_DRAWSPLIT_V (1 << 5) #define EDGEWIDTH 1 #define AREAGRID 4 @@ -315,6 +315,9 @@ enum { #define PNL_DEFAULT_CLOSED 1 #define PNL_NO_HEADER 2 +/* Fallback panel category (only for old scripts which need updating) */ +#define PNL_CATEGORY_FALLBACK "Misc" + /* uiList layout_type */ enum { UILST_LAYOUT_DEFAULT = 0, diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h index cd1977c0ce3..8d59a13768b 100644 --- a/source/blender/makesdna/DNA_sensor_types.h +++ b/source/blender/makesdna/DNA_sensor_types.h @@ -57,7 +57,9 @@ typedef struct bMouseSensor { short type; short flag; short pad1; - short pad2; + short mode; /* flag to choose material or property */ + char propname[64]; + char matname[64]; } bMouseSensor; /* DEPRECATED */ diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 69d4693ab05..4795048d346 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -249,6 +249,11 @@ typedef struct SpeedControlVars { int lastValidFrame; } SpeedControlVars; +typedef struct GaussianBlurVars { + float size_x; + float size_y; +} GaussianBlurVars; + /* ***************** Sequence modifiers ****************** */ typedef struct SequenceModifierData { @@ -421,7 +426,8 @@ enum { SEQ_TYPE_SPEED = 29, SEQ_TYPE_MULTICAM = 30, SEQ_TYPE_ADJUSTMENT = 31, - SEQ_TYPE_EFFECT_MAX = 31 + SEQ_TYPE_GAUSSIAN_BLUR = 40, + SEQ_TYPE_EFFECT_MAX = 40 }; #define SEQ_MOVIECLIP_RENDER_UNDISTORTED (1 << 0) @@ -434,7 +440,7 @@ enum { */ -#define SEQ_HAS_PATH(_seq) (ELEM4((_seq)->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) +#define SEQ_HAS_PATH(_seq) (ELEM((_seq)->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) /* modifiers */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index c7a6d4809a5..6f57f549efb 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -809,6 +809,8 @@ typedef enum eSpaceImage_Flag { SI_DRAW_OTHER = (1 << 23), SI_COLOR_CORRECTION = (1 << 24), + + SI_NO_DRAW_TEXPAINT = (1 << 25) } eSpaceImage_Flag; /* Text Editor ============================================ */ @@ -989,6 +991,7 @@ typedef enum eSpaceNode_TexFrom { typedef enum eSpaceNode_ShaderFrom { SNODE_SHADER_OBJECT = 0, SNODE_SHADER_WORLD = 1, + SNODE_SHADER_LINESTYLE = 2, } eSpaceNode_ShaderFrom; /* Game Logic Editor ===================================== */ diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 1906f71a230..d256cfb2e85 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -111,9 +111,12 @@ typedef struct CBData { /* 32 = MAXCOLORBAND */ /* note that this has to remain a single struct, for UserDef */ typedef struct ColorBand { - short flag, tot, cur, ipotype; + short tot, cur; + char ipotype, ipotype_hue; + char color_mode; + char pad[1]; + CBData data[32]; - } ColorBand; typedef struct EnvMap { @@ -498,7 +501,6 @@ typedef struct ColorMapping { #define MTEX_BLEND_SAT 11 #define MTEX_BLEND_VAL 12 #define MTEX_BLEND_COLOR 13 -/* free for use */ #define MTEX_SOFT_LIGHT 15 #define MTEX_LIN_LIGHT 16 @@ -510,6 +512,32 @@ typedef struct ColorMapping { #define MTEX_MAP_MODE_RANDOM 4 #define MTEX_MAP_MODE_STENCIL 5 +/* **************** ColorBand ********************* */ + +/* colormode */ +enum { + COLBAND_BLEND_RGB = 0, + COLBAND_BLEND_HSV = 1, + COLBAND_BLEND_HSL = 2, +}; + +/* interpolation */ +enum { + COLBAND_INTERP_LINEAR = 0, + COLBAND_INTERP_EASE = 1, + COLBAND_INTERP_B_SPLINE = 2, + COLBAND_INTERP_CARDINAL = 3, + COLBAND_INTERP_CONSTANT = 4, +}; + +/* color interpolation */ +enum { + COLBAND_HUE_NEAR = 0, + COLBAND_HUE_FAR = 1, + COLBAND_HUE_CW = 2, + COLBAND_HUE_CCW = 3, +}; + /* **************** EnvMap ********************* */ /* type */ @@ -585,7 +613,7 @@ typedef struct ColorMapping { #define TEX_VD_IMAGE_SEQUENCE 3 #define TEX_VD_SMOKE 4 /* for voxels which use VoxelData->source_path */ -#define TEX_VD_IS_SOURCE_PATH(_format) (ELEM3(_format, TEX_VD_BLENDERVOXEL, TEX_VD_RAW_8BIT, TEX_VD_RAW_16BIT)) +#define TEX_VD_IS_SOURCE_PATH(_format) (ELEM(_format, TEX_VD_BLENDERVOXEL, TEX_VD_RAW_8BIT, TEX_VD_RAW_16BIT)) /* smoke data types */ #define TEX_VD_SMOKEDENSITY 0 diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index cb2341b0b7f..ed59014cf75 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -154,7 +154,6 @@ typedef struct uiGradientColors { char high_gradient[4]; int show_grad; int pad2; - } uiGradientColors; typedef struct ThemeUI { @@ -163,7 +162,7 @@ typedef struct ThemeUI { uiWidgetColors wcol_radio, wcol_option, wcol_toggle; uiWidgetColors wcol_num, wcol_numslider; uiWidgetColors wcol_menu, wcol_pulldown, wcol_menu_back, wcol_menu_item, wcol_tooltip; - uiWidgetColors wcol_box, wcol_scroll, wcol_progress, wcol_list_item; + uiWidgetColors wcol_box, wcol_scroll, wcol_progress, wcol_list_item, wcol_pie_menu; uiWidgetStateColors wcol_state; @@ -246,6 +245,7 @@ typedef struct ThemeSpace { char extra_edge_len[4], extra_edge_angle[4], extra_face_angle[4], extra_face_area[4]; char normal[4]; char vertex_normal[4]; + char loop_normal[4]; char bone_solid[4], bone_pose[4], bone_pose_active[4]; char strip[4], strip_select[4]; char cframe[4]; @@ -263,7 +263,7 @@ typedef struct ThemeSpace { char keyborder[4], keyborder_select[4]; char console_output[4], console_input[4], console_info[4], console_error[4]; - char console_cursor[4], console_select[4], pad1[4]; + char console_cursor[4], console_select[4]; char vertex_size, outline_width, facedot_size; char noodle_curving; @@ -328,6 +328,9 @@ typedef struct ThemeSpace { char info_warning[4], info_warning_text[4]; char info_info[4], info_info_text[4]; char info_debug[4], info_debug_text[4]; + + char paint_curve_pivot[4]; + char paint_curve_handle[4]; } ThemeSpace; @@ -489,7 +492,8 @@ typedef struct UserDef { short color_picker_type; char ipo_new; /* interpolation mode for newly added F-Curves */ char keyhandles_new; /* handle types for newly added keyframes */ - char pad1[2]; + char gpu_select_method; + char pad1; short scrcastfps; /* frame rate for screencast to be played back */ short scrcastwait; /* milliseconds between screencast snapshots */ @@ -531,6 +535,15 @@ typedef struct UserDef { float fcu_inactive_alpha; /* opacity of inactive F-Curves in F-Curve Editor */ float pixelsize; /* private, set by GHOST, to multiply DPI with */ + short pie_interaction_type; /* if keeping a pie menu spawn button pressed after this time, it turns into + * a drag/release pie menu */ + short pie_initial_timeout; /* direction in the pie menu will always be calculated from the initial position + * within this time limit */ + int pie_animation_timeout; + int pad2; + short pie_menu_radius; /* pie menu radius */ + short pie_menu_threshold; /* pie menu distance from center before a direction is set */ + struct WalkNavigation walk_navigation; } UserDef; @@ -716,6 +729,13 @@ typedef enum eOpenGL_RenderingOptions { /* USER_DISABLE_AA = (1 << 4), */ /* DEPRECATED */ } eOpenGL_RenderingOptions; +/* selection method for opengl gpu_select_method */ +typedef enum eOpenGL_SelectOptions { + USER_SELECT_AUTO = 0, + USER_SELECT_USE_OCCLUSION_QUERY = 1, + USER_SELECT_USE_SELECT_RENDERMODE = 2 +} eOpenGL_SelectOptions; + /* wm draw method */ typedef enum eWM_DrawMethod { USER_DRAW_TRIPLE = 0, diff --git a/source/blender/makesdna/DNA_vfont_types.h b/source/blender/makesdna/DNA_vfont_types.h index 14ec6c9b312..7025a5767c4 100644 --- a/source/blender/makesdna/DNA_vfont_types.h +++ b/source/blender/makesdna/DNA_vfont_types.h @@ -66,7 +66,7 @@ typedef struct VFont { #define FO_SELCHANGE 10 /* BKE_vfont_to_curve will move the cursor in these cases */ -#define FO_CURS_IS_MOTION(mode) (ELEM4(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN)) +#define FO_CURS_IS_MOTION(mode) (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN)) #define FO_BUILTIN_NAME "<builtin>" diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index add59bafc3f..8cbc198837b 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -262,6 +262,7 @@ extern StructRNA RNA_GameProperty; extern StructRNA RNA_GameSoftBodySettings; extern StructRNA RNA_GameStringProperty; extern StructRNA RNA_GameTimerProperty; +extern StructRNA RNA_GaussianBlurSequence; extern StructRNA RNA_GlowSequence; extern StructRNA RNA_GreasePencil; extern StructRNA RNA_Group; @@ -277,6 +278,7 @@ extern StructRNA RNA_ImagePaint; extern StructRNA RNA_ImageSequence; extern StructRNA RNA_ImageTexture; extern StructRNA RNA_ImageUser; +extern StructRNA RNA_ImapaintToolCapabilities; extern StructRNA RNA_InflowFluidSettings; extern StructRNA RNA_IntProperty; extern StructRNA RNA_Itasc; @@ -427,6 +429,9 @@ extern StructRNA RNA_OrController; extern StructRNA RNA_OutflowFluidSettings; extern StructRNA RNA_PackedFile; extern StructRNA RNA_Paint; +extern StructRNA RNA_PaintCurve; +extern StructRNA RNA_Palette; +extern StructRNA RNA_PaletteColor; extern StructRNA RNA_Panel; extern StructRNA RNA_Particle; extern StructRNA RNA_ParticleBrush; @@ -630,6 +635,7 @@ extern StructRNA RNA_TransformConstraint; extern StructRNA RNA_TransformSequence; extern StructRNA RNA_UILayout; extern StructRNA RNA_UIList; +extern StructRNA RNA_UIPieMenu; extern StructRNA RNA_UIPopupMenu; extern StructRNA RNA_UVWarpModifier; extern StructRNA RNA_UVProjectModifier; @@ -791,6 +797,8 @@ void RNA_property_enum_items(struct bContext *C, PointerRNA *ptr, PropertyRNA *p EnumPropertyItem **item, int *r_totitem, bool *r_free); void RNA_property_enum_items_gettexted(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, EnumPropertyItem **r_item, int *r_totitem, bool *r_free); +void RNA_property_enum_items_gettexted_all(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, + EnumPropertyItem **r_item, int *r_totitem, bool *r_free); bool RNA_property_enum_value(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const char *identifier, int *r_value); bool RNA_property_enum_identifier(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **identifier); bool RNA_property_enum_name(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **name); @@ -924,9 +932,22 @@ bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index); +typedef struct PropertyElemRNA PropertyElemRNA; +struct PropertyElemRNA { + PropertyElemRNA *next, *prev; + PointerRNA ptr; + PropertyRNA *prop; + int index; +}; +bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements); + char *RNA_path_from_ID_to_struct(PointerRNA *ptr); char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop); +char *RNA_path_resolve_from_type_to_property( + struct PointerRNA *ptr, struct PropertyRNA *prop, + const struct StructRNA *type); + char *RNA_path_full_ID_py(struct ID *id); char *RNA_path_full_struct_py(struct PointerRNA *ptr); char *RNA_path_full_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index); diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index ff4caabe636..e6bd9fb79b4 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -264,6 +264,10 @@ if(WITH_BULLET) add_definitions(-DWITH_BULLET) endif() +if(WITH_FREESTYLE) + add_definitions(-DWITH_FREESTYLE) +endif() + # Build makesrna executable blender_include_dirs( . diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript index ff75d9a1721..08cbd6143a5 100644 --- a/source/blender/makesrna/intern/SConscript +++ b/source/blender/makesrna/intern/SConscript @@ -141,6 +141,9 @@ if env['WITH_BF_COLLADA']: if env['WITH_BF_CYCLES']: defs.append('WITH_CYCLES') +if env['WITH_BF_FREESTYLE']: + defs.append('WITH_FREESTYLE') + if env['OURPLATFORM'] == 'linux': cflags='-pthread' diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 7f1f04cdb6a..9023f25e3d5 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -745,6 +745,24 @@ static void rna_clamp_value_range(FILE *f, PropertyRNA *prop) } } +#ifdef USE_RNA_RANGE_CHECK +static void rna_clamp_value_range_check( + FILE *f, PropertyRNA *prop, + const char *dnaname_prefix, const char *dnaname) +{ + if (prop->type == PROP_INT) { + IntPropertyRNA *iprop = (IntPropertyRNA *)prop; + fprintf(f, + " { BLI_STATIC_ASSERT(" + "(TYPEOF_MAX(%s%s) >= %d) && " + "(TYPEOF_MIN(%s%s) <= %d), " + "\"invalid limits\"); }\n", + dnaname_prefix, dnaname, iprop->hardmax, + dnaname_prefix, dnaname, iprop->hardmin); + } +} +#endif /* USE_RNA_RANGE_CHECK */ + static void rna_clamp_value(FILE *f, PropertyRNA *prop, int array) { if (prop->type == PROP_INT) { @@ -944,6 +962,18 @@ static char *rna_def_property_set_func(FILE *f, StructRNA *srna, PropertyRNA *pr } fprintf(f, " }\n"); } + +#ifdef USE_RNA_RANGE_CHECK + if (dp->dnaname && manualfunc == NULL) { + if (dp->dnaarraylength == 1) { + rna_clamp_value_range_check(f, prop, "data->", dp->dnaname); + } + else { + rna_clamp_value_range_check(f, prop, "*data->", dp->dnaname); + } + } +#endif + fprintf(f, "}\n\n"); } else { @@ -975,6 +1005,13 @@ static char *rna_def_property_set_func(FILE *f, StructRNA *srna, PropertyRNA *pr rna_clamp_value(f, prop, 0); } } + +#ifdef USE_RNA_RANGE_CHECK + if (dp->dnaname && manualfunc == NULL) { + rna_clamp_value_range_check(f, prop, "data->", dp->dnaname); + } +#endif + fprintf(f, "}\n\n"); } break; diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 7959e60da33..83fe56102ac 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -153,6 +153,8 @@ short RNA_type_to_ID_code(StructRNA *type) if (RNA_struct_is_a(type, &RNA_WindowManager)) return ID_WM; if (RNA_struct_is_a(type, &RNA_MovieClip)) return ID_MC; if (RNA_struct_is_a(type, &RNA_Mask)) return ID_MSK; + if (RNA_struct_is_a(type, &RNA_Palette)) return ID_PAL; + if (RNA_struct_is_a(type, &RNA_PaintCurve)) return ID_PC; return 0; } @@ -190,6 +192,9 @@ StructRNA *ID_code_to_RNA_type(short idcode) case ID_WM: return &RNA_WindowManager; case ID_MC: return &RNA_MovieClip; case ID_MSK: return &RNA_Mask; + case ID_PAL: return &RNA_Palette; + case ID_PC: return &RNA_PaintCurve; + default: return &RNA_ID; } } @@ -620,6 +625,10 @@ static void rna_def_library(BlenderRNA *brna) prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Library"); RNA_def_property_ui_text(prop, "Parent", ""); + + prop = RNA_def_property(srna, "packed_file", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "packedfile"); + RNA_def_property_ui_text(prop, "Packed File", ""); } void RNA_def_ID(BlenderRNA *brna) { diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index ded0278b44d..34e78018b03 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -55,6 +55,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "WM_api.h" @@ -359,12 +360,12 @@ static bool rna_idproperty_verify_valid(PointerRNA *ptr, PropertyRNA *prop, IDPr if (idprop->subtype == IDP_FLOAT && prop->type != PROP_FLOAT) return false; - if (idprop->subtype == IDP_INT && !ELEM3(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM)) + if (idprop->subtype == IDP_INT && !ELEM(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM)) return false; break; case IDP_INT: - if (!ELEM3(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM)) + if (!ELEM(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM)) return false; break; case IDP_FLOAT: @@ -872,8 +873,8 @@ char RNA_property_array_item_char(PropertyRNA *prop, int index) if ((index < 4) && ELEM(subtype, PROP_QUATERNION, PROP_AXISANGLE)) { return quatitem[index]; } - else if ((index < 4) && ELEM8(subtype, PROP_TRANSLATION, PROP_DIRECTION, PROP_XYZ, PROP_XYZ_LENGTH, - PROP_EULER, PROP_VELOCITY, PROP_ACCELERATION, PROP_COORDS)) + else if ((index < 4) && ELEM(subtype, PROP_TRANSLATION, PROP_DIRECTION, PROP_XYZ, PROP_XYZ_LENGTH, + PROP_EULER, PROP_VELOCITY, PROP_ACCELERATION, PROP_COORDS)) { return vectoritem[index]; } @@ -902,7 +903,7 @@ int RNA_property_array_item_index(PropertyRNA *prop, char name) return 3; } } - else if (ELEM6(subtype, PROP_TRANSLATION, PROP_DIRECTION, PROP_XYZ, + else if (ELEM(subtype, PROP_TRANSLATION, PROP_DIRECTION, PROP_XYZ, PROP_EULER, PROP_VELOCITY, PROP_ACCELERATION)) { switch (name) { @@ -1249,12 +1250,9 @@ void RNA_property_enum_items(bContext *C, PointerRNA *ptr, PropertyRNA *prop, En } } -void RNA_property_enum_items_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop, - EnumPropertyItem **r_item, int *r_totitem, bool *r_free) -{ - RNA_property_enum_items(C, ptr, prop, r_item, r_totitem, r_free); - #ifdef WITH_INTERNATIONAL +static void property_enum_translate(PropertyRNA *prop, EnumPropertyItem **r_item, int *r_totitem, bool *r_free) +{ if (!(prop->flag & PROP_ENUM_NO_TRANSLATE)) { int i; @@ -1300,9 +1298,71 @@ void RNA_property_enum_items_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *r_item = nitem; } +} +#endif + +void RNA_property_enum_items_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop, + EnumPropertyItem **r_item, int *r_totitem, bool *r_free) +{ + RNA_property_enum_items(C, ptr, prop, r_item, r_totitem, r_free); + +#ifdef WITH_INTERNATIONAL + property_enum_translate(prop, r_item, r_totitem, r_free); #endif } +void RNA_property_enum_items_gettexted_all(bContext *C, PointerRNA *ptr, PropertyRNA *prop, + EnumPropertyItem **r_item, int *r_totitem, bool *r_free) +{ + EnumPropertyRNA *eprop = (EnumPropertyRNA *)rna_ensure_property(prop); + int mem_size = sizeof(EnumPropertyItem) * (eprop->totitem + 1); + /* first return all items */ + *r_free = true; + *r_item = MEM_mallocN(mem_size, "enum_gettext_all"); + memcpy(*r_item, eprop->item, mem_size); + + if (r_totitem) + *r_totitem = eprop->totitem; + + if (eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) { + EnumPropertyItem *item; + int i; + bool free = false; + + if (prop->flag & PROP_ENUM_NO_CONTEXT) + item = eprop->itemf(NULL, ptr, prop, &free); + else + item = eprop->itemf(C, ptr, prop, &free); + + /* any callbacks returning NULL should be fixed */ + BLI_assert(item != NULL); + + for (i = 0; i < eprop->totitem; i++) { + bool exists = false; + int i_fixed; + + /* items that do not exist on list are returned, but have their names/identifiers NULLed out */ + for (i_fixed = 0; item[i_fixed].identifier; i_fixed++) { + if (STREQ(item[i_fixed].identifier, (*r_item)[i].identifier)) { + exists = true; + break; + } + } + + if (!exists) { + (*r_item)[i].name = NULL; + (*r_item)[i].identifier = ""; + } + } + + if (free) + MEM_freeN(item); + } + +#ifdef WITH_INTERNATIONAL + property_enum_translate(prop, r_item, r_totitem, r_free); +#endif +} bool RNA_property_enum_value(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const char *identifier, int *r_value) { @@ -3329,7 +3389,7 @@ static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *pro /* check type */ itemtype = RNA_property_type(itemprop); - if (!ELEM3(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { + if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { BKE_report(reports, RPT_ERROR, "Only boolean, int and float properties supported"); return 0; } @@ -3409,7 +3469,7 @@ static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *pro break; } - if (!ELEM3(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { + if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { BKE_report(reports, RPT_ERROR, "Only boolean, int and float properties supported"); err = 1; break; @@ -4015,11 +4075,14 @@ static bool rna_path_parse_array_index(const char **path, PointerRNA *ptr, Prope } static bool rna_path_parse(PointerRNA *ptr, const char *path, - PointerRNA *r_ptr, PropertyRNA **r_prop, int *index, + PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index, + ListBase *r_elements, const bool eval_pointer) { PropertyRNA *prop; PointerRNA curptr; + PropertyElemRNA *prop_elem = NULL; + int index = -1; char fixedbuf[256]; int type; @@ -4061,6 +4124,14 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path, if (!prop) return false; + if (r_elements) { + prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__); + prop_elem->ptr = curptr; + prop_elem->prop = prop; + prop_elem->index = -1; /* index will be added later, if needed. */ + BLI_addtail(r_elements, prop_elem); + } + type = RNA_property_type(prop); /* now look up the value of this property if it is a pointer or @@ -4076,7 +4147,7 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path, curptr = nextptr; prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */ - if (index) *index = -1; + index = -1; } break; } @@ -4093,21 +4164,38 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path, curptr = nextptr; prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */ - if (index) *index = -1; + index = -1; } break; } default: - if (index) { - if (!rna_path_parse_array_index(&path, &curptr, prop, index)) + if (r_index || prop_elem) { + if (!rna_path_parse_array_index(&path, &curptr, prop, &index)) { return false; + } + + if (prop_elem) { + prop_elem->index = index; + } } break; } } - *r_ptr = curptr; - *r_prop = prop; + if (r_ptr) + *r_ptr = curptr; + if (r_prop) + *r_prop = prop; + if (r_index) + *r_index = index; + + if (prop_elem && (prop_elem->ptr.data != curptr.data || prop_elem->prop != prop || prop_elem->index != index)) { + PropertyElemRNA *prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__); + prop_elem->ptr = curptr; + prop_elem->prop = prop; + prop_elem->index = index; + BLI_addtail(r_elements, prop_elem); + } return true; } @@ -4120,7 +4208,7 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path, */ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop) { - if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, true)) + if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, true)) return false; return r_ptr->data != NULL; @@ -4134,7 +4222,7 @@ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prop */ bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) { - if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, true)) + if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, true)) return false; return r_ptr->data != NULL; @@ -4149,7 +4237,7 @@ bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, */ bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop) { - if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, false)) + if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, false)) return false; return r_ptr->data != NULL && *r_prop != NULL; @@ -4165,12 +4253,25 @@ bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_ */ bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) { - if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, false)) + if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, false)) return false; return r_ptr->data != NULL && *r_prop != NULL; } +/** + * Resolve the given RNA Path into a linked list of PropertyElemRNA's. + * + * To be used when complex operations over path are needed, like e.g. get relative paths, to avoid too much + * string operations. + * + * \return True if there was no error while resolving the path + * \note Assumes all pointers provided are valid + */ +bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements) +{ + return rna_path_parse(ptr, path, NULL, NULL, NULL, r_elements, false); +} char *RNA_path_append(const char *path, PointerRNA *UNUSED(ptr), PropertyRNA *prop, int intkey, const char *strkey) { @@ -4498,6 +4599,47 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop) } /** + * \return the path to given ptr/prop from the closest ancestor of given type, if any (else return NULL). + */ +char *RNA_path_resolve_from_type_to_property( + PointerRNA *ptr, PropertyRNA *prop, + const StructRNA *type) +{ + /* Try to recursively find an "type"'d ancestor, + * to handle situations where path from ID is not enough. */ + PointerRNA idptr; + ListBase path_elems = {NULL}; + char *path = NULL; + char *full_path = RNA_path_from_ID_to_property(ptr, prop); + + if (full_path == NULL) { + return NULL; + } + + RNA_id_pointer_create(ptr->id.data, &idptr); + + if (RNA_path_resolve_elements(&idptr, full_path, &path_elems)) { + PropertyElemRNA *prop_elem; + + for (prop_elem = path_elems.last; prop_elem; prop_elem = prop_elem->prev) { + if (RNA_struct_is_a(prop_elem->ptr.type, type)) { + char *ref_path = RNA_path_from_ID_to_struct(&prop_elem->ptr); + if (ref_path) { + path = BLI_strdup(full_path + strlen(ref_path) + 1); /* +1 for the linking '.' */ + MEM_freeN(ref_path); + } + break; + } + } + + BLI_freelistN(&path_elems); + } + + MEM_freeN(full_path); + return path; +} + +/** * Get the ID as a python representation, eg: * bpy.data.foo["bar"] */ @@ -6323,18 +6465,29 @@ bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index) return false; } } - + bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index) { int len, fromlen; + PropertyRNA *fromprop = prop; + + if (prop->magic != RNA_MAGIC) { + /* In case of IDProperty, we have to find the *real* idprop of ptr, + * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */ + prop = (PropertyRNA *)rna_idproperty_find(ptr, ((IDProperty *)fromprop)->name); + /* Even though currently we now prop will always be the 'fromprop', this might not be the case in the future. */ + if (prop == fromprop) { + fromprop = (PropertyRNA *)rna_idproperty_find(fromptr, ((IDProperty *)prop)->name); + } + } /* get the length of the array to work with */ len = RNA_property_array_length(ptr, prop); - fromlen = RNA_property_array_length(fromptr, prop); + fromlen = RNA_property_array_length(fromptr, fromprop); if (len != fromlen) return false; - + /* get and set the default values as appropriate for the various types */ switch (RNA_property_type(prop)) { case PROP_BOOLEAN: @@ -6342,18 +6495,18 @@ bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, if (index == -1) { int *tmparray = MEM_callocN(sizeof(int) * len, "copy - boolean"); - RNA_property_boolean_get_array(fromptr, prop, tmparray); + RNA_property_boolean_get_array(fromptr, fromprop, tmparray); RNA_property_boolean_set_array(ptr, prop, tmparray); MEM_freeN(tmparray); } else { - int value = RNA_property_boolean_get_index(fromptr, prop, index); + int value = RNA_property_boolean_get_index(fromptr, fromprop, index); RNA_property_boolean_set_index(ptr, prop, index, value); } } else { - int value = RNA_property_boolean_get(fromptr, prop); + int value = RNA_property_boolean_get(fromptr, fromprop); RNA_property_boolean_set(ptr, prop, value); } return true; @@ -6362,18 +6515,18 @@ bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, if (index == -1) { int *tmparray = MEM_callocN(sizeof(int) * len, "copy - int"); - RNA_property_int_get_array(fromptr, prop, tmparray); + RNA_property_int_get_array(fromptr, fromprop, tmparray); RNA_property_int_set_array(ptr, prop, tmparray); MEM_freeN(tmparray); } else { - int value = RNA_property_int_get_index(fromptr, prop, index); + int value = RNA_property_int_get_index(fromptr, fromprop, index); RNA_property_int_set_index(ptr, prop, index, value); } } else { - int value = RNA_property_int_get(fromptr, prop); + int value = RNA_property_int_get(fromptr, fromprop); RNA_property_int_set(ptr, prop, value); } return true; @@ -6382,36 +6535,36 @@ bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, if (index == -1) { float *tmparray = MEM_callocN(sizeof(float) * len, "copy - float"); - RNA_property_float_get_array(fromptr, prop, tmparray); + RNA_property_float_get_array(fromptr, fromprop, tmparray); RNA_property_float_set_array(ptr, prop, tmparray); MEM_freeN(tmparray); } else { - float value = RNA_property_float_get_index(fromptr, prop, index); + float value = RNA_property_float_get_index(fromptr, fromprop, index); RNA_property_float_set_index(ptr, prop, index, value); } } else { - float value = RNA_property_float_get(fromptr, prop); + float value = RNA_property_float_get(fromptr, fromprop); RNA_property_float_set(ptr, prop, value); } return true; case PROP_ENUM: { - int value = RNA_property_enum_get(fromptr, prop); + int value = RNA_property_enum_get(fromptr, fromprop); RNA_property_enum_set(ptr, prop, value); return true; } case PROP_POINTER: { - PointerRNA value = RNA_property_pointer_get(fromptr, prop); + PointerRNA value = RNA_property_pointer_get(fromptr, fromprop); RNA_property_pointer_set(ptr, prop, value); return true; } case PROP_STRING: { - char *value = RNA_property_string_get_alloc(fromptr, prop, NULL, 0, NULL); + char *value = RNA_property_string_get_alloc(fromptr, fromprop, NULL, 0, NULL); RNA_property_string_set(ptr, prop, value); MEM_freeN(value); return true; diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index ecfa1286a78..750c98a536d 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -281,7 +281,7 @@ static void rna_def_dopesheet(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", ADS_FLAG_SHOW_DBFILTERS); RNA_def_property_ui_text(prop, "Show Datablock Filters", "Show options for whether channels related to certain types of data are included"); - RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, -1); + RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN, NULL); /* General Filtering Settings */ diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index 62e681d1374..0114ffa35c0 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -150,7 +150,7 @@ static void rna_ConstraintActuator_type_set(struct PointerRNA *ptr, int value) switch (ca->type) { case ACT_CONST_TYPE_ORI: /* negative axis not supported in the orientation mode */ - if (ELEM3(ca->mode, ACT_CONST_DIRNX, ACT_CONST_DIRNY, ACT_CONST_DIRNZ)) + if (ELEM(ca->mode, ACT_CONST_DIRNX, ACT_CONST_DIRNY, ACT_CONST_DIRNZ)) ca->mode = ACT_CONST_NONE; break; @@ -1090,6 +1090,7 @@ static void rna_def_property_actuator(BlenderRNA *brna) {ACT_PROP_ADD, "ADD", 0, "Add", ""}, {ACT_PROP_COPY, "COPY", 0, "Copy", ""}, {ACT_PROP_TOGGLE, "TOGGLE", 0, "Toggle", "For bool/int/float/timer properties only"}, + {ACT_PROP_LEVEL, "LEVEL", 0, "Level", "For bool/int/float/timer properties only"}, {0, NULL, 0, NULL, NULL} }; @@ -1369,6 +1370,23 @@ static void rna_def_edit_object_actuator(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_track_axis_items[] = { + {ACT_TRACK_TRAXIS_X, "TRACKAXISX", 0, "X axis", ""}, + {ACT_TRACK_TRAXIS_Y, "TRACKAXISY", 0, "Y axis", ""}, + {ACT_TRACK_TRAXIS_Z, "TRACKAXISZ", 0, "Z axis", ""}, + {ACT_TRACK_TRAXIS_NEGX, "TRACKAXISNEGX", 0, "-X axis", ""}, + {ACT_TRACK_TRAXIS_NEGY, "TRACKAXISNEGY", 0, "-Y axis", ""}, + {ACT_TRACK_TRAXIS_NEGZ, "TRACKAXISNEGZ", 0, "-Z axis", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem prop_up_axis_items[] = { + {ACT_TRACK_UP_X, "UPAXISX", 0, "X axis", ""}, + {ACT_TRACK_UP_Y, "UPAXISY", 0, "Y axis", ""}, + {ACT_TRACK_UP_Z, "UPAXISZ", 0, "Z axis", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "EditObjectActuator", "Actuator"); RNA_def_struct_ui_text(srna, "Edit Object Actuator", "Actuator used to edit objects"); RNA_def_struct_sdna_from(srna, "bEditObjectActuator", "data"); @@ -1385,6 +1403,18 @@ static void rna_def_edit_object_actuator(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Dynamic Operation", ""); RNA_def_property_update(prop, NC_LOGIC, NULL); + prop = RNA_def_property(srna, "up_axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "upflag"); + RNA_def_property_enum_items(prop, prop_up_axis_items); + RNA_def_property_ui_text(prop, "Up Axis", "The axis that points upward"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "trackflag"); + RNA_def_property_enum_items(prop, prop_track_axis_items); + RNA_def_property_ui_text(prop, "Track Axis", "The axis that points to the target object"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Object"); RNA_def_property_pointer_sdna(prop, NULL, "ob"); diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 1bccceab5ab..421d7b28dda 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -475,7 +475,7 @@ static int rna_Armature_is_editmode_get(PointerRNA *ptr) return (arm->edbo != NULL); } -void rna_Armature_transform(struct bArmature *arm, float *mat) +static void rna_Armature_transform(struct bArmature *arm, float *mat) { ED_armature_transform(arm, (float (*)[4])mat); } diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 893cad2b76a..1ff99271146 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -55,6 +55,9 @@ static EnumPropertyItem sculpt_stroke_method_items[] = { {BRUSH_SPACE, "SPACE", 0, "Space", "Limit brush application to the distance specified by spacing"}, {BRUSH_AIRBRUSH, "AIRBRUSH", 0, "Airbrush", "Keep applying paint effect while holding mouse (spray)"}, {BRUSH_ANCHORED, "ANCHORED", 0, "Anchored", "Keep the brush anchored to the initial location"}, + {BRUSH_LINE, "LINE", 0, "Line", "Draw a line with dabs separated according to spacing"}, + {BRUSH_CURVE, "CURVE", 0, "Curve", + "Define the stroke curve with a bezier curve (dabs are separated according to spacing)"}, {0, NULL, 0, NULL, NULL} }; @@ -99,6 +102,8 @@ EnumPropertyItem brush_image_tool_items[] = { {PAINT_TOOL_SOFTEN, "SOFTEN", ICON_BRUSH_SOFTEN, "Soften", ""}, {PAINT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_SMEAR, "Smear", ""}, {PAINT_TOOL_CLONE, "CLONE", ICON_BRUSH_CLONE, "Clone", ""}, + {PAINT_TOOL_FILL, "FILL", ICON_BRUSH_TEXFILL, "Fill", ""}, + {PAINT_TOOL_MASK, "MASK", ICON_BRUSH_TEXMASK, "Mask", ""}, {0, NULL, 0, NULL, NULL} }; @@ -120,9 +125,9 @@ EnumPropertyItem brush_image_tool_items[] = { static int rna_SculptToolCapabilities_has_accumulate_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ELEM6(br->sculpt_tool, - SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CREASE, - SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_LAYER); + return ELEM(br->sculpt_tool, + SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CREASE, + SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_LAYER); } static int rna_SculptToolCapabilities_has_auto_smooth_get(PointerRNA *ptr) @@ -142,9 +147,9 @@ static int rna_SculptToolCapabilities_has_jitter_get(PointerRNA *ptr) Brush *br = (Brush *)ptr->data; return (!(br->flag & BRUSH_ANCHORED) && !(br->flag & BRUSH_DRAG_DOT) && - !ELEM4(br->sculpt_tool, - SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, - SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)); + !ELEM(br->sculpt_tool, + SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, + SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)); } static int rna_SculptToolCapabilities_has_normal_weight_get(PointerRNA *ptr) @@ -156,7 +161,7 @@ static int rna_SculptToolCapabilities_has_normal_weight_get(PointerRNA *ptr) static int rna_BrushCapabilities_has_overlay_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ELEM3(br->mtex.brush_map_mode, + return ELEM(br->mtex.brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL); @@ -177,22 +182,22 @@ static int rna_SculptToolCapabilities_has_pinch_factor_get(PointerRNA *ptr) static int rna_SculptToolCapabilities_has_plane_offset_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ELEM5(br->sculpt_tool, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS, - SCULPT_TOOL_FILL, SCULPT_TOOL_FLATTEN, SCULPT_TOOL_SCRAPE); + return ELEM(br->sculpt_tool, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS, + SCULPT_TOOL_FILL, SCULPT_TOOL_FLATTEN, SCULPT_TOOL_SCRAPE); } static int rna_SculptToolCapabilities_has_random_texture_angle_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return (!ELEM4(br->sculpt_tool, - SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, - SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)); + return (!ELEM(br->sculpt_tool, + SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, + SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)); } static int rna_BrushCapabilities_has_random_texture_angle_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return (ELEM3(br->mtex.brush_map_mode, + return (ELEM(br->mtex.brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_AREA, MTEX_MAP_MODE_RANDOM) && @@ -202,19 +207,19 @@ static int rna_BrushCapabilities_has_random_texture_angle_get(PointerRNA *ptr) static int rna_SculptToolCapabilities_has_sculpt_plane_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return !ELEM4(br->sculpt_tool, SCULPT_TOOL_INFLATE, - SCULPT_TOOL_MASK, SCULPT_TOOL_PINCH, - SCULPT_TOOL_SMOOTH); + return !ELEM(br->sculpt_tool, SCULPT_TOOL_INFLATE, + SCULPT_TOOL_MASK, SCULPT_TOOL_PINCH, + SCULPT_TOOL_SMOOTH); } static int rna_SculptToolCapabilities_has_secondary_color_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ELEM10(br->sculpt_tool, - SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS, - SCULPT_TOOL_CREASE, SCULPT_TOOL_DRAW, SCULPT_TOOL_FILL, - SCULPT_TOOL_FLATTEN, SCULPT_TOOL_INFLATE, SCULPT_TOOL_PINCH, - SCULPT_TOOL_SCRAPE); + return ELEM(br->sculpt_tool, + SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS, + SCULPT_TOOL_CREASE, SCULPT_TOOL_DRAW, SCULPT_TOOL_FILL, + SCULPT_TOOL_FLATTEN, SCULPT_TOOL_INFLATE, SCULPT_TOOL_PINCH, + SCULPT_TOOL_SCRAPE); } static int rna_SculptToolCapabilities_has_smooth_stroke_get(PointerRNA *ptr) @@ -222,19 +227,37 @@ static int rna_SculptToolCapabilities_has_smooth_stroke_get(PointerRNA *ptr) Brush *br = (Brush *)ptr->data; return (!(br->flag & BRUSH_ANCHORED) && !(br->flag & BRUSH_DRAG_DOT) && - !ELEM4(br->sculpt_tool, + !(br->flag & BRUSH_LINE) && + !(br->flag & BRUSH_CURVE) && + !ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)); } +static int rna_BrushCapabilities_has_smooth_stroke_get(PointerRNA *ptr) +{ + Brush *br = (Brush *)ptr->data; + return (!(br->flag & BRUSH_ANCHORED) && + !(br->flag & BRUSH_DRAG_DOT) && + !(br->flag & BRUSH_LINE) && + !(br->flag & BRUSH_CURVE)); +} + static int rna_SculptToolCapabilities_has_space_attenuation_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ((br->flag & BRUSH_SPACE) && - !ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, + return ((br->flag & (BRUSH_SPACE | BRUSH_LINE | BRUSH_CURVE)) && + !ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SNAKE_HOOK)); } +static int rna_ImapaintToolCapabilities_has_space_attenuation_get(PointerRNA *ptr) +{ + Brush *br = (Brush *)ptr->data; + return (br->flag & (BRUSH_SPACE | BRUSH_LINE | BRUSH_CURVE)) && + br->imagepaint_tool != PAINT_TOOL_FILL; +} + static int rna_BrushCapabilities_has_spacing_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; @@ -250,12 +273,12 @@ static int rna_SculptToolCapabilities_has_strength_get(PointerRNA *ptr) static int rna_BrushCapabilities_has_texture_angle_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ELEM5(br->mtex.brush_map_mode, - MTEX_MAP_MODE_VIEW, - MTEX_MAP_MODE_AREA, - MTEX_MAP_MODE_TILED, - MTEX_MAP_MODE_STENCIL, - MTEX_MAP_MODE_RANDOM); + return ELEM(br->mtex.brush_map_mode, + MTEX_MAP_MODE_VIEW, + MTEX_MAP_MODE_AREA, + MTEX_MAP_MODE_TILED, + MTEX_MAP_MODE_STENCIL, + MTEX_MAP_MODE_RANDOM); } static int rna_SculptToolCapabilities_has_gravity_get(PointerRNA *ptr) @@ -267,17 +290,46 @@ static int rna_SculptToolCapabilities_has_gravity_get(PointerRNA *ptr) static int rna_BrushCapabilities_has_texture_angle_source_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ELEM3(br->mtex.brush_map_mode, + return ELEM(br->mtex.brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_AREA, MTEX_MAP_MODE_RANDOM); } -static PointerRNA rna_Sculpt_sculpt_tool_capabilities_get(PointerRNA *ptr) +static int rna_ImapaintToolCapabilities_has_accumulate_get(PointerRNA *ptr) +{ + /* only support for draw tool */ + Brush *br = (Brush *)ptr->data; + + return ((br->flag & BRUSH_AIRBRUSH) || + (br->flag & BRUSH_DRAG_DOT) || + (br->flag & BRUSH_ANCHORED) || + (br->imagepaint_tool == PAINT_TOOL_SOFTEN) || + (br->imagepaint_tool == PAINT_TOOL_SMEAR) || + (br->imagepaint_tool == PAINT_TOOL_FILL) || + (br->mtex.tex && !ELEM(br->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)) + ) ? false : true; +} + +static int rna_ImapaintToolCapabilities_has_radius_get(PointerRNA *ptr) +{ + /* only support for draw tool */ + Brush *br = (Brush *)ptr->data; + + return (br->imagepaint_tool != PAINT_TOOL_FILL); +} + + +static PointerRNA rna_Sculpt_tool_capabilities_get(PointerRNA *ptr) { return rna_pointer_inherit_refine(ptr, &RNA_SculptToolCapabilities, ptr->id.data); } +static PointerRNA rna_Imapaint_tool_capabilities_get(PointerRNA *ptr) +{ + return rna_pointer_inherit_refine(ptr, &RNA_ImapaintToolCapabilities, ptr->id.data); +} + static PointerRNA rna_Brush_capabilities_get(PointerRNA *ptr) { return rna_pointer_inherit_refine(ptr, &RNA_BrushCapabilities, ptr->id.data); @@ -328,7 +380,6 @@ static void rna_Brush_size_update(Main *bmain, Scene *scene, PointerRNA *ptr) static void rna_Brush_sculpt_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - BKE_paint_invalidate_overlay_all(); rna_Brush_reset_icon(br, "sculpt"); rna_Brush_update(bmain, scene, ptr); } @@ -336,7 +387,6 @@ static void rna_Brush_sculpt_tool_update(Main *bmain, Scene *scene, PointerRNA * static void rna_Brush_vertex_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - BKE_paint_invalidate_overlay_all(); rna_Brush_reset_icon(br, "vertex_paint"); rna_Brush_update(bmain, scene, ptr); } @@ -344,11 +394,16 @@ static void rna_Brush_vertex_tool_update(Main *bmain, Scene *scene, PointerRNA * static void rna_Brush_imagepaint_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - BKE_paint_invalidate_overlay_all(); rna_Brush_reset_icon(br, "image_paint"); rna_Brush_update(bmain, scene, ptr); } +static void rna_Brush_stroke_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, scene); + rna_Brush_update(bmain, scene, ptr); +} + static void rna_Brush_icon_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; @@ -388,6 +443,17 @@ static void rna_Brush_set_size(PointerRNA *ptr, int value) brush->size = value; } +static void rna_Brush_use_gradient_set(PointerRNA *ptr, int value) +{ + Brush *br = (Brush *)ptr->data; + + if (value) br->flag |= BRUSH_USE_GRADIENT; + else br->flag &= ~BRUSH_USE_GRADIENT; + + if ((br->flag & BRUSH_USE_GRADIENT) && br->gradient == NULL) + br->gradient = add_colorband(true); +} + static void rna_Brush_set_unprojected_radius(PointerRNA *ptr, float value) { Brush *brush = ptr->data; @@ -397,13 +463,16 @@ static void rna_Brush_set_unprojected_radius(PointerRNA *ptr, float value) brush->unprojected_radius = value; } -static EnumPropertyItem *rna_Brush_direction_itemf(bContext *UNUSED(C), PointerRNA *ptr, +static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *UNUSED(r_free)) { + PaintMode mode = BKE_paintmode_get_active_from_context(C); + static EnumPropertyItem prop_default_items[] = { {0, NULL, 0, NULL, NULL} }; + /* sculpt mode */ static EnumPropertyItem prop_flatten_contrast_items[] = { {0, "FLATTEN", 0, "Flatten", "Add effect of brush"}, {BRUSH_DIR_IN, "CONTRAST", 0, "Contrast", "Subtract effect of brush"}, @@ -434,41 +503,66 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *UNUSED(C), PointerR {0, NULL, 0, NULL, NULL} }; + /* texture paint mode */ + static EnumPropertyItem prop_soften_sharpen_items[] = { + {0, "SOFTEN", 0, "Soften", "Blur effect of brush"}, + {BRUSH_DIR_IN, "SHARPEN", 0, "Sharpen", "Sharpen effect of brush"}, + {0, NULL, 0, NULL, NULL} + }; + Brush *me = (Brush *)(ptr->data); - switch (me->sculpt_tool) { - case SCULPT_TOOL_DRAW: - case SCULPT_TOOL_CREASE: - case SCULPT_TOOL_BLOB: - case SCULPT_TOOL_LAYER: - case SCULPT_TOOL_CLAY: - case SCULPT_TOOL_CLAY_STRIPS: - return prop_direction_items; - - case SCULPT_TOOL_MASK: - switch ((BrushMaskTool)me->mask_tool) { - case BRUSH_MASK_DRAW: + switch (mode) { + case PAINT_SCULPT: + switch (me->sculpt_tool) { + case SCULPT_TOOL_DRAW: + case SCULPT_TOOL_CREASE: + case SCULPT_TOOL_BLOB: + case SCULPT_TOOL_LAYER: + case SCULPT_TOOL_CLAY: + case SCULPT_TOOL_CLAY_STRIPS: return prop_direction_items; - break; - case BRUSH_MASK_SMOOTH: - return prop_default_items; - break; - } - case SCULPT_TOOL_FLATTEN: - return prop_flatten_contrast_items; + case SCULPT_TOOL_MASK: + switch ((BrushMaskTool)me->mask_tool) { + case BRUSH_MASK_DRAW: + return prop_direction_items; + break; + case BRUSH_MASK_SMOOTH: + return prop_default_items; + break; + } - case SCULPT_TOOL_FILL: - return prop_fill_deepen_items; + case SCULPT_TOOL_FLATTEN: + return prop_flatten_contrast_items; - case SCULPT_TOOL_SCRAPE: - return prop_scrape_peaks_items; + case SCULPT_TOOL_FILL: + return prop_fill_deepen_items; - case SCULPT_TOOL_PINCH: - return prop_pinch_magnify_items; + case SCULPT_TOOL_SCRAPE: + return prop_scrape_peaks_items; - case SCULPT_TOOL_INFLATE: - return prop_inflate_deflate_items; + case SCULPT_TOOL_PINCH: + return prop_pinch_magnify_items; + + case SCULPT_TOOL_INFLATE: + return prop_inflate_deflate_items; + + default: + return prop_default_items; + } + break; + + case PAINT_TEXTURE_2D: + case PAINT_TEXTURE_PROJECTIVE: + switch (me->imagepaint_tool) { + case PAINT_TOOL_SOFTEN: + return prop_soften_sharpen_items; + + default: + return prop_default_items; + } + break; default: return prop_default_items; @@ -484,11 +578,15 @@ static EnumPropertyItem *rna_Brush_stroke_itemf(bContext *C, PointerRNA *UNUSED( {0, "DOTS", 0, "Dots", "Apply paint on each mouse move step"}, {BRUSH_SPACE, "SPACE", 0, "Space", "Limit brush application to the distance specified by spacing"}, {BRUSH_AIRBRUSH, "AIRBRUSH", 0, "Airbrush", "Keep applying paint effect while holding mouse (spray)"}, + {BRUSH_LINE, "LINE", 0, "Line", "Drag a line with dabs separated according to spacing"}, + {BRUSH_CURVE, "CURVE", 0, "Curve", "Define the stroke curve with a bezier curve. Dabs are separated according to spacing"}, {0, NULL, 0, NULL, NULL} }; switch (mode) { case PAINT_SCULPT: + case PAINT_TEXTURE_2D: + case PAINT_TEXTURE_PROJECTIVE: return sculpt_stroke_method_items; default: @@ -622,10 +720,39 @@ static void rna_def_brush_capabilities(BlenderRNA *brna) BRUSH_CAPABILITY(has_texture_angle, "Has Texture Angle"); BRUSH_CAPABILITY(has_texture_angle_source, "Has Texture Angle Source"); BRUSH_CAPABILITY(has_spacing, "Has Spacing"); + BRUSH_CAPABILITY(has_smooth_stroke, "Has Smooth Stroke"); + #undef BRUSH_CAPABILITY } +static void rna_def_image_paint_capabilities(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ImapaintToolCapabilities", NULL); + RNA_def_struct_sdna(srna, "Brush"); + RNA_def_struct_nested(brna, srna, "Brush"); + RNA_def_struct_ui_text(srna, "Image Paint Capabilities", + "Read-only indications of which brush operations " + "are supported by the current image paint brush"); + +#define IMAPAINT_TOOL_CAPABILITY(prop_name_, ui_name_) \ + prop = RNA_def_property(srna, #prop_name_, \ + PROP_BOOLEAN, PROP_NONE); \ + RNA_def_property_clear_flag(prop, PROP_EDITABLE); \ + RNA_def_property_boolean_funcs(prop, "rna_ImapaintToolCapabilities_" \ + #prop_name_ "_get", NULL); \ + RNA_def_property_ui_text(prop, ui_name_, NULL) + + IMAPAINT_TOOL_CAPABILITY(has_accumulate, "Has Accumulate"); + IMAPAINT_TOOL_CAPABILITY(has_space_attenuation, "Has Space Attenuation"); + IMAPAINT_TOOL_CAPABILITY(has_radius, "Has Radius"); + +#undef IMAPAINT_TOOL_CAPABILITY +} + static void rna_def_brush(BlenderRNA *brna) { StructRNA *srna; @@ -640,6 +767,22 @@ static void rna_def_brush(BlenderRNA *brna) {IMB_BLEND_DARKEN, "DARKEN", 0, "Darken", "Use darken blending mode while painting"}, {IMB_BLEND_ERASE_ALPHA, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"}, {IMB_BLEND_ADD_ALPHA, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"}, + {IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use overlay blending mode while painting"}, + {IMB_BLEND_HARDLIGHT, "HARDLIGHT", 0, "Hard light", "Use hard light blending mode while painting"}, + {IMB_BLEND_COLORBURN, "COLORBURN", 0, "Color burn", "Use color burn blending mode while painting"}, + {IMB_BLEND_LINEARBURN, "LINEARBURN", 0, "Linear burn", "Use linear burn blending mode while painting"}, + {IMB_BLEND_COLORDODGE, "COLORDODGE", 0, "Color dodge", "Use color dodge blending mode while painting"}, + {IMB_BLEND_SCREEN, "SCREEN", 0, "Screen", "Use screen blending mode while painting"}, + {IMB_BLEND_SOFTLIGHT, "SOFTLIGHT", 0, "Soft light", "Use softlight blending mode while painting"}, + {IMB_BLEND_PINLIGHT, "PINLIGHT", 0, "Pin light", "Use pinlight blending mode while painting"}, + {IMB_BLEND_VIVIDLIGHT, "VIVIDLIGHT", 0, "Vivid light", "Use vividlight blending mode while painting"}, + {IMB_BLEND_LINEARLIGHT, "LINEARLIGHT", 0, "Linear light", "Use linearlight blending mode while painting"}, + {IMB_BLEND_DIFFERENCE, "DIFFERENCE", 0, "Difference", "Use difference blending mode while painting"}, + {IMB_BLEND_EXCLUSION, "EXCLUSION", 0, "Exclusion", "Use exclusion blending mode while painting"}, + {IMB_BLEND_HUE, "HUE", 0, "Hue", "Use hue blending mode while painting"}, + {IMB_BLEND_SATURATION, "SATURATION", 0, "Saturation", "Use saturation blending mode while painting"}, + {IMB_BLEND_LUMINOSITY, "LUMINOSITY", 0, "Luminosity", "Use luminosity blending mode while painting"}, + {IMB_BLEND_COLOR, "COLOR", 0, "Color", "Use color blending mode while painting"}, {0, NULL, 0, NULL, NULL} }; @@ -671,6 +814,32 @@ static void rna_def_brush(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem brush_blur_mode_items[] = { + {KERNEL_BOX, "BOX", 0, "Box", ""}, + {KERNEL_GAUSSIAN, "GAUSSIAN", 0, "Gaussian", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem brush_gradient_items[] = { + {BRUSH_GRADIENT_PRESSURE, "PRESSURE", 0, "Pressure", ""}, + {BRUSH_GRADIENT_SPACING_REPEAT, "SPACING_REPEAT", 0, "Repeat", ""}, + {BRUSH_GRADIENT_SPACING_CLAMP, "SPACING_CLAMP", 0, "Clamp", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem brush_gradient_fill_items[] = { + {BRUSH_GRADIENT_LINEAR, "LINEAR", 0, "Linear", ""}, + {BRUSH_GRADIENT_RADIAL, "RADIAL", 0, "Radial", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem brush_mask_pressure_items[] = { + {0, "NONE", 0, "Off", ""}, + {BRUSH_MASK_PRESSURE_RAMP, "RAMP", ICON_STYLUS_PRESSURE, "Ramp", ""}, + {BRUSH_MASK_PRESSURE_CUTOFF, "CUTOFF", ICON_STYLUS_PRESSURE, "Cutoff", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "Brush", "ID"); RNA_def_struct_ui_text(srna, "Brush", "Brush datablock for storing brush settings for painting and sculpting"); RNA_def_struct_ui_icon(srna, ICON_BRUSH_DATA); @@ -710,7 +879,7 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_enum_items(prop, sculpt_stroke_method_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Brush_stroke_itemf"); RNA_def_property_ui_text(prop, "Stroke Method", ""); - RNA_def_property_update(prop, 0, "rna_Brush_update"); + RNA_def_property_update(prop, 0, "rna_Brush_stroke_update"); prop = RNA_def_property(srna, "texture_angle_source_random", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); @@ -769,6 +938,13 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Spacing", "Spacing between brush daubs as a percentage of brush diameter"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "grad_spacing", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "gradient_spacing"); + RNA_def_property_range(prop, 1, 10000); + RNA_def_property_ui_range(prop, 1, 10000, 5, -1); + RNA_def_property_ui_text(prop, "Gradient Spacing", "Spacing before brush gradient goes full circle"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "smooth_stroke_radius", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 10, 200); RNA_def_property_ui_text(prop, "Smooth Stroke Radius", "Minimum distance from last point before stroke continues"); @@ -791,7 +967,13 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "rgb"); RNA_def_property_ui_text(prop, "Color", ""); RNA_def_property_update(prop, 0, "rna_Brush_update"); - + + prop = RNA_def_property(srna, "secondary_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "secondary_rgb"); + RNA_def_property_ui_text(prop, "Secondary Color", ""); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -884,6 +1066,32 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Mask Stencil Dimensions", "Dimensions of mask stencil in viewport"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "sharp_threshold", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 100.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3); + RNA_def_property_float_sdna(prop, NULL, "sharp_threshold"); + RNA_def_property_ui_text(prop, "Sharp Threshold", "Threshold below which, no sharpening is done"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "fill_threshold", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 100.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3); + RNA_def_property_float_sdna(prop, NULL, "fill_threshold"); + RNA_def_property_ui_text(prop, "Fill Threshold", "Threshold above which filling is not propagated"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "blur_kernel_radius", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "blur_kernel_radius"); + RNA_def_property_range(prop, 1, 10000); + RNA_def_property_ui_range(prop, 1, 50, 1, -1); + RNA_def_property_ui_text(prop, "Kernel Radius", "Radius of kernel used for soften and sharpen in pixels"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "blur_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, brush_blur_mode_items); + RNA_def_property_ui_text(prop, "Blur Mode", ""); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + /* flag */ prop = RNA_def_property(srna, "use_airbrush", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_AIRBRUSH); @@ -919,7 +1127,13 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); RNA_def_property_ui_text(prop, "Size Pressure", "Enable tablet pressure sensitivity for size"); RNA_def_property_update(prop, 0, "rna_Brush_update"); - + + prop = RNA_def_property(srna, "use_gradient", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_USE_GRADIENT); + RNA_def_property_boolean_funcs(prop, NULL, "rna_Brush_use_gradient_set"); + RNA_def_property_ui_text(prop, "Use Gradient", "Use Gradient by utilizing a sampling method"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_pressure_jitter", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_JITTER_PRESSURE); RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); @@ -932,6 +1146,12 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Spacing Pressure", "Enable tablet pressure sensitivity for spacing"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_pressure_masking", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "mask_pressure"); + RNA_def_property_enum_items(prop, brush_mask_pressure_items); + RNA_def_property_ui_text(prop, "Mask Pressure Mode", "Pen pressure makes texture influence smaller"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_inverse_smooth_pressure", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_INVERSE_SMOOTH_PRESSURE); RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); @@ -974,6 +1194,16 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Space", "Limit brush application to the distance specified by spacing"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_line", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_LINE); + RNA_def_property_ui_text(prop, "Line", "Draw a line with dabs separated according to spacing"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "use_curve", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_CURVE); + RNA_def_property_ui_text(prop, "Curve", "Define the stroke curve with a bezier curve. Dabs are separated according to spacing"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_smooth_stroke", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SMOOTH_STROKE); RNA_def_property_ui_text(prop, "Smooth Stroke", "Brush lags behind mouse and follows a smoother path"); @@ -1015,7 +1245,7 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Edge-to-edge", "Drag anchor brush from edge-to-edge"); RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "use_drag_dot", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "use_restore_mesh", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_DRAG_DOT); RNA_def_property_ui_text(prop, "Restore Mesh", "Allow a single dot to be carefully positioned"); RNA_def_property_update(prop, 0, "rna_Brush_update"); @@ -1031,6 +1261,28 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Curve", "Editable falloff curve"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "paint_curve", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Paint Curve", "Active Paint Curve"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "gradient", PROP_POINTER, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "gradient"); + RNA_def_property_struct_type(prop, "ColorRamp"); + RNA_def_property_ui_text(prop, "Gradient", ""); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + /* gradient source */ + prop = RNA_def_property(srna, "gradient_stroke_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, brush_gradient_items); + RNA_def_property_ui_text(prop, "Gradient Stroke Mode", ""); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "gradient_fill_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, brush_gradient_fill_items); + RNA_def_property_ui_text(prop, "Gradient Fill Mode", ""); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + /* overlay flags */ prop = RNA_def_property(srna, "use_primary_overlay", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay_flags", BRUSH_OVERLAY_PRIMARY); @@ -1173,8 +1425,14 @@ static void rna_def_brush(BlenderRNA *brna) prop = RNA_def_property(srna, "sculpt_capabilities", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "SculptToolCapabilities"); - RNA_def_property_pointer_funcs(prop, "rna_Sculpt_sculpt_tool_capabilities_get", NULL, NULL, NULL); + RNA_def_property_pointer_funcs(prop, "rna_Sculpt_tool_capabilities_get", NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Sculpt Capabilities", "Brush's capabilities in sculpt mode"); + + prop = RNA_def_property(srna, "image_paint_capabilities", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_struct_type(prop, "ImapaintToolCapabilities"); + RNA_def_property_pointer_funcs(prop, "rna_Imapaint_tool_capabilities_get", NULL, NULL, NULL); + RNA_def_property_ui_text(prop, "Image Painting Capabilities", "Brush's capabilities in image paint mode"); } @@ -1211,6 +1469,11 @@ static void rna_def_operator_stroke_element(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Pressure", "Tablet pressure"); + prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE); + RNA_def_property_flag(prop, PROP_IDPROPERTY); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_text(prop, "Brush Size", "Brush Size in screen space"); + prop = RNA_def_property(srna, "pen_flip", PROP_BOOLEAN, PROP_NONE); RNA_def_property_flag(prop, PROP_IDPROPERTY); RNA_def_property_ui_text(prop, "Flip", ""); @@ -1237,6 +1500,7 @@ void RNA_def_brush(BlenderRNA *brna) rna_def_brush(brna); rna_def_brush_capabilities(brna); rna_def_sculpt_capabilities(brna); + rna_def_image_paint_capabilities(brna); rna_def_brush_texture_slot(brna); rna_def_operator_stroke_element(brna); } diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index cca78ee2d8d..fa2a3258d1a 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -176,7 +176,7 @@ static char *rna_ColorRamp_path(PointerRNA *ptr) char *node_path; for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM3(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) { + if (ELEM(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) { if (node->storage == ptr->data) { /* all node color ramp properties called 'color_ramp' * prepend path from ID to the node @@ -193,7 +193,7 @@ static char *rna_ColorRamp_path(PointerRNA *ptr) case ID_LS: { - char *path = BKE_path_from_ID_to_color_ramp((FreestyleLineStyle *)id, (ColorBand *)ptr->data); + char *path = BKE_linestyle_path_to_color_ramp((FreestyleLineStyle *)id, (ColorBand *)ptr->data); if (path) return path; break; @@ -265,7 +265,7 @@ static char *rna_ColorRampElement_path(PointerRNA *ptr) bNode *node; for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM3(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) { + if (ELEM(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) { RNA_pointer_create(id, &RNA_ColorRamp, node->storage, &ramp_ptr); COLRAMP_GETPATH; } @@ -277,7 +277,7 @@ static char *rna_ColorRampElement_path(PointerRNA *ptr) ListBase listbase; LinkData *link; - BKE_list_modifier_color_ramps((FreestyleLineStyle *)id, &listbase); + BKE_linestyle_modifier_list_color_ramps((FreestyleLineStyle *)id, &listbase); for (link = (LinkData *)listbase.first; link; link = link->next) { RNA_pointer_create(id, &RNA_ColorRamp, link->data, &ramp_ptr); COLRAMP_GETPATH; @@ -324,7 +324,7 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA * bNode *node; for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM3(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) { + if (ELEM(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) { ED_node_tag_update_nodetree(bmain, ntree); } } @@ -378,7 +378,7 @@ static void rna_ColorRampElement_remove(struct ColorBand *coba, ReportList *repo RNA_POINTER_INVALIDATE(element_ptr); } -void rna_CurveMap_remove_point(CurveMap *cuma, ReportList *reports, PointerRNA *point_ptr) +static void rna_CurveMap_remove_point(CurveMap *cuma, ReportList *reports, PointerRNA *point_ptr) { CurveMapPoint *point = point_ptr->data; if (curvemap_remove_point(cuma, point) == false) { @@ -850,7 +850,12 @@ static void rna_def_color_ramp_element(BlenderRNA *brna) RNA_def_property_array(prop, 4); RNA_def_property_ui_text(prop, "Color", "Set color of selected color stop"); RNA_def_property_update(prop, 0, "rna_ColorRamp_update"); - + + prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_COLOR); + RNA_def_property_float_sdna(prop, NULL, "a"); + RNA_def_property_ui_text(prop, "Alpha", "Set alpha of selected color stop"); + RNA_def_property_update(prop, 0, "rna_ColorRamp_update"); + prop = RNA_def_property(srna, "position", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "pos"); RNA_def_property_range(prop, 0, 1); @@ -895,14 +900,29 @@ static void rna_def_color_ramp(BlenderRNA *brna) FunctionRNA *func; static EnumPropertyItem prop_interpolation_items[] = { - {1, "EASE", 0, "Ease", ""}, - {3, "CARDINAL", 0, "Cardinal", ""}, - {0, "LINEAR", 0, "Linear", ""}, - {2, "B_SPLINE", 0, "B-Spline", ""}, - {4, "CONSTANT", 0, "Constant", ""}, + {COLBAND_INTERP_EASE, "EASE", 0, "Ease", ""}, + {COLBAND_INTERP_CARDINAL, "CARDINAL", 0, "Cardinal", ""}, + {COLBAND_INTERP_LINEAR, "LINEAR", 0, "Linear", ""}, + {COLBAND_INTERP_B_SPLINE, "B_SPLINE", 0, "B-Spline", ""}, + {COLBAND_INTERP_CONSTANT, "CONSTANT", 0, "Constant", ""}, {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_mode_items[] = { + {COLBAND_BLEND_RGB, "RGB", 0, "RGB", ""}, + {COLBAND_BLEND_HSV, "HSV", 0, "HSV", ""}, + {COLBAND_BLEND_HSL, "HSL", 0, "HSL", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem prop_hsv_items[] = { + {COLBAND_HUE_NEAR, "NEAR", 0, "Near", ""}, + {COLBAND_HUE_FAR, "FAR", 0, "Far", ""}, + {COLBAND_HUE_CW, "CW", 0, "Clockwise", ""}, + {COLBAND_HUE_CCW, "CCW", 0, "Counter-Clockwise", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "ColorRamp", NULL); RNA_def_struct_sdna(srna, "ColorBand"); RNA_def_struct_path_func(srna, "rna_ColorRamp_path"); @@ -921,6 +941,18 @@ static void rna_def_color_ramp(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Interpolation", "Set interpolation between color stops"); RNA_def_property_update(prop, 0, "rna_ColorRamp_update"); + prop = RNA_def_property(srna, "hue_interpolation", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "ipotype_hue"); + RNA_def_property_enum_items(prop, prop_hsv_items); + RNA_def_property_ui_text(prop, "Color Interpolation", "Set color interpolation"); + RNA_def_property_update(prop, 0, "rna_ColorRamp_update"); + + prop = RNA_def_property(srna, "color_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "color_mode"); + RNA_def_property_enum_items(prop, prop_mode_items); + RNA_def_property_ui_text(prop, "Color Mode", "Set color mode to use for interpolation"); + RNA_def_property_update(prop, 0, "rna_ColorRamp_update"); + #if 0 /* use len(elements) */ prop = RNA_def_property(srna, "total", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "tot"); diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 120992cffe8..5519b192ca4 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -351,7 +351,7 @@ static void rna_ActionConstraint_minmax_range(PointerRNA *ptr, float *min, float bActionConstraint *acon = (bActionConstraint *)con->data; /* 0, 1, 2 = magic numbers for rotX, rotY, rotZ */ - if (ELEM3(acon->type, 0, 1, 2)) { + if (ELEM(acon->type, 0, 1, 2)) { *min = -180.0f; *max = 180.0f; } @@ -2452,6 +2452,12 @@ static void rna_def_constraint_follow_track(BlenderRNA *brna) RNA_def_property_enum_items(prop, frame_method_items); RNA_def_property_ui_text(prop, "Frame Method", "How the footage fits in the camera frame"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); + + /* use undistortion */ + prop = RNA_def_property(srna, "use_undistorted_position", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", FOLLOWTRACK_USE_UNDISTORTION); + RNA_def_property_ui_text(prop, "Undistort", "Parent to undistorted position of 2D track"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); } static void rna_def_constraint_camera_solver(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_curve_api.c b/source/blender/makesrna/intern/rna_curve_api.c index b689242f68f..e85511f08e9 100644 --- a/source/blender/makesrna/intern/rna_curve_api.c +++ b/source/blender/makesrna/intern/rna_curve_api.c @@ -38,14 +38,16 @@ #include "BLI_utildefines.h" -#include "ED_curve.h" +#include "BKE_curve.h" #include "rna_internal.h" /* own include */ #ifdef RNA_RUNTIME -void rna_Curve_transform(Curve *cu, float *mat) +static void rna_Curve_transform(Curve *cu, float *mat, int shape_keys) { - ED_curve_transform(cu, (float (*)[4])mat); + BKE_curve_transform(cu, (float (*)[4])mat, shape_keys); + + DAG_id_tag_update(&cu->id, 0); } #else @@ -58,6 +60,13 @@ void RNA_api_curve(StructRNA *srna) RNA_def_function_ui_description(func, "Transform curve by a matrix"); parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys"); + + func = RNA_def_function(srna, "validate_material_indices", "BKE_curve_material_index_validate"); + RNA_def_function_ui_description(func, "Validate material indices of splines or letters, return True when the curve " + "has had invalid indices corrected (to default 0)"); + parm = RNA_def_boolean(func, "result", 0, "Result", ""); + RNA_def_function_return(func, parm); } #endif diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 9f9cc57a475..3b9078153f3 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -820,7 +820,7 @@ static FCM_EnvelopeData *rna_FModifierEnvelope_points_add(FModifier *fmod, Repor return (env->data + i); } -void rna_FModifierEnvelope_points_remove(FModifier *fmod, ReportList *reports, PointerRNA *point) +static void rna_FModifierEnvelope_points_remove(FModifier *fmod, ReportList *reports, PointerRNA *point) { FCM_EnvelopeData *cp = point->data; FMod_Envelope *env = (FMod_Envelope *)fmod->data; diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c index 8f4108c23d0..01feb3cb748 100644 --- a/source/blender/makesrna/intern/rna_fluidsim.c +++ b/source/blender/makesrna/intern/rna_fluidsim.c @@ -465,7 +465,8 @@ static void rna_def_fluidsim_volume(StructRNA *srna) RNA_def_property_enum_bitflag_sdna(prop, NULL, "volumeInitType"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_enum_items(prop, volume_type_items); - RNA_def_property_ui_text(prop, "Volume Initialization", "Volume initialization type"); + RNA_def_property_ui_text(prop, "Volume Initialization", "Volume initialization type " + "(WARNING: complex volumes might require too much memory and break simulation)"); prop = RNA_def_property(srna, "use_animated_mesh", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "domainNovecgen", 0); diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index be275058957..83b7a81c649 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -202,6 +202,7 @@ void rna_def_texmat_common(struct StructRNA *srna, const char *texspace_editable void rna_def_mtex_common(struct BlenderRNA *brna, struct StructRNA *srna, const char *begin, const char *activeget, const char *activeset, const char *activeeditable, const char *structname, const char *structname_slots, const char *update, const char *update_index); +void rna_def_texpaint_slots(struct BlenderRNA *brna, struct StructRNA *srna); void rna_def_render_layer_common(struct StructRNA *srna, int scene); void rna_def_actionbone_group_common(struct StructRNA *srna, int update_flag, const char *update_cb); @@ -412,4 +413,24 @@ void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values); # endif #endif +/* C11 for compile time range checks */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +# define USE_RNA_RANGE_CHECK +# define TYPEOF_MAX(x) \ + _Generic((x), \ + bool: 1, \ + char: CHAR_MAX, signed char: SCHAR_MAX, unsigned char: UCHAR_MAX, \ + signed short: SHRT_MAX, unsigned short: USHRT_MAX, \ + signed int: INT_MAX, unsigned int: UINT_MAX, \ + float: FLT_MAX, double: DBL_MAX) + +# define TYPEOF_MIN(x) \ + _Generic((x), \ + bool: 0, \ + char: CHAR_MIN, signed char: SCHAR_MIN, unsigned char: 0, \ + signed short: SHRT_MIN, unsigned short: 0, \ + signed int: INT_MIN, unsigned int: 0, \ + float: -FLT_MAX, double: -DBL_MAX) +#endif + #endif /* __RNA_INTERNAL_H__ */ diff --git a/source/blender/makesrna/intern/rna_lattice_api.c b/source/blender/makesrna/intern/rna_lattice_api.c index acb71b29ea8..ed0489db1a2 100644 --- a/source/blender/makesrna/intern/rna_lattice_api.c +++ b/source/blender/makesrna/intern/rna_lattice_api.c @@ -38,14 +38,14 @@ #include "BLI_utildefines.h" -#include "ED_lattice.h" - #include "rna_internal.h" /* own include */ #ifdef RNA_RUNTIME -void rna_Lattice_transform(Lattice *lt, float *mat) +static void rna_Lattice_transform(Lattice *lt, float *mat, int shape_keys) { - ED_lattice_transform(lt, (float (*)[4])mat); + BKE_lattice_transform(lt, (float (*)[4])mat, shape_keys); + + DAG_id_tag_update(<->id, 0); } #else @@ -58,6 +58,7 @@ void RNA_api_lattice(StructRNA *srna) RNA_def_function_ui_description(func, "Transform lattice by a matrix"); parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys"); } #endif diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c index faff39e679a..96b81f12620 100644 --- a/source/blender/makesrna/intern/rna_linestyle.c +++ b/source/blender/makesrna/intern/rna_linestyle.c @@ -87,6 +87,8 @@ EnumPropertyItem linestyle_geometry_modifier_type_items[] = { #include "BKE_texture.h" #include "BKE_depsgraph.h" +#include "ED_node.h" + #include "RNA_access.h" static StructRNA *rna_LineStyle_color_modifier_refine(struct PointerRNA *ptr) @@ -283,10 +285,20 @@ static void rna_LineStyle_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin WM_main_add_notifier(NC_LINESTYLE, linestyle); } +static void rna_LineStyle_use_nodes_update(bContext *C, PointerRNA *ptr) +{ + FreestyleLineStyle *linestyle = (FreestyleLineStyle *)ptr->data; + + if (linestyle->use_nodes && linestyle->nodetree == NULL) + BKE_linestyle_default_shader(C, linestyle); + + rna_LineStyle_update(CTX_data_main(C), CTX_data_scene(C), ptr); +} + static LineStyleModifier *rna_LineStyle_color_modifier_add(FreestyleLineStyle *linestyle, ReportList *reports, const char *name, int type) { - LineStyleModifier *modifier = BKE_add_linestyle_color_modifier(linestyle, name, type); + LineStyleModifier *modifier = BKE_linestyle_color_modifier_add(linestyle, name, type); if (!modifier) { BKE_report(reports, RPT_ERROR, "Failed to add the color modifier"); @@ -304,7 +316,7 @@ static void rna_LineStyle_color_modifier_remove(FreestyleLineStyle *linestyle, R { LineStyleModifier *modifier = modifier_ptr->data; - if (BKE_remove_linestyle_color_modifier(linestyle, modifier) == -1) { + if (BKE_linestyle_color_modifier_remove(linestyle, modifier) == -1) { BKE_reportf(reports, RPT_ERROR, "Color modifier '%s' could not be removed", modifier->name); return; } @@ -318,7 +330,7 @@ static void rna_LineStyle_color_modifier_remove(FreestyleLineStyle *linestyle, R static LineStyleModifier *rna_LineStyle_alpha_modifier_add(FreestyleLineStyle *linestyle, ReportList *reports, const char *name, int type) { - LineStyleModifier *modifier = BKE_add_linestyle_alpha_modifier(linestyle, name, type); + LineStyleModifier *modifier = BKE_linestyle_alpha_modifier_add(linestyle, name, type); if (!modifier) { BKE_report(reports, RPT_ERROR, "Failed to add the alpha modifier"); @@ -336,7 +348,7 @@ static void rna_LineStyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, R { LineStyleModifier *modifier = modifier_ptr->data; - if (BKE_remove_linestyle_alpha_modifier(linestyle, modifier) == -1) { + if (BKE_linestyle_alpha_modifier_remove(linestyle, modifier) == -1) { BKE_reportf(reports, RPT_ERROR, "Alpha modifier '%s' could not be removed", modifier->name); return; } @@ -350,7 +362,7 @@ static void rna_LineStyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, R static LineStyleModifier *rna_LineStyle_thickness_modifier_add(FreestyleLineStyle *linestyle, ReportList *reports, const char *name, int type) { - LineStyleModifier *modifier = BKE_add_linestyle_thickness_modifier(linestyle, name, type); + LineStyleModifier *modifier = BKE_linestyle_thickness_modifier_add(linestyle, name, type); if (!modifier) { BKE_report(reports, RPT_ERROR, "Failed to add the thickness modifier"); @@ -368,7 +380,7 @@ static void rna_LineStyle_thickness_modifier_remove(FreestyleLineStyle *linestyl { LineStyleModifier *modifier = modifier_ptr->data; - if (BKE_remove_linestyle_thickness_modifier(linestyle, modifier) == -1) { + if (BKE_linestyle_thickness_modifier_remove(linestyle, modifier) == -1) { BKE_reportf(reports, RPT_ERROR, "Thickness modifier '%s' could not be removed", modifier->name); return; } @@ -382,7 +394,7 @@ static void rna_LineStyle_thickness_modifier_remove(FreestyleLineStyle *linestyl static LineStyleModifier *rna_LineStyle_geometry_modifier_add(FreestyleLineStyle *linestyle, ReportList *reports, const char *name, int type) { - LineStyleModifier *modifier = BKE_add_linestyle_geometry_modifier(linestyle, name, type); + LineStyleModifier *modifier = BKE_linestyle_geometry_modifier_add(linestyle, name, type); if (!modifier) { BKE_report(reports, RPT_ERROR, "Failed to add the geometry modifier"); @@ -400,7 +412,7 @@ static void rna_LineStyle_geometry_modifier_remove(FreestyleLineStyle *linestyle { LineStyleModifier *modifier = modifier_ptr->data; - if (BKE_remove_linestyle_geometry_modifier(linestyle, modifier) == -1) { + if (BKE_linestyle_geometry_modifier_remove(linestyle, modifier) == -1) { BKE_reportf(reports, RPT_ERROR, "Geometry modifier '%s' could not be removed", modifier->name); return; } @@ -500,7 +512,7 @@ static void rna_def_linestyle_mtex(BlenderRNA *brna) prop = RNA_def_property(srna, "use_tips", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_TIPS); - RNA_def_property_ui_text(prop, "Use tips", "Lower half of the texture is for tips of the stroke"); + RNA_def_property_ui_text(prop, "Use Tips", "Lower half of the texture is for tips of the stroke"); RNA_def_property_update(prop, 0, "rna_LineStyle_update"); prop = RNA_def_property(srna, "texture_coords", PROP_ENUM, PROP_NONE); @@ -571,6 +583,7 @@ static void rna_def_modifier_type_common(StructRNA *srna, EnumPropertyItem *modi prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "modifier.flags", LS_MODIFIER_ENABLED); RNA_def_property_ui_text(prop, "Use", "Enable or disable this modifier during stroke rendering"); + RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update"); prop = RNA_def_property(srna, "expanded", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "modifier.flags", LS_MODIFIER_EXPANDED); @@ -1337,7 +1350,6 @@ static void rna_def_linestyle(BlenderRNA *brna) RNA_def_property_enum_bitflag_sdna(prop, NULL, "panel"); RNA_def_property_enum_items(prop, panel_items); RNA_def_property_ui_text(prop, "Panel", "Select the property panel to be shown"); - RNA_def_property_update(prop, NC_LINESTYLE, NULL); prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "r"); @@ -1606,14 +1618,14 @@ static void rna_def_linestyle(BlenderRNA *brna) /* nodes */ prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); - RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node based textures"); + RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node-based shaders"); prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_nodes", 1); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_ui_text(prop, "Use Nodes", "Use texture nodes for the line style"); - RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update"); + RNA_def_property_ui_text(prop, "Use Nodes", "Use shader nodes for the line style"); + RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_use_nodes_update"); } void RNA_def_linestyle(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c index f163808c61b..65d81359045 100644 --- a/source/blender/makesrna/intern/rna_main.c +++ b/source/blender/makesrna/intern/rna_main.c @@ -281,6 +281,14 @@ static void rna_Main_linestyle_begin(CollectionPropertyIterator *iter, PointerRN rna_iterator_listbase_begin(iter, &bmain->linestyle, NULL); } +static void rna_Main_version_get(PointerRNA *ptr, int *value) +{ + Main *bmain = (Main *)ptr->data; + value[0] = bmain->versionfile / 100; + value[1] = bmain->versionfile % 100; + value[2] = bmain->subversionfile; +} + #ifdef UNIT_TEST static PointerRNA rna_Test_test_get(PointerRNA *ptr) @@ -376,6 +384,12 @@ void RNA_def_main(BlenderRNA *brna) RNA_def_property_boolean_funcs(prop, "rna_Main_use_autopack_get", "rna_Main_use_autopack_set"); RNA_def_property_ui_text(prop, "Use Autopack", "Automatically pack all external data into .blend file"); + prop = RNA_def_int_vector(srna, "version", 3, NULL, 0, INT_MAX, + "Version", "Version of the blender the .blend was saved with", 0, INT_MAX); + RNA_def_property_int_funcs(prop, "rna_Main_version_get", NULL, NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_THICK_WRAP); + for (i = 0; lists[i].name; i++) { prop = RNA_def_property(srna, lists[i].identifier, PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, lists[i].type); diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index bac1f132126..b4c332be373 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -683,14 +683,14 @@ static void rna_Main_grease_pencil_remove(Main *bmain, ReportList *reports, Poin gpd->id.name + 2, ID_REAL_USERS(gpd)); } -FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name) +static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name) { - FreestyleLineStyle *linestyle = BKE_new_linestyle(name, bmain); + FreestyleLineStyle *linestyle = BKE_linestyle_new(name, bmain); id_us_min(&linestyle->id); return linestyle; } -void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, FreestyleLineStyle *linestyle) +static void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, FreestyleLineStyle *linestyle) { if (ID_REAL_USERS(linestyle) <= 0) BKE_libblock_free(bmain, linestyle); diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 7ae15b0b06c..37b6947cfac 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -82,6 +82,8 @@ EnumPropertyItem ramp_blend_items[] = { #include "DNA_node_types.h" #include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "BKE_context.h" #include "BKE_depsgraph.h" @@ -92,6 +94,8 @@ EnumPropertyItem ramp_blend_items[] = { #include "BKE_paint.h" #include "ED_node.h" +#include "ED_image.h" +#include "BKE_scene.h" static void rna_Material_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { @@ -165,6 +169,49 @@ static void rna_Material_mtex_begin(CollectionPropertyIterator *iter, PointerRNA rna_iterator_array_begin(iter, (void *)ma->mtex, sizeof(MTex *), MAX_MTEX, 0, NULL); } +static void rna_Material_texpaint_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Material *ma = (Material *)ptr->data; + rna_iterator_array_begin(iter, (void *)ma->texpaintslot, sizeof(TexPaintSlot), ma->tot_slots, 0, NULL); +} + + +static void rna_Material_active_paint_texture_index_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + bScreen *sc; + Material *ma = ptr->id.data; + + if (ma->use_nodes && ma->nodetree && BKE_scene_use_new_shading_nodes(scene)) { + struct bNode *node; + int index = 0; + for (node = ma->nodetree->nodes.first; node; node = node->next) { + if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) { + if (index++ == ma->paint_active_slot) { + break; + } + } + } + if (node) + nodeSetActive(ma->nodetree, node); + } + + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + ScrArea *sa; + for (sa = sc->areabase.first; sa; sa = sa->next) { + SpaceLink *sl; + for (sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_IMAGE) { + SpaceImage *sima = (SpaceImage *)sl; + ED_space_image_set(sima, scene, scene->obedit, ma->texpaintslot[ma->paint_active_slot].ima); + } + } + } + } + + DAG_id_tag_update(&ma->id, 0); + WM_main_add_notifier(NC_MATERIAL | ND_SHADING, ma); +} + static PointerRNA rna_Material_active_texture_get(PointerRNA *ptr) { Material *ma = (Material *)ptr->data; @@ -307,7 +354,7 @@ static EnumPropertyItem *rna_Material_texture_coordinates_itemf(bContext *UNUSED if (ma->material_type == MA_TYPE_VOLUME) { } - else if (ELEM3(ma->material_type, MA_TYPE_SURFACE, MA_TYPE_HALO, MA_TYPE_WIRE)) { + else if (ELEM(ma->material_type, MA_TYPE_SURFACE, MA_TYPE_HALO, MA_TYPE_WIRE)) { RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_UV); RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_STRAND); RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_WINDOW); @@ -2059,6 +2106,8 @@ void RNA_def_material(BlenderRNA *brna) "rna_Material_active_texture_set", "rna_Material_active_texture_editable", "MaterialTextureSlot", "MaterialTextureSlots", "rna_Material_update", "rna_Material_update"); + rna_def_texpaint_slots(brna, srna); + /* only material has this one */ prop = RNA_def_property(srna, "use_textures", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "septex", 1); @@ -2147,4 +2196,56 @@ void rna_def_mtex_common(BlenderRNA *brna, StructRNA *srna, const char *begin, RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, update_index); } +static void rna_def_tex_slot(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "TexPaintSlot", NULL); + RNA_def_struct_ui_text(srna, "Texture Paint Slot", + "Slot that contains information about texture painting"); + + prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_maxlength(prop, 64); /* else it uses the pointer size! */ + RNA_def_property_string_sdna(prop, NULL, "uvname"); + RNA_def_property_ui_text(prop, "UV Map", "Name of UV map"); + RNA_def_property_update(prop, NC_GEOM | ND_DATA, "rna_Material_update"); + + prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Index", "Index of MTex slot in the material"); +} + + +void rna_def_texpaint_slots(BlenderRNA *brna, StructRNA *srna) +{ + PropertyRNA *prop; + + rna_def_tex_slot(brna); + + /* mtex */ + prop = RNA_def_property(srna, "texture_paint_images", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "texpaintslot", NULL); + RNA_def_property_collection_funcs(prop, "rna_Material_texpaint_begin", "rna_iterator_array_next", "rna_iterator_array_end", + "rna_iterator_array_dereference_get", NULL, NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "Image"); + RNA_def_property_ui_text(prop, "Texture Slot Images", "Texture images used for texture painting"); + + prop = RNA_def_property(srna, "texture_paint_slots", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_funcs(prop, "rna_Material_texpaint_begin", "rna_iterator_array_next", "rna_iterator_array_end", + "rna_iterator_array_get", NULL, NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "TexPaintSlot"); + RNA_def_property_ui_text(prop, "Texture Slots", "Texture slots defining the mapping and influence of textures"); + + prop = RNA_def_property(srna, "paint_active_slot", PROP_INT, PROP_UNSIGNED); + RNA_def_property_range(prop, 0, SHRT_MAX); + RNA_def_property_ui_text(prop, "Active Paint Texture Index", "Index of active texture paint slot"); + RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, "rna_Material_active_paint_texture_index_update"); + + prop = RNA_def_property(srna, "paint_clone_slot", PROP_INT, PROP_UNSIGNED); + RNA_def_property_range(prop, 0, SHRT_MAX); + RNA_def_property_ui_text(prop, "Clone Paint Texture Index", "Index of clone texture paint slot"); + RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, NULL); +} + #endif diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 8c0f9980108..b0b99dcd2ca 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -3121,11 +3121,13 @@ static void rna_def_mesh(BlenderRNA *brna) "rna_Mesh_uv_texture_stencil_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Mask UV Map", "UV map to mask the painted area"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "uv_texture_stencil_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_funcs(prop, "rna_Mesh_uv_texture_stencil_index_get", "rna_Mesh_uv_texture_stencil_index_set", "rna_Mesh_uv_texture_index_range"); RNA_def_property_ui_text(prop, "Mask UV Map Index", "Mask UV map index"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); /* Tessellated face colors - used by renderers */ diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 212859cfea4..cc1f57d8a14 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -139,9 +139,11 @@ static void rna_Mesh_calc_smooth_groups(Mesh *mesh, int use_bitflags, int *r_pol r_group_total, use_bitflags); } -static void rna_Mesh_transform(Mesh *mesh, float *mat) +static void rna_Mesh_transform(Mesh *mesh, float *mat, int shape_keys) { - ED_mesh_transform(mesh, (float (*)[4])mat); + BKE_mesh_transform(mesh, (float (*)[4])mat, shape_keys); + + DAG_id_tag_update(&mesh->id, 0); } #else @@ -155,6 +157,7 @@ void RNA_api_mesh(StructRNA *srna) RNA_def_function_ui_description(func, "Transform mesh vertices by a matrix"); parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys"); func = RNA_def_function(srna, "calc_normals", "BKE_mesh_calc_normals"); RNA_def_function_ui_description(func, "Calculate vertex normals"); @@ -206,11 +209,17 @@ void RNA_api_mesh(StructRNA *srna) RNA_def_function_return(func, parm); func = RNA_def_function(srna, "validate", "BKE_mesh_validate"); - RNA_def_function_ui_description(func, "validate geometry, return True when the mesh has had " + RNA_def_function_ui_description(func, "Validate geometry, return True when the mesh has had " "invalid geometry corrected/removed"); RNA_def_boolean(func, "verbose", 0, "Verbose", "Output information about the errors found"); parm = RNA_def_boolean(func, "result", 0, "Result", ""); RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "validate_material_indices", "BKE_mesh_validate_material_indices"); + RNA_def_function_ui_description(func, "Validate material indices of polygons, return True when the mesh has had " + "invalid indices corrected (to default 0)"); + parm = RNA_def_boolean(func, "result", 0, "Result", ""); + RNA_def_function_return(func, parm); } #endif diff --git a/source/blender/makesrna/intern/rna_meta_api.c b/source/blender/makesrna/intern/rna_meta_api.c index 7fe59bc5be6..43dca6fe4f1 100644 --- a/source/blender/makesrna/intern/rna_meta_api.c +++ b/source/blender/makesrna/intern/rna_meta_api.c @@ -38,14 +38,16 @@ #include "BLI_utildefines.h" -#include "ED_mball.h" +#include "BKE_mball.h" #include "rna_internal.h" /* own include */ #ifdef RNA_RUNTIME -void rna_Meta_transform(struct MetaBall *mb, float *mat) +static void rna_Meta_transform(struct MetaBall *mb, float *mat) { - ED_mball_transform(mb, (float (*)[4])mat); + BKE_mball_transform(mb, (float (*)[4])mat); + + DAG_id_tag_update(&mb->id, 0); } #else diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 7ffc138e1a3..4911c106f53 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -2239,6 +2239,13 @@ static void rna_def_modifier_bevel(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0.15f, 1.0f, 0.05, 2); RNA_def_property_ui_text(prop, "Profile", "The profile shape (0.5 = round)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "material", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "mat"); + RNA_def_property_range(prop, -1, SHRT_MAX); + RNA_def_property_ui_text(prop, "Material", "Material index of generated faces, -1 for automatic"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + } static void rna_def_modifier_shrinkwrap(BlenderRNA *brna) @@ -2601,6 +2608,11 @@ static void rna_def_modifier_solidify(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SOLIDIFY_FLIP); RNA_def_property_ui_text(prop, "Flip Normals", "Invert the face direction"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "use_rim_only", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SOLIDIFY_NOSHELL); + RNA_def_property_ui_text(prop, "Only Rim", "Only add the rim to the original data"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_screw(BlenderRNA *brna) @@ -3681,26 +3693,27 @@ void RNA_def_modifier(BlenderRNA *brna) /* flags */ prop = RNA_def_property(srna, "show_viewport", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Realtime); - RNA_def_property_ui_text(prop, "Realtime", "Display modifier in realtime"); + RNA_def_property_ui_text(prop, "Realtime", "Display modifier in viewport"); RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); RNA_def_property_update(prop, 0, "rna_Modifier_update"); RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 0); prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Render); - RNA_def_property_ui_text(prop, "Render", "Use modifier during rendering"); + RNA_def_property_ui_text(prop, "Render", "Use modifier during render"); RNA_def_property_ui_icon(prop, ICON_SCENE, 0); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); prop = RNA_def_property(srna, "show_in_editmode", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Editmode); - RNA_def_property_ui_text(prop, "Edit Mode", "Use modifier while in the Edit mode"); + RNA_def_property_ui_text(prop, "Edit Mode", "Display modifier in Edit mode"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); RNA_def_property_ui_icon(prop, ICON_EDITMODE_HLT, 0); prop = RNA_def_property(srna, "show_on_cage", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_OnCage); - RNA_def_property_ui_text(prop, "On Cage", "Enable direct editing of modifier control cage"); + RNA_def_property_ui_text(prop, "On Cage", "Adjust edit cage to modifier result"); + RNA_def_property_ui_icon(prop, ICON_MESH_DATA, 0); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 065b6f787b6..e90de3631d6 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3172,6 +3172,12 @@ static void def_sh_output(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_sh_output_linestyle(StructRNA *srna) +{ + def_sh_output(srna); + def_mix_rgb(srna); +} + static void def_sh_material(StructRNA *srna) { PropertyRNA *prop; @@ -3762,6 +3768,16 @@ static void def_sh_uvmap(StructRNA *srna) RNA_def_struct_sdna_from(srna, "bNode", NULL); } +static void def_sh_uvalongstroke(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "use_tips", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); + RNA_def_property_ui_text(prop, "Use Tips", "Lower half of the texture is for tips of the stroke"); + 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[] = { @@ -6187,6 +6203,27 @@ static void def_cmp_planetrackdeform(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_cmp_sunbeams(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeSunBeams", "storage"); + + prop = RNA_def_property(srna, "source", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "source"); + RNA_def_property_range(prop, -100.0f, 100.0f); + RNA_def_property_ui_range(prop, -10.0f, 10.0f, 10, 3); + RNA_def_property_ui_text(prop, "Source", "Source point of rays as a factor of the image width & height"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "ray_length", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "ray_length"); + RNA_def_property_range(prop, 0.0f, 100.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 10, 3); + RNA_def_property_ui_text(prop, "Ray Length", "Length of rays as a factor of the image size"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + /* -- Texture Nodes --------------------------------------------------------- */ static void def_tex_output(StructRNA *srna) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 5d10a0a61c1..699bfaa0f93 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -61,12 +61,12 @@ EnumPropertyItem object_mode_items[] = { {OB_MODE_OBJECT, "OBJECT", ICON_OBJECT_DATAMODE, "Object Mode", ""}, {OB_MODE_EDIT, "EDIT", ICON_EDITMODE_HLT, "Edit Mode", ""}, + {OB_MODE_POSE, "POSE", ICON_POSE_HLT, "Pose Mode", ""}, {OB_MODE_SCULPT, "SCULPT", ICON_SCULPTMODE_HLT, "Sculpt Mode", ""}, {OB_MODE_VERTEX_PAINT, "VERTEX_PAINT", ICON_VPAINT_HLT, "Vertex Paint", ""}, {OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""}, {OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""}, {OB_MODE_PARTICLE_EDIT, "PARTICLE_EDIT", ICON_PARTICLEMODE, "Particle Edit", ""}, - {OB_MODE_POSE, "POSE", ICON_POSE_HLT, "Pose Mode", ""}, {0, NULL, 0, NULL, NULL} }; @@ -370,8 +370,14 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value) Object *ob = (Object *)ptr->data; ID *id = value.data; - if (id == NULL || ob->mode & OB_MODE_EDIT) + if (ob->mode & OB_MODE_EDIT) { return; + } + + /* assigning NULL only for empties */ + if ((id == NULL) && (ob->type != OB_EMPTY)) { + return; + } if (ob->type == OB_EMPTY) { if (ob->data) { @@ -379,7 +385,7 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value) ob->data = NULL; } - if (id && GS(id->name) == ID_IM) { + if (!id || GS(id->name) == ID_IM) { id_us_plus(id); ob->data = id; } @@ -391,11 +397,10 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value) if (ob->data) { id_us_min((ID *)ob->data); } - if (id) { - /* no need to type-check here ID. this is done in the _typef() function */ - BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name))); - id_us_plus(id); - } + + /* no need to type-check here ID. this is done in the _typef() function */ + BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name))); + id_us_plus(id); ob->data = id; test_object_materials(G.main, id); diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 0f37575146b..84eb94cfef4 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -598,9 +598,20 @@ static char *rna_FieldSettings_path(PointerRNA *ptr) static void rna_EffectorWeight_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { - DAG_id_tag_update((ID *)ptr->id.data, OB_RECALC_DATA | PSYS_RECALC_RESET); + ID *id = ptr->id.data; - WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + if (id && GS(id->name) == ID_SCE) { + Scene *scene = (Scene *)id; + Base *base; + + for (base = scene->base.first; base; base = base->next) { + BKE_ptcache_object_reset(scene, base->object, PTCACHE_RESET_DEPSGRAPH); + } + } + else { + DAG_id_tag_update(id, OB_RECALC_DATA | PSYS_RECALC_RESET); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + } } static void rna_EffectorWeight_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) @@ -733,7 +744,7 @@ static EnumPropertyItem *rna_Effector_shape_itemf(bContext *UNUSED(C), PointerRN return curve_shape_items; } - else if (ELEM3(ob->type, OB_MESH, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_MESH, OB_SURF, OB_FONT)) { if (ob->pd->forcefield == PFIELD_VORTEX) return vortex_shape_items; diff --git a/source/blender/makesrna/intern/rna_packedfile.c b/source/blender/makesrna/intern/rna_packedfile.c index d0c0ed25d22..34810e8a91b 100644 --- a/source/blender/makesrna/intern/rna_packedfile.c +++ b/source/blender/makesrna/intern/rna_packedfile.c @@ -45,14 +45,14 @@ EnumPropertyItem unpack_method_items[] = { #ifdef RNA_RUNTIME -void rna_PackedImage_data_get(PointerRNA *ptr, char *value) +static void rna_PackedImage_data_get(PointerRNA *ptr, char *value) { PackedFile *pf = (PackedFile *)ptr->data; memcpy(value, pf->data, (size_t)pf->size); value[pf->size] = '\0'; } -int rna_PackedImage_data_len(PointerRNA *ptr) +static int rna_PackedImage_data_len(PointerRNA *ptr) { PackedFile *pf = (PackedFile *)ptr->data; return pf->size; /* No need to include trailing NULL char here! */ diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 674ea92fcbe..113311383f4 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -316,9 +316,9 @@ static void rna_Particle_uv_on_emitter(ParticleData *particle, ReportList *repor static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *object, int particle_no, int step, float n_co[3]) { - ParticleSettings *part = 0; - ParticleData *pars = 0; - ParticleCacheKey *cache = 0; + ParticleSettings *part = NULL; + ParticleData *pars = NULL; + ParticleCacheKey *cache = NULL; int totchild = 0; int path_nbr = 0; int totpart; @@ -432,25 +432,24 @@ static EnumPropertyItem *rna_Particle_Material_itemf(bContext *C, PointerRNA *UN return item; } -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]) +/* return < 0 means invalid (no matching tessellated face could be found). */ +static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesystem, + ParticleSystemModifierData *modifier, ParticleData *particle, + int particle_no, float (**r_fuv)[4]) { - ParticleSettings *part = 0; + ParticleSettings *part = NULL; int totpart; int totchild = 0; - int num; + int totface; + int num = -1; - 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 */ + totface = modifier->dm->getNumTessFaces(modifier->dm); /* 1. check that everything is ok & updated */ - if (particlesystem == NULL) - return; + if (!particlesystem || !totface) { + return num; + } part = particlesystem->part; @@ -468,52 +467,31 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, Rep totpart = particlesystem->totpart; if (particle_no >= totpart + totchild) - return; + return num; -/* 3. start creating renderable things */ - /* setup per particle individual stuff */ + /* 2. get matching face index. */ if (particle_no < totpart) { - - /* get uvco & mcol */ - num = (ELEM(particle->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? - particle->num : particle->num_dmcache; + num = (ELEM(particle->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? particle->num : particle->num_dmcache; if (num == DMCACHE_NOTFOUND) - if (particle->num < modifier->dm->getNumTessFaces(modifier->dm)) - num = particle->num; + num = particle->num; - 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, r_uv); - } - else { - r_uv[0] = 0.0f; - r_uv[1] = 0.0f; + if (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (num != DMCACHE_NOTFOUND && num < totface) { + *r_fuv = &particle->fuv; + return num; } } } else { ChildParticle *cpa = particlesystem->child + particle_no - totpart; - num = cpa->num; - /* get uvco & mcol */ if (part->childtype == PART_CHILD_FACES) { - 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, r_uv); - } - else { - r_uv[0] = 0.0f; - r_uv[1] = 0.0f; + if (ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (num != DMCACHE_NOTFOUND && num < totface) { + *r_fuv = &cpa->fuv; + return num; } } } @@ -522,137 +500,78 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, Rep num = parent->num_dmcache; if (num == DMCACHE_NOTFOUND) - if (parent->num < modifier->dm->getNumTessFaces(modifier->dm)) - num = parent->num; - - 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, r_uv); - } - else { - r_uv[0] = 0.0f; - r_uv[1] = 0.0f; + num = parent->num; + + if (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (num != DMCACHE_NOTFOUND && num < totface) { + *r_fuv = &parent->fuv; + return num; } } } } + + return -1; } -static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem, ParticleSystemModifierData *modifier, - ParticleData *particle, int particle_no, int vcol_no, - float n_mcol[3]) +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; - int totpart; - int totchild = 0; - int num; - MCol mcol = {255, 255, 255, 255}; - - /* 1. check that everything is ok & updated */ - if (particlesystem == NULL) + if (!CustomData_has_layer(&modifier->dm->loopData, CD_MLOOPUV)) { + BKE_report(reports, RPT_ERROR, "Mesh has no UV data"); + zero_v2(r_uv); return; - - part = particlesystem->part; - - if (particlesystem->renderdata) { - totchild = particlesystem->totchild; - } - else { - totchild = (int)((float)particlesystem->totchild * (float)(part->disp) / 100.0f); } - /* can happen for disconnected/global hair */ - if (part->type == PART_HAIR && !particlesystem->childcache) - totchild = 0; - - totpart = particlesystem->totpart; - - if (particle_no >= totpart + totchild) - return; - - /* 3. start creating renderable things */ - /* setup per particle individual stuff */ - if (particle_no < totpart) { + { + float (*fuv)[4]; + /* Note all sanity checks are done in this helper func. */ + const int num = rna_ParticleSystem_tessfaceidx_on_emitter(particlesystem, modifier, particle, + particle_no, &fuv); - /* get uvco & mcol */ - num = particle->num_dmcache; + if (num < 0) { + /* No matching face found. */ + zero_v2(r_uv); + } + else { + MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); + MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, uv_no); - if (num == DMCACHE_NOTFOUND) - if (particle->num < modifier->dm->getNumTessFaces(modifier->dm)) - num = particle->num; - - if (n_mcol && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { - if (num != DMCACHE_NOTFOUND) { - MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); - MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no); - mc += num * 4; - - psys_interpolate_mcol(mc, mface->v4, particle->fuv, &mcol); - n_mcol[0] = (float)mcol.b / 255.0f; - n_mcol[1] = (float)mcol.g / 255.0f; - n_mcol[2] = (float)mcol.r / 255.0f; - } - else { - n_mcol[0] = 0.0f; - n_mcol[1] = 0.0f; - n_mcol[2] = 0.0f; - } + psys_interpolate_uvs(&mtface[num], mface->v4, *fuv, r_uv); } } - else { - ChildParticle *cpa = particlesystem->child + particle_no - totpart; +} - num = cpa->num; +static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem, ReportList *reports, + ParticleSystemModifierData *modifier, ParticleData *particle, + int particle_no, int vcol_no, float r_mcol[3]) +{ + if (!CustomData_has_layer(&modifier->dm->loopData, CD_MLOOPCOL)) { + BKE_report(reports, RPT_ERROR, "Mesh has no VCol data"); + zero_v3(r_mcol); + return; + } - /* get uvco & mcol */ - if (part->childtype == PART_CHILD_FACES) { - if (n_mcol && 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); - MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no); - mc += cpa->num * 4; - - psys_interpolate_mcol(mc, mface->v4, cpa->fuv, &mcol); - n_mcol[0] = (float)mcol.b / 255.0f; - n_mcol[1] = (float)mcol.g / 255.0f; - n_mcol[2] = (float)mcol.r / 255.0f; - } - else { - n_mcol[0] = 0.0f; - n_mcol[1] = 0.0f; - n_mcol[2] = 0.0f; - } - } + { + float (*fuv)[4]; + /* Note all sanity checks are done in this helper func. */ + const int num = rna_ParticleSystem_tessfaceidx_on_emitter(particlesystem, modifier, particle, + particle_no, &fuv); + + if (num < 0) { + /* No matching face found. */ + zero_v3(r_mcol); } else { - ParticleData *parent = particlesystem->particles + cpa->parent; - num = parent->num_dmcache; - - if (num == DMCACHE_NOTFOUND) - if (parent->num < modifier->dm->getNumTessFaces(modifier->dm)) - num = parent->num; - - if (n_mcol && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { - if (num != DMCACHE_NOTFOUND) { - MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); - MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no); - mc += num * 4; - - psys_interpolate_mcol(mc, mface->v4, parent->fuv, &mcol); - n_mcol[0] = (float)mcol.b / 255.0f; - n_mcol[1] = (float)mcol.g / 255.0f; - n_mcol[2] = (float)mcol.r / 255.0f; - } - else { - n_mcol[0] = 0.0f; - n_mcol[1] = 0.0f; - n_mcol[2] = 0.0f; - } - } + MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); + MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no); + MCol mcol; + + psys_interpolate_mcol(&mc[num * 4], mface->v4, *fuv, &mcol); + r_mcol[0] = (float)mcol.b / 255.0f; + r_mcol[1] = (float)mcol.g / 255.0f; + r_mcol[2] = (float)mcol.r / 255.0f; } } } @@ -2142,7 +2061,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "use_dynamic_rotation", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_ROT_DYN); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Dynamic", "Particle rotations are effected by collisions and effectors"); + RNA_def_property_ui_text(prop, "Dynamic", "Particle rotations are affected by collisions and effectors"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "use_multiply_size_mass", PROP_BOOLEAN, PROP_NONE); @@ -2194,7 +2113,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "use_self_effect", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_SELF_EFFECT); - RNA_def_property_ui_text(prop, "Self Effect", "Particle effectors effect themselves"); + RNA_def_property_ui_text(prop, "Self Effect", "Particle effectors affect themselves"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); @@ -2520,7 +2439,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "simplify_refsize", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "simplify_refsize"); - RNA_def_property_range(prop, 1, 32768); + RNA_def_property_range(prop, 1, SHRT_MAX); RNA_def_property_ui_text(prop, "Reference Size", "Reference size in pixels, after which simplification begins"); prop = RNA_def_property(srna, "simplify_rate", PROP_FLOAT, PROP_NONE); @@ -3496,6 +3415,7 @@ static void rna_def_particle_system(BlenderRNA *brna) /* extract hair mcols */ func = RNA_def_function(srna, "mcol_on_emitter", "rna_ParticleSystem_mcol_on_emitter"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); 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); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 13349446168..682a7f4ee31 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -880,7 +880,7 @@ static EnumPropertyItem *rna_ImageFormatSettings_color_depth_itemf(bContext *UNU } else { const int depth_ok = BKE_imtype_valid_depths(imf->imtype); - const int is_float = ELEM3(imf->imtype, R_IMF_IMTYPE_RADHDR, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER); + const int is_float = ELEM(imf->imtype, R_IMF_IMTYPE_RADHDR, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER); EnumPropertyItem *item_8bit = &image_color_depth_items[0]; EnumPropertyItem *item_10bit = &image_color_depth_items[1]; @@ -1316,7 +1316,7 @@ static void object_simplify_update(Object *ob) ob->id.flag &= ~LIB_DOIT; for (md = ob->modifiers.first; md; md = md->next) { - if (ELEM3(md->type, eModifierType_Subsurf, eModifierType_Multires, eModifierType_ParticleSystem)) { + if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires, eModifierType_ParticleSystem)) { DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } } @@ -2120,6 +2120,11 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Use Unified Weight", "Instead of per-brush weight, the weight is shared across brushes"); + prop = RNA_def_property(srna, "use_unified_color", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", UNIFIED_PAINT_COLOR); + RNA_def_property_ui_text(prop, "Use Unified Color", + "Instead of per-brush color, the color is shared across brushes"); + /* unified paint settings that override the equivalent settings * from the active brush */ prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL); @@ -2152,6 +2157,18 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Weight", "Weight to assign in vertex groups"); RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update"); + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "rgb"); + RNA_def_property_ui_text(prop, "Color", ""); + RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update"); + + prop = RNA_def_property(srna, "secondary_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "secondary_rgb"); + RNA_def_property_ui_text(prop, "Secondary Color", ""); + RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update"); + prop = RNA_def_property(srna, "use_pressure_size", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", UNIFIED_PAINT_BRUSH_SIZE_PRESSURE); RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); @@ -3245,7 +3262,7 @@ static void rna_def_bake_data(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "cage_extrusion", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.0, MAXFLOAT); + RNA_def_property_range(prop, 0.0, FLT_MAX); RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3); RNA_def_property_ui_text(prop, "Cage Extrusion", "Distance to use for the inward ray cast when using selected to active"); @@ -5621,7 +5638,7 @@ void RNA_def_scene(BlenderRNA *brna) prop = RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_ACCELERATION); RNA_def_property_float_sdna(prop, NULL, "physics_settings.gravity"); RNA_def_property_array(prop, 3); - RNA_def_property_range(prop, -200.0f, 200.0f); + RNA_def_property_ui_range(prop, -200.0f, 200.0f, 1, 2); RNA_def_property_ui_text(prop, "Gravity", "Constant acceleration in a given direction"); RNA_def_property_update(prop, 0, "rna_Physics_update"); diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index e0431fcff16..cf591dc7750 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -128,6 +128,13 @@ static EnumPropertyItem *rna_Area_type_itemf(bContext *UNUSED(C), PointerRNA *UN return space_type_items + 1; } +static int rna_Area_type_get(PointerRNA *ptr) +{ + ScrArea *sa = (ScrArea *)ptr->data; + /* read from this instead of 'spacetype' for correct reporting: T41435 */ + return sa->butspacetype; +} + static void rna_Area_type_set(PointerRNA *ptr, int value) { ScrArea *sa = (ScrArea *)ptr->data; @@ -232,7 +239,7 @@ static void rna_def_area(BlenderRNA *brna) 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_enum_funcs(prop, "rna_Area_type_get", "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); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index a3a06893522..d48d8589f96 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -34,8 +34,13 @@ #include "DNA_ID.h" #include "DNA_scene_types.h" #include "DNA_brush_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "BKE_paint.h" +#include "BKE_material.h" + +#include "ED_image.h" #include "WM_api.h" #include "WM_types.h" @@ -71,11 +76,14 @@ EnumPropertyItem symmetrize_direction_items[] = { #include "MEM_guardedalloc.h" #include "BKE_context.h" +#include "BKE_DerivedMesh.h" #include "BKE_pointcache.h" #include "BKE_particle.h" #include "BKE_depsgraph.h" #include "BKE_pbvh.h" +#include "GPU_buffers.h" + #include "ED_particle.h" static EnumPropertyItem particle_edit_disconnected_hair_brush_items[] = { @@ -285,8 +293,100 @@ static void rna_Paint_brush_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po BKE_paint_invalidate_overlay_all(); WM_main_add_notifier(NC_BRUSH | NA_EDITED, br); } + +static void rna_ImaPaint_viewport_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +{ + /* not the best solution maybe, but will refresh the 3D viewport */ + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); +} + +static void rna_ImaPaint_mode_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) +{ + Object *ob = OBACT; + + /* of course we need to invalidate here */ + BKE_texpaint_slots_refresh_object(scene, ob); + + /* we assume that changing the current mode will invalidate the uv layers so we need to refresh display */ + GPU_drawobject_free(ob->derivedFinal); + WM_main_add_notifier(NC_GEOM | ND_DATA, &ob->id); +} + +static void rna_ImaPaint_canvas_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) +{ + bScreen *sc; + Image *ima = scene->toolsettings->imapaint.canvas; + + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + ScrArea *sa; + for (sa = sc->areabase.first; sa; sa = sa->next) { + SpaceLink *sl; + for (sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_IMAGE) { + SpaceImage *sima = (SpaceImage *)sl; + ED_space_image_set(sima, scene, scene->obedit, ima); + } + } + } + } + + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); +} #else +static void rna_def_palettecolor(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "PaletteColor", NULL); + RNA_def_struct_ui_text(srna, "Palette Color", ""); + + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "rgb"); + RNA_def_property_ui_text(prop, "Color", ""); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "value"); + RNA_def_property_ui_text(prop, "Value", ""); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "value"); + RNA_def_property_ui_text(prop, "Weight", ""); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); +} + + +static void rna_def_palette(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "Palette", "ID"); + RNA_def_struct_ui_text(srna, "Palette", ""); + RNA_def_struct_ui_icon(srna, ICON_COLOR); + + prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "PaletteColor"); + RNA_def_property_ui_text(prop, "Palette Color", "Colors that are part of this palette"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); +} + +static void rna_def_paint_curve(BlenderRNA *brna) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, "PaintCurve", "ID"); + RNA_def_struct_ui_text(srna, "Paint Curve", ""); + RNA_def_struct_ui_icon(srna, ICON_CURVE_BEZCURVE); +} + + static void rna_def_paint(BlenderRNA *brna) { StructRNA *srna; @@ -302,6 +402,11 @@ static void rna_def_paint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Brush", "Active Brush"); RNA_def_property_update(prop, 0, "rna_Paint_brush_update"); + prop = RNA_def_property(srna, "palette", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, NULL); + RNA_def_property_ui_text(prop, "Palette", "Active Palette"); + prop = RNA_def_property(srna, "show_brush", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SHOW_BRUSH); RNA_def_property_ui_text(prop, "Show Brush", ""); @@ -507,6 +612,14 @@ static void rna_def_image_paint(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + + static EnumPropertyItem paint_type_items[] = { + {IMAGEPAINT_MODE_MATERIAL, "MATERIAL", 0, + "Material", "Detect image slots from the material"}, + {IMAGEPAINT_MODE_IMAGE, "IMAGE", 0, + "Image", "Set image for texture painting directly"}, + {0, NULL, 0, NULL, NULL} + }; srna = RNA_def_struct(brna, "ImagePaint", "Paint"); RNA_def_struct_sdna(srna, "ImagePaintSettings"); @@ -532,13 +645,36 @@ static void rna_def_image_paint(BlenderRNA *brna) prop = RNA_def_property(srna, "use_stencil_layer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_STENCIL); RNA_def_property_ui_text(prop, "Stencil Layer", "Set the mask layer from the UV map buttons"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_viewport_update"); prop = RNA_def_property(srna, "invert_stencil", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_STENCIL_INV); RNA_def_property_ui_text(prop, "Invert", "Invert the stencil layer"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_viewport_update"); + + prop = RNA_def_property(srna, "stencil_image", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "stencil"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Stencil Image", "Image used as stencil"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_viewport_update"); + + prop = RNA_def_property(srna, "canvas", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Canvas", "Image used as canvas"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_canvas_update"); + + prop = RNA_def_property(srna, "clone_image", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "clone"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Clone Image", "Image used as clone source"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + prop = RNA_def_property(srna, "stencil_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "stencil_col"); + RNA_def_property_ui_text(prop, "Stencil Color", "Stencil color in the viewport"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_viewport_update"); + prop = RNA_def_property(srna, "use_clone_layer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_CLONE); RNA_def_property_ui_text(prop, "Clone Map", @@ -558,6 +694,11 @@ static void rna_def_image_paint(BlenderRNA *brna) prop = RNA_def_int_array(srna, "screen_grab_size", 2, NULL, 0, 0, "screen_grab_size", "Size to capture the image for re-projecting", 0, 0); RNA_def_property_range(prop, 512, 16384); + + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, paint_type_items); + RNA_def_property_ui_text(prop, "Mode", "Mode of operation for projection painting"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_mode_update"); } static void rna_def_particle_edit(BlenderRNA *brna) @@ -741,6 +882,9 @@ void RNA_def_sculpt_paint(BlenderRNA *brna) { /* *** Non-Animated *** */ RNA_define_animate_sdna(false); + rna_def_palettecolor(brna); + rna_def_palette(brna); + rna_def_paint_curve(brna); rna_def_paint(brna); rna_def_sculpt(brna); rna_def_uv_sculpt(brna); diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c index aeef04f4ac7..3944b59dff7 100644 --- a/source/blender/makesrna/intern/rna_sensor.c +++ b/source/blender/makesrna/intern/rna_sensor.c @@ -405,6 +405,12 @@ static void rna_def_mouse_sensor(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static const EnumPropertyItem prop_mouse_type_items[] = { + {SENS_COLLISION_PROPERTY, "PROPERTY", ICON_LOGIC, "Property", "Use a material for ray intersections"}, + {SENS_COLLISION_MATERIAL, "MATERIAL", ICON_MATERIAL_DATA, "Material", "Use a property for ray intersections"}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "MouseSensor", "Sensor"); RNA_def_struct_ui_text(srna, "Mouse Sensor", "Sensor to detect mouse events"); RNA_def_struct_sdna_from(srna, "bMouseSensor", "data"); @@ -419,6 +425,27 @@ static void rna_def_mouse_sensor(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_MOUSE_FOCUS_PULSE); RNA_def_property_ui_text(prop, "Pulse", "Moving the mouse over a different object generates a pulse"); RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "use_material", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode"); + RNA_def_property_enum_items(prop, prop_mouse_type_items); + RNA_def_property_ui_text(prop, "M/P", "Toggle collision on material or property"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "propname"); + RNA_def_property_ui_text(prop, "Property", "Only look for objects with this property (blank = all objects)"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "matname"); + RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "use_x_ray", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_RAY_XRAY); + RNA_def_property_ui_text(prop, "X-Ray", "Toggle X-Ray option (see through objects that don't have the property)"); + RNA_def_property_update(prop, NC_LOGIC, NULL); } static void rna_def_keyboard_sensor(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index ddae8b2a01a..00f0a6ff487 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -539,6 +539,8 @@ static StructRNA *rna_Sequence_refine(struct PointerRNA *ptr) return &RNA_ColorSequence; case SEQ_TYPE_SPEED: return &RNA_SpeedControlSequence; + case SEQ_TYPE_GAUSSIAN_BLUR: + return &RNA_GaussianBlurSequence; default: return &RNA_Sequence; } @@ -1374,6 +1376,7 @@ static void rna_def_sequence(BlenderRNA *brna) {SEQ_TYPE_SPEED, "SPEED", 0, "Speed", ""}, {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""}, {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""}, + {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""}, {0, NULL, 0, NULL, NULL} }; @@ -2203,6 +2206,23 @@ static void rna_def_speed_control(StructRNA *srna) RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_COMPRESS_IPO_Y); RNA_def_property_ui_text(prop, "Scale to length", "Scale values from 0.0 to 1.0 to target sequence length"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); + +} + +static void rna_def_gaussian_blur(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "GaussianBlurVars", "effectdata"); + prop = RNA_def_property(srna, "size_x", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_ui_text(prop, "Size X", "Size of the blur along X axis"); + RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, -1); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); + + prop = RNA_def_property(srna, "size_y", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_ui_text(prop, "Size Y", "Size of the blur along Y axis"); + RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, -1); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); } static EffectInfo def_effects[] = { @@ -2227,6 +2247,8 @@ static EffectInfo def_effects[] = { "Sequence strip applying affine transformations to other strips", rna_def_transform, 1}, {"WipeSequence", "Wipe Sequence", "Sequence strip creating a wipe transition", rna_def_wipe, 1}, + {"GaussianBlurSequence", "Gaussian Blur Sequence", "Sequence strip creating a gaussian blur", + rna_def_gaussian_blur, 1}, {"", "", "", NULL, 0} }; diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 30fcb63169b..70370f1ae36 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -468,6 +468,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) {SEQ_TYPE_SPEED, "SPEED", 0, "Speed", ""}, {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""}, {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""}, + {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index 6e0d374e3e9..887670eb5ff 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -633,21 +633,21 @@ static void rna_def_smoke_flow_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "vel_multi"); - RNA_def_property_range(prop, -2.0, 2.0); + RNA_def_property_range(prop, -100.0, 100.0); RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5); RNA_def_property_ui_text(prop, "Source", "Multiplier of source velocity passed to smoke"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); prop = RNA_def_property(srna, "velocity_normal", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "vel_normal"); - RNA_def_property_range(prop, -2.0, 2.0); + RNA_def_property_range(prop, -100.0, 100.0); RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5); RNA_def_property_ui_text(prop, "Normal", "Amount of normal directional velocity"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); prop = RNA_def_property(srna, "velocity_random", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "vel_random"); - RNA_def_property_range(prop, 0.0, 2.0); + RNA_def_property_range(prop, 0.0, 10.0); RNA_def_property_ui_range(prop, 0.0, 2.0, 0.05, 5); RNA_def_property_ui_text(prop, "Random", "Amount of random velocity"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 39d6e665077..5ca38aae9bc 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -87,6 +87,18 @@ EnumPropertyItem space_type_items[] = { {0, NULL, 0, NULL, NULL} }; +static EnumPropertyItem pivot_items_full[] = { + {V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", + "Pivot around bounding box center of selected object(s)"}, + {V3D_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Pivot around the 3D cursor"}, + {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, + "Individual Origins", "Pivot around each object's own origin"}, + {V3D_CENTROID, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point", + "Pivot around the median point of selected objects"}, + {V3D_ACTIVE, "ACTIVE_ELEMENT", ICON_ROTACTIVE, "Active Element", "Pivot around active object"}, + {0, NULL, 0, NULL, NULL} +}; + static EnumPropertyItem draw_channels_items[] = { {SI_USE_ALPHA, "COLOR_ALPHA", ICON_IMAGE_RGB_ALPHA, "Color and Alpha", "Draw image with RGB colors and alpha transparency"}, @@ -454,12 +466,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 *bmain, Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_SpaceView3D_viewport_shade_update(Main *bmain, Scene *scene, PointerRNA *ptr) { View3D *v3d = (View3D *)(ptr->data); ScrArea *sa = rna_area_from_space(ptr); - ED_view3d_shade_update(bmain, v3d, sa); + ED_view3d_shade_update(bmain, scene, v3d, sa); } static void rna_SpaceView3D_matcap_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) @@ -616,9 +628,7 @@ static int rna_SpaceView3D_viewport_shade_get(PointerRNA *ptr) View3D *v3d = (View3D *)ptr->data; int drawtype = v3d->drawtype; - if (drawtype == OB_MATERIAL && !BKE_scene_use_new_shading_nodes(scene)) - return OB_SOLID; - else if (drawtype == OB_RENDER && !(type && type->view_draw)) + if (drawtype == OB_RENDER && !(type && type->view_draw)) return OB_SOLID; return drawtype; @@ -637,9 +647,7 @@ static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_WIRE); RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_SOLID); RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_TEXTURE); - - if (BKE_scene_use_new_shading_nodes(scene)) - RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_MATERIAL); + RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_MATERIAL); if (type && type->view_draw) RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_RENDER); @@ -803,6 +811,24 @@ static void rna_SpaceImageEditor_scopes_update(Main *UNUSED(bmain), Scene *scene ED_space_image_release_buffer(sima, ibuf, lock); } +static EnumPropertyItem *rna_SpaceImageEditor_pivot_itemf(bContext *UNUSED(C), PointerRNA *ptr, + PropertyRNA *UNUSED(prop), bool *UNUSED(r_free)) +{ + static EnumPropertyItem pivot_items[] = { + {V3D_CENTER, "CENTER", ICON_ROTATE, "Bounding Box Center", ""}, + {V3D_CENTROID, "MEDIAN", ICON_ROTATECENTER, "Median Point", ""}, + {V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""}, + {0, NULL, 0, NULL, NULL} + }; + + SpaceImage *sima = (SpaceImage *)ptr->data; + + if (sima->mode == SI_MODE_PAINT) + return pivot_items_full; + else + return pivot_items; +} + /* Space Text Editor */ static void rna_SpaceTextEditor_word_wrap_set(PointerRNA *ptr, int value) @@ -1274,25 +1300,25 @@ static int rna_SpaceNodeEditor_path_length(PointerRNA *ptr) return ED_node_tree_path_length(snode); } -void rna_SpaceNodeEditor_path_clear(SpaceNode *snode, bContext *C) +static void rna_SpaceNodeEditor_path_clear(SpaceNode *snode, bContext *C) { ED_node_tree_start(snode, NULL, NULL, NULL); ED_node_tree_update(C); } -void rna_SpaceNodeEditor_path_start(SpaceNode *snode, bContext *C, PointerRNA *node_tree) +static void rna_SpaceNodeEditor_path_start(SpaceNode *snode, bContext *C, PointerRNA *node_tree) { ED_node_tree_start(snode, (bNodeTree *)node_tree->data, NULL, NULL); ED_node_tree_update(C); } -void rna_SpaceNodeEditor_path_append(SpaceNode *snode, bContext *C, PointerRNA *node_tree, PointerRNA *node) +static void rna_SpaceNodeEditor_path_append(SpaceNode *snode, bContext *C, PointerRNA *node_tree, PointerRNA *node) { ED_node_tree_push(snode, node_tree->data, node->data); ED_node_tree_update(C); } -void rna_SpaceNodeEditor_path_pop(SpaceNode *snode, bContext *C) +static void rna_SpaceNodeEditor_path_pop(SpaceNode *snode, bContext *C) { ED_node_tree_pop(snode); ED_node_tree_update(C); @@ -1492,6 +1518,11 @@ static void rna_def_space_image_uv(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Draw Other Objects", "Draw other selected objects that share the same image"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); + prop = RNA_def_property(srna, "show_texpaint", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SI_NO_DRAW_TEXPAINT); + RNA_def_property_ui_text(prop, "Draw Texture Paint UVs", "Draw overlay of texture paint uv layer"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); + prop = RNA_def_property(srna, "show_normalized_coords", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_COORDFLOATS); RNA_def_property_ui_text(prop, "Normalized Coordinates", @@ -1752,24 +1783,12 @@ static void rna_def_space_view3d(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - 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, "3D Cursor", "Pivot around the 3D cursor"}, - {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, - "Individual Origins", "Pivot around each object's own origin"}, - {V3D_CENTROID, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point", - "Pivot around the median point of selected objects"}, - {V3D_ACTIVE, "ACTIVE_ELEMENT", ICON_ROTACTIVE, "Active Element", "Pivot around active object"}, - {0, NULL, 0, NULL, NULL} - }; - static EnumPropertyItem manipulators_items[] = { - {V3D_MANIP_TRANSLATE, "TRANSLATE", ICON_MAN_TRANS, "Manipulator Translate", + {V3D_MANIP_TRANSLATE, "TRANSLATE", ICON_MAN_TRANS, "Translate", "Use the manipulator for movement transformations"}, - {V3D_MANIP_ROTATE, "ROTATE", ICON_MAN_ROT, "Manipulator Rotate", + {V3D_MANIP_ROTATE, "ROTATE", ICON_MAN_ROT, "Rotate", "Use the manipulator for rotation transformations"}, - {V3D_MANIP_SCALE, "SCALE", ICON_MAN_SCALE, "Manipulator Scale", + {V3D_MANIP_SCALE, "SCALE", ICON_MAN_SCALE, "Scale", "Use the manipulator for scale transformations"}, {0, NULL, 0, NULL, NULL} }; @@ -2042,7 +2061,7 @@ static void rna_def_space_view3d(BlenderRNA *brna) prop = RNA_def_property(srna, "pivot_point", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "around"); - RNA_def_property_enum_items(prop, pivot_items); + RNA_def_property_enum_items(prop, pivot_items_full); RNA_def_property_ui_text(prop, "Pivot Point", "Pivot center for rotation/scaling"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_pivot_update"); @@ -2310,13 +2329,6 @@ static void rna_def_space_image(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; - static EnumPropertyItem pivot_items[] = { - {V3D_CENTER, "CENTER", ICON_ROTATE, "Bounding Box Center", ""}, - {V3D_CENTROID, "MEDIAN", ICON_ROTATECENTER, "Median Point", ""}, - {V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""}, - {0, NULL, 0, NULL, NULL} - }; - StructRNA *srna; PropertyRNA *prop; @@ -2404,7 +2416,8 @@ static void rna_def_space_image(BlenderRNA *brna) prop = RNA_def_property(srna, "pivot_point", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "around"); - RNA_def_property_enum_items(prop, pivot_items); + RNA_def_property_enum_items(prop, pivot_items_full); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceImageEditor_pivot_itemf"); RNA_def_property_ui_text(prop, "Pivot", "Rotation/Scaling Pivot"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); @@ -3398,13 +3411,18 @@ static void rna_def_space_node(BlenderRNA *brna) {SNODE_TEX_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Edit texture nodes from Object"}, {SNODE_TEX_WORLD, "WORLD", ICON_WORLD_DATA, "World", "Edit texture nodes from World"}, {SNODE_TEX_BRUSH, "BRUSH", ICON_BRUSH_DATA, "Brush", "Edit texture nodes from Brush"}, +#ifdef WITH_FREESTYLE {SNODE_TEX_LINESTYLE, "LINESTYLE", ICON_LINE_DATA, "Line Style", "Edit texture nodes from Line Style"}, +#endif {0, NULL, 0, NULL, NULL} }; static EnumPropertyItem shader_type_items[] = { {SNODE_SHADER_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Edit shader nodes from Object"}, {SNODE_SHADER_WORLD, "WORLD", ICON_WORLD_DATA, "World", "Edit shader nodes from World"}, +#ifdef WITH_FREESTYLE + {SNODE_SHADER_LINESTYLE, "LINESTYLE", ICON_LINE_DATA, "Line Style", "Edit shader nodes from Line Style"}, +#endif {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index 537ffe630a2..899da62d9d3 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -393,6 +393,7 @@ static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerR nodeUpdateID(scene->nodetree, &clip->id); WM_main_add_notifier(NC_SCENE | ND_NODES, NULL); + WM_main_add_notifier(NC_SCENE, NULL); DAG_id_tag_update(&clip->id, 0); } diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index f14fadfa722..92c5530202b 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -210,7 +210,12 @@ static StructRNA *rna_Panel_register(Main *bmain, ReportList *reports, void *dat identifier, (int)sizeof(dummypt.idname)); return NULL; } - + + if ((dummypt.category[0] == '\0') && (dummypt.region_type == RGN_TYPE_TOOLS)) { + /* Use a fallback, otherwise an empty value will draw the panel in every category. */ + strcpy(dummypt.category, PNL_CATEGORY_FALLBACK); + } + if (!(art = region_type_find(reports, dummypt.space_type, dummypt.region_type))) return NULL; @@ -987,7 +992,6 @@ static void rna_def_panel(BlenderRNA *brna) prop = RNA_def_property(srna, "bl_category", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "type->category"); - RNA_def_property_string_default(prop, BLF_I18NCONTEXT_DEFAULT_BPYRNA); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index d3d17a90f99..b13bdedaffd 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -462,6 +462,13 @@ void RNA_api_ui_layout(StructRNA *srna) 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", false, "", "Align buttons to each other"); + /* radial/pie layout */ + func = RNA_def_function(srna, "menu_pie", "uiLayoutRadial"); + parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); + RNA_def_function_return(func, parm); + RNA_def_function_ui_description(func, "Sublayout. Items placed in this sublayout are placed " + "in a radial fashion around the menu center)"); + /* Icon of a rna pointer */ func = RNA_def_function(srna, "icon", "rna_ui_get_rnaptr_icon"); parm = RNA_def_int(func, "icon_value", ICON_NONE, 0, INT_MAX, "", "Icon identifier", 0, INT_MAX); @@ -740,6 +747,11 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_boolean(func, "lock_luminosity", false, "", "Keep the color at its original vector length"); RNA_def_boolean(func, "cubic", false, "", "Cubic saturation for picking values close to white"); + func = RNA_def_function(srna, "template_palette", "uiTemplatePalette"); + RNA_def_function_ui_description(func, "Item. A palette used to pick colors"); + api_ui_item_rna_common(func); + RNA_def_boolean(func, "color", 0, "", "Display the colors as colors or values"); + func = RNA_def_function(srna, "template_image_layers", "uiTemplateImageLayers"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "image", "Image", "", ""); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index f4974266f60..aa378955fb0 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -91,6 +91,7 @@ EnumPropertyItem navigation_mode_items[] = { #include "BKE_idprop.h" #include "GPU_draw.h" +#include "GPU_select.h" #include "BLF_api.h" @@ -332,6 +333,11 @@ static void rna_UserDef_viewport_lights_update(Main *bmain, Scene *scene, Pointe rna_userdef_update(bmain, scene, ptr); } +static int rna_Scene_GPU_selection_supported(UserDef *UNUSED(U)) +{ + return GPU_select_query_check_support(); +} + static void rna_userdef_autosave_update(Main *bmain, Scene *scene, PointerRNA *ptr) { wmWindowManager *wm = bmain->wm.first; @@ -947,6 +953,12 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_ui_text(prop, "Menu Backdrop Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "wcol_pie_menu", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_ui_text(prop, "Pie Menu Colors", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "wcol_tooltip", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_ui_text(prop, "Tooltip Colors", ""); @@ -1292,7 +1304,23 @@ static void rna_def_userdef_theme_spaces_face(StructRNA *srna) RNA_def_property_update(prop, 0, "rna_userdef_update"); } -static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs, bool incl_lastsel, bool incl_vector) +static void rna_def_userdef_theme_spaces_paint_curves(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "paint_curve_handle", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Paint Curve Handle", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "paint_curve_pivot", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Paint Curve Pivot", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); +} + +static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs, bool incl_lastsel, + bool incl_vector, bool incl_verthandle) { PropertyRNA *prop; @@ -1377,8 +1405,8 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Align handle selected color", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - - if (incl_nurbs == false) { + + if (!incl_nurbs) { /* assume that when nurbs are off, this is for 2D (i.e. anim) editors */ prop = RNA_def_property(srna, "handle_auto_clamped", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "handle_auto_clamped"); @@ -1400,6 +1428,23 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs RNA_def_property_ui_text(prop, "Last selected point", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); } + + if (incl_verthandle) { + prop = RNA_def_property(srna, "handle_vertex", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Handle Vertex", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "handle_vertex_select", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Handle Vertex Select", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "handle_vertex_size", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 0, 255); + RNA_def_property_ui_text(prop, "Handle Vertex Size", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + } } static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna) @@ -1488,7 +1533,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna) rna_def_userdef_theme_spaces_vertex(srna); rna_def_userdef_theme_spaces_edge(srna); rna_def_userdef_theme_spaces_face(srna); - rna_def_userdef_theme_spaces_curves(srna, true, true, true); + rna_def_userdef_theme_spaces_curves(srna, true, true, true, false); prop = RNA_def_property(srna, "extra_edge_len", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); @@ -1525,6 +1570,12 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Vertex Normal", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "split_normal", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "loop_normal"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Split Normal", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "bone_solid", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Bone Solid", ""); @@ -1567,6 +1618,8 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna) RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Skin Root", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + + rna_def_userdef_theme_spaces_paint_curves(srna); } @@ -1632,22 +1685,7 @@ static void rna_def_userdef_theme_space_graph(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_userdef_update"); rna_def_userdef_theme_spaces_vertex(srna); - rna_def_userdef_theme_spaces_curves(srna, false, true, true); - - prop = RNA_def_property(srna, "handle_vertex", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Handle Vertex", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop = RNA_def_property(srna, "handle_vertex_select", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Handle Vertex Select", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop = RNA_def_property(srna, "handle_vertex_size", PROP_INT, PROP_NONE); - RNA_def_property_range(prop, 0, 255); - RNA_def_property_ui_text(prop, "Handle Vertex Size", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); + rna_def_userdef_theme_spaces_curves(srna, false, true, true, true); } static void rna_def_userdef_theme_space_file(BlenderRNA *brna) @@ -2258,7 +2296,9 @@ static void rna_def_userdef_theme_space_image(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Current Frame", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - rna_def_userdef_theme_spaces_curves(srna, false, false, false); + rna_def_userdef_theme_spaces_curves(srna, false, false, false, true); + + rna_def_userdef_theme_spaces_paint_curves(srna); } static void rna_def_userdef_theme_space_seq(BlenderRNA *brna) @@ -2745,21 +2785,6 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Current Frame", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop = RNA_def_property(srna, "handle_vertex", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Handle Vertex", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop = RNA_def_property(srna, "handle_vertex_select", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Handle Vertex Select", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop = RNA_def_property(srna, "handle_vertex_size", PROP_INT, PROP_NONE); - RNA_def_property_range(prop, 0, 255); - RNA_def_property_ui_text(prop, "Handle Vertex Size", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop = RNA_def_property(srna, "strips", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "strip"); RNA_def_property_array(prop, 3); @@ -2772,7 +2797,7 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Strips Selected", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - rna_def_userdef_theme_spaces_curves(srna, false, false, false); + rna_def_userdef_theme_spaces_curves(srna, false, false, false, true); } static void rna_def_userdef_themes(BlenderRNA *brna) @@ -3141,7 +3166,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) /* display */ prop = RNA_def_property(srna, "show_tooltips", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_TOOLTIPS); - RNA_def_property_ui_text(prop, "Tooltips", "Display tooltips"); + RNA_def_property_ui_text(prop, "Tooltips", "Display tooltips (when off hold Alt to force display)"); prop = RNA_def_property(srna, "show_tooltips_python", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", USER_TOOLTIPS_PYTHON); @@ -3195,6 +3220,26 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Sub Level Menu Open Delay", "Time delay in 1/10 seconds before automatically opening sub level menus"); + /* pie menus */ + prop = RNA_def_property(srna, "pie_initial_timeout", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 0, 1000); + RNA_def_property_ui_text(prop, "Recenter Timeout", + "Pie menus will use the initial mouse position as center for this amount of time " + "(in 1/100ths of sec)"); + + prop = RNA_def_property(srna, "pie_animation_timeout", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 0, 1000); + RNA_def_property_ui_text(prop, "Animation Timeout", + "Time needed to fully animate the pie to unfolded state (in 1/100ths of sec)"); + + prop = RNA_def_property(srna, "pie_menu_radius", PROP_INT, PROP_PIXEL); + RNA_def_property_range(prop, 0, 1000); + RNA_def_property_ui_text(prop, "Radius", "Pie menu size in pixels"); + + prop = RNA_def_property(srna, "pie_menu_threshold", PROP_INT, PROP_PIXEL); + RNA_def_property_range(prop, 0, 1000); + RNA_def_property_ui_text(prop, "Threshold", "Distance from center needed before a selection can be made"); + prop = RNA_def_property(srna, "use_quit_dialog", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_QUIT_PROMPT); RNA_def_property_ui_text(prop, "Prompt Quit", @@ -3569,7 +3614,9 @@ static void rna_def_userdef_edit(BlenderRNA *brna) static void rna_def_userdef_system(BlenderRNA *brna) { + FunctionRNA *func; PropertyRNA *prop; + PropertyRNA *parm; StructRNA *srna; static EnumPropertyItem gl_texture_clamp_items[] = { @@ -3689,6 +3736,13 @@ static void rna_def_userdef_system(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem gpu_select_method_items[] = { + {USER_SELECT_AUTO, "AUTO", 0, "Automatic", ""}, + {USER_SELECT_USE_SELECT_RENDERMODE, "GL_SELECT", 0, "OpenGL Select", ""}, + {USER_SELECT_USE_OCCLUSION_QUERY, "GL_QUERY", 0, "OpenGL Occlusion Queries", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "UserPreferencesSystem", NULL); RNA_def_struct_sdna(srna, "UserDef"); RNA_def_struct_nested(brna, srna, "UserPreferences"); @@ -3931,12 +3985,24 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_boolean_negative_sdna(prop, NULL, "text_render", USER_TEXT_DISABLE_AA); RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user interface text anti-aliased"); RNA_def_property_update(prop, 0, "rna_userdef_text_update"); - + + func = RNA_def_function(srna, "is_occlusion_query_supported", "rna_Scene_GPU_selection_supported"); + parm = RNA_def_boolean(func, "is_supported", 0, "Occlusion Query Support", + "Check if GPU supports Occlusion Queries"); + RNA_def_function_return(func, parm); + + prop = RNA_def_property(srna, "select_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "gpu_select_method"); + RNA_def_property_enum_items(prop, gpu_select_method_items); + RNA_def_property_ui_text(prop, "Selection Method", + "Use OpenGL occlusion queries or selection render mode to accelerate selection"); + /* Full scene anti-aliasing */ prop = RNA_def_property(srna, "multi_sample", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "ogl_multisamples"); RNA_def_property_enum_items(prop, multi_sample_levels); - RNA_def_property_ui_text(prop, "MultiSample", "Enable OpenGL multi-sampling, only for systems that support it, requires restart"); + RNA_def_property_ui_text(prop, "MultiSample", + "Enable OpenGL multi-sampling, only for systems that support it, requires restart"); prop = RNA_def_property(srna, "use_region_overlap", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag2", USER_REGION_OVERLAP); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 23b6d1e41ae..7513a687978 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -565,6 +565,24 @@ static int rna_Event_unicode_length(PointerRNA *ptr) } } +static float rna_Event_pressure_get(PointerRNA *ptr) +{ + wmEvent *event = ptr->data; + return WM_event_tablet_data(event, NULL, NULL); +} + +static int rna_Event_is_tablet_get(PointerRNA *ptr) +{ + wmEvent *event = ptr->data; + return WM_event_is_tablet(event); +} + +static void rna_Event_tilt_get(PointerRNA *ptr, float *values) +{ + wmEvent *event = ptr->data; + WM_event_tablet_data(event, NULL, values); +} + static PointerRNA rna_PopupMenu_layout_get(PointerRNA *ptr) { struct uiPopupMenu *pup = ptr->data; @@ -576,6 +594,17 @@ static PointerRNA rna_PopupMenu_layout_get(PointerRNA *ptr) return rptr; } +static PointerRNA rna_PieMenu_layout_get(PointerRNA *ptr) +{ + struct uiPieMenu *pie = ptr->data; + uiLayout *layout = uiPieMenuLayout(pie); + + PointerRNA rptr; + RNA_pointer_create(ptr->id.data, &RNA_UILayout, layout, &rptr); + + return rptr; +} + static void rna_Window_screen_set(PointerRNA *ptr, PointerRNA value) { wmWindow *win = (wmWindow *)ptr->data; @@ -587,7 +616,7 @@ static void rna_Window_screen_set(PointerRNA *ptr, PointerRNA value) win->newscreen = value.data; } -int rna_Window_screen_assign_poll(PointerRNA *UNUSED(ptr), PointerRNA value) +static int rna_Window_screen_assign_poll(PointerRNA *UNUSED(ptr), PointerRNA value) { bScreen *screen = (bScreen *)value.id.data; @@ -1608,6 +1637,21 @@ static void rna_def_event(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Mouse Previous Y Position", "The window relative vertical location of the mouse"); + prop = RNA_def_property(srna, "pressure", PROP_FLOAT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_float_funcs(prop, "rna_Event_pressure_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Tablet Pressure", "The pressure of the tablet or 1.0 if no tablet present"); + + prop = RNA_def_property(srna, "tilt", PROP_FLOAT, PROP_XYZ_LENGTH); + RNA_def_property_array(prop, 2); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_float_funcs(prop, "rna_Event_tilt_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Tablet Tilt", "The pressure of the tablet or zeroes if no tablet present"); + + prop = RNA_def_property(srna, "is_tablet", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_funcs(prop, "rna_Event_is_tablet_get", NULL); + RNA_def_property_ui_text(prop, "Tablet Pressure", "The pressure of the tablet or 1.0 if no tablet present"); /* modifiers */ prop = RNA_def_property(srna, "shift", PROP_BOOLEAN, PROP_NONE); @@ -1683,6 +1727,26 @@ static void rna_def_popupmenu(BlenderRNA *brna) RNA_define_verify_sdna(1); /* not in sdna */ } +static void rna_def_piemenu(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "UIPieMenu", NULL); + RNA_def_struct_ui_text(srna, "PieMenu", ""); + RNA_def_struct_sdna(srna, "uiPieMenu"); + + RNA_define_verify_sdna(0); /* not in sdna */ + + /* could wrap more, for now this is enough */ + prop = RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "UILayout"); + RNA_def_property_pointer_funcs(prop, "rna_PieMenu_layout_get", + NULL, NULL, NULL); + + RNA_define_verify_sdna(1); /* not in sdna */ +} + static void rna_def_window(BlenderRNA *brna) { StructRNA *srna; @@ -2045,6 +2109,7 @@ void RNA_def_wm(BlenderRNA *brna) rna_def_event(brna); rna_def_timer(brna); rna_def_popupmenu(brna); + rna_def_piemenu(brna); rna_def_window(brna); rna_def_windowmanager(brna); rna_def_keyconfig(brna); diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index 9b288903aa2..ad638f2187c 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -111,7 +111,7 @@ static void rna_event_timer_remove(struct wmWindowManager *wm, wmTimer *timer) } /* placeholder data for final implementation of a true progressbar */ -struct wmStaticProgress { +static struct wmStaticProgress { float min; float max; bool is_valid; @@ -310,6 +310,24 @@ static void rna_PupMenuEnd(bContext *C, PointerRNA *handle) uiPupMenuEnd(C, handle->data); } +/* pie menu wrapper */ +static PointerRNA rna_PieMenuBegin(bContext *C, const char *title, int icon, PointerRNA *event) +{ + PointerRNA r_ptr; + void *data; + + data = (void *)uiPieMenuBegin(C, title, icon, event->data); + + RNA_pointer_create(NULL, &RNA_UIPieMenu, data, &r_ptr); + + return r_ptr; +} + +static void rna_PieMenuEnd(bContext *C, PointerRNA *handle) +{ + uiPieMenuEnd(C, handle->data); +} + #else #define WM_GEN_INVOKE_EVENT (1 << 0) @@ -461,6 +479,26 @@ void RNA_api_wm(StructRNA *srna) RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "menu", "UIPopupMenu", "", ""); RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL); + + /* wrap uiPieMenuBegin */ + func = RNA_def_function(srna, "piemenu_begin__internal", "rna_PieMenuBegin"); + RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); + parm = RNA_def_string(func, "title", NULL, 0, "", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(parm, icon_items); + parm = RNA_def_pointer(func, "event", "Event", "", ""); + RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL); + /* return */ + parm = RNA_def_pointer(func, "menu_pie", "UIPieMenu", "", ""); + RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_function_return(func, parm); + + /* wrap uiPieMenuEnd */ + func = RNA_def_function(srna, "piemenu_end__internal", "rna_PieMenuEnd"); + RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); + parm = RNA_def_pointer(func, "menu", "UIPieMenu", "", ""); + RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL); } void RNA_api_operator(StructRNA *srna) diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 0a4a6140c02..2768d9412d7 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -22,7 +22,8 @@ * Ton Roosendaal, * Ben Batt, * Brecht Van Lommel, - * Campbell Barton + * Campbell Barton, + * Patrice Bertrand * * ***** END GPL LICENSE BLOCK ***** * @@ -30,16 +31,14 @@ /** \file blender/modifiers/intern/MOD_array.c * \ingroup modifiers + * + * Array modifier: duplicates the object multiple times along an axis. */ - -/* Array modifier: duplicates the object multiple times along an axis */ - #include "MEM_guardedalloc.h" #include "BLI_math.h" #include "BLI_utildefines.h" -#include "BLI_ghash.h" #include "DNA_curve_types.h" #include "DNA_meshdata_types.h" @@ -53,14 +52,8 @@ #include "MOD_util.h" -#include "bmesh.h" - #include "depsgraph_private.h" -#include <ctype.h> -#include <stdlib.h> -#include <string.h> - /* Due to cyclic dependencies it's possible that curve used for * deformation here is not evaluated at the time of evaluating * this modifier. @@ -140,7 +133,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, } } -static float vertarray_size(MVert *mvert, int numVerts, int axis) +static float vertarray_size(const MVert *mvert, int numVerts, int axis) { int i; float min_co, max_co; @@ -159,206 +152,303 @@ static float vertarray_size(MVert *mvert, int numVerts, int axis) return max_co - min_co; } -static int *find_doubles_index_map(BMesh *bm, BMOperator *dupe_op, - const ArrayModifierData *amd, - int *index_map_length) +BLI_INLINE float sum_v3(const float v[3]) { - BMOperator find_op; - BMOIter oiter; - BMVert *v, *v2; - BMElem *ele; - int *index_map, i; - - BMO_op_initf(bm, &find_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), - "find_doubles verts=%av dist=%f keep_verts=%s", - amd->merge_dist, dupe_op, "geom"); - - BMO_op_exec(bm, &find_op); - - i = 0; - BMO_ITER (ele, &oiter, dupe_op->slots_in, "geom", BM_ALL) { - BM_elem_index_set(ele, i); /* set_dirty */ - i++; - } - - BMO_ITER (ele, &oiter, dupe_op->slots_out, "geom.out", BM_ALL) { - BM_elem_index_set(ele, i); /* set_dirty */ - i++; - } - /* above loops over all, so set all to dirty, if this is somehow - * setting valid values, this line can be removed - campbell */ - bm->elem_index_dirty |= BM_ALL; + return v[0] + v[1] + v[2]; +} - (*index_map_length) = i; - index_map = MEM_callocN(sizeof(int) * (*index_map_length), "index_map"); +/* Structure used for sorting vertices, when processing doubles */ +typedef struct SortVertsElem { + int vertex_num; /* The original index of the vertex, prior to sorting */ + float co[3]; /* Its coordinates */ + float sum_co; /* sum_v3(co), just so we don't do the sum many times. */ +} SortVertsElem; - /*element type argument doesn't do anything here*/ - BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) { - v2 = BMO_iter_map_value_ptr(&oiter); - index_map[BM_elem_index_get(v)] = BM_elem_index_get(v2) + 1; - } +static int svert_sum_cmp(const void *e1, const void *e2) +{ + const SortVertsElem *sv1 = (SortVertsElem *)e1; + const SortVertsElem *sv2 = (SortVertsElem *)e2; - BMO_op_finish(bm, &find_op); + if (sv1->sum_co > sv2->sum_co) return 1; + else if (sv1->sum_co < sv2->sum_co) return -1; + else return 0; +} - return index_map; +static void svert_from_mvert(SortVertsElem *sv, const MVert *mv, const int i_begin, const int i_end) +{ + int i; + for (i = i_begin; i < i_end; i++, sv++, mv++) { + sv->vertex_num = i; + copy_v3_v3(sv->co, mv->co); + sv->sum_co = sum_v3(mv->co); + } } -/* Used for start/end cap. - * - * this function expects all existing vertices to be tagged, - * so we can know new verts are not tagged. - * - * All verts will be tagged on exit. +/** + * Take as inputs two sets of verts, to be processed for detection of doubles and mapping. + * Each set of verts is defined by its start within mverts array and its num_verts; + * It builds a mapping for all vertices within source, to vertices within target, or -1 if no double found + * The int doubles_map[num_verts_source] array must have been allocated by caller. */ -static void bm_merge_dm_transform(BMesh *bm, DerivedMesh *dm, float mat[4][4], - const ArrayModifierData *amd, - BMOperator *dupe_op, - BMOpSlot dupe_op_slot_args[BMO_OP_MAX_SLOTS], const char *dupe_slot_name, - BMOperator *weld_op) +static void dm_mvert_map_doubles( + int *doubles_map, + const MVert *mverts, + const int target_start, + const int target_num_verts, + const int source_start, + const int source_num_verts, + const float dist, + const bool with_follow) { - const bool is_input = (dupe_op->slots_in == dupe_op_slot_args); - BMVert *v, *v2, *v3; - BMIter iter; + const float dist3 = (M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */ + int i_source, i_target, i_target_low_bound, target_end, source_end; + SortVertsElem *sorted_verts_target, *sorted_verts_source; + SortVertsElem *sve_source, *sve_target, *sve_target_low_bound; + bool target_scan_completed; + + target_end = target_start + target_num_verts; + source_end = source_start + source_num_verts; + + /* build array of MVerts to be tested for merging */ + sorted_verts_target = MEM_mallocN(sizeof(SortVertsElem) * target_num_verts, __func__); + sorted_verts_source = MEM_mallocN(sizeof(SortVertsElem) * source_num_verts, __func__); + + /* Copy target vertices index and cos into SortVertsElem array */ + svert_from_mvert(sorted_verts_target, mverts + target_start, target_start, target_end); + + /* Copy source vertices index and cos into SortVertsElem array */ + svert_from_mvert(sorted_verts_source, mverts + source_start, source_start, source_end); + + /* sort arrays according to sum of vertex coordinates (sumco) */ + qsort(sorted_verts_target, target_num_verts, sizeof(SortVertsElem), svert_sum_cmp); + qsort(sorted_verts_source, source_num_verts, sizeof(SortVertsElem), svert_sum_cmp); + + sve_target_low_bound = sorted_verts_target; + i_target_low_bound = 0; + target_scan_completed = false; + + /* Scan source vertices, in SortVertsElem sorted array, */ + /* all the while maintaining the lower bound of possible doubles in target vertices */ + for (i_source = 0, sve_source = sorted_verts_source; + i_source < source_num_verts; + i_source++, sve_source++) + { + bool double_found; + float sve_source_sumco; - /* Add the DerivedMesh's elements to the BMesh. The pre-existing - * elements were already tagged, so the new elements can be - * identified by not having the BM_ELEM_TAG flag set. */ - DM_to_bmesh_ex(dm, bm, false); + /* If source has already been assigned to a target (in an earlier call, with other chunks) */ + if (doubles_map[sve_source->vertex_num] != -1) { + continue; + } - if (amd->flags & MOD_ARR_MERGE) { - /* if merging is enabled, find doubles */ - - BMOIter oiter; - BMOperator find_op; - BMOpSlot *slot_targetmap; - - BMO_op_initf(bm, &find_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), - is_input ? /* ugh */ - "find_doubles verts=%Hv dist=%f keep_verts=%s" : - "find_doubles verts=%Hv dist=%f keep_verts=%S", - BM_ELEM_TAG, amd->merge_dist, - dupe_op, dupe_slot_name); - - /* append the dupe's geom to the findop input verts */ - if (is_input) { - BMO_slot_buffer_append(&find_op, slots_in, "verts", - dupe_op, slots_in, dupe_slot_name); + /* If target fully scanned already, then all remaining source vertices cannot have a double */ + if (target_scan_completed) { + doubles_map[sve_source->vertex_num] = -1; + continue; } - else if (dupe_op->slots_out == dupe_op_slot_args) { - BMO_slot_buffer_append(&find_op, slots_in, "verts", - dupe_op, slots_out, dupe_slot_name); + + sve_source_sumco = sum_v3(sve_source->co); + + /* Skip all target vertices that are more than dist3 lower in terms of sumco */ + /* and advance the overall lower bound, applicable to all remaining vertices as well. */ + while ((i_target_low_bound < target_num_verts) && + (sve_target_low_bound->sum_co < sve_source_sumco - dist3)) + { + i_target_low_bound++; + sve_target_low_bound++; } - else { - BLI_assert(0); + /* If end of target list reached, then no more possible doubles */ + if (i_target_low_bound >= target_num_verts) { + doubles_map[sve_source->vertex_num] = -1; + target_scan_completed = true; + continue; } - - /* transform and tag verts */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(v, BM_ELEM_TAG)) { - mul_m4_v3(mat, v->co); - BM_elem_flag_enable(v, BM_ELEM_TAG); + /* Test target candidates starting at the low bound of possible doubles, ordered in terms of sumco */ + i_target = i_target_low_bound; + sve_target = sve_target_low_bound; + + /* i_target will scan vertices in the [v_source_sumco - dist3; v_source_sumco + dist3] range */ + + double_found = false; + while ((i_target < target_num_verts) && + (sve_target->sum_co <= sve_source_sumco + dist3)) + { + /* Testing distance for candidate double in target */ + /* v_target is within dist3 of v_source in terms of sumco; check real distance */ + if (compare_len_v3v3(sve_source->co, sve_target->co, dist)) { + /* Double found */ + /* If double target is itself already mapped to other vertex, + * behavior depends on with_follow option */ + int target_vertex = sve_target->vertex_num; + if (doubles_map[target_vertex] != -1) { + if (with_follow) { /* with_follow option: map to initial target */ + target_vertex = doubles_map[target_vertex]; + } + else { + /* not with_follow: if target is mapped, then we do not map source, and stop searching */ + break; + } + } + doubles_map[sve_source->vertex_num] = target_vertex; + double_found = true; + break; } + i_target++; + sve_target++; + } + /* End of candidate scan: if none found then no doubles */ + if (!double_found) { + doubles_map[sve_source->vertex_num] = -1; } + } - BMO_op_exec(bm, &find_op); + MEM_freeN(sorted_verts_source); + MEM_freeN(sorted_verts_target); +} - slot_targetmap = BMO_slot_get(weld_op->slots_in, "targetmap"); - /* add new merge targets to weld operator */ - BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) { - 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))) { - v2 = v3; - } - BMO_slot_map_elem_insert(weld_op, slot_targetmap, v, v2); - } +static void dm_merge_transform( + DerivedMesh *result, DerivedMesh *cap_dm, float cap_offset[4][4], + unsigned int cap_verts_index, unsigned int cap_edges_index, int cap_loops_index, int cap_polys_index, + int cap_nverts, int cap_nedges, int cap_nloops, int cap_npolys) +{ + int *index_orig; + int i; + MVert *mv; + MEdge *me; + MLoop *ml; + MPoly *mp; + + /* needed for subsurf so arrays are allocated */ + cap_dm->getVertArray(cap_dm); + cap_dm->getEdgeArray(cap_dm); + cap_dm->getNumLoops(cap_dm); + cap_dm->getNumPolys(cap_dm); + + DM_copy_vert_data(cap_dm, result, 0, cap_verts_index, cap_nverts); + DM_copy_edge_data(cap_dm, result, 0, cap_edges_index, cap_nedges); + DM_copy_loop_data(cap_dm, result, 0, cap_loops_index, cap_nloops); + DM_copy_poly_data(cap_dm, result, 0, cap_polys_index, cap_npolys); + + mv = CDDM_get_verts(result) + cap_verts_index; + + for (i = 0; i < cap_nverts; i++, mv++) { + mul_m4_v3(cap_offset, mv->co); + /* Reset MVert flags for caps */ + mv->flag = mv->bweight = 0; + } - BMO_op_finish(bm, &find_op); + /* adjust cap edge vertex indices */ + me = CDDM_get_edges(result) + cap_edges_index; + for (i = 0; i < cap_nedges; i++, me++) { + me->v1 += cap_verts_index; + me->v2 += cap_verts_index; } - else { - /* transform and tag verts */ - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(v, BM_ELEM_TAG)) { - mul_m4_v3(mat, v->co); - BM_elem_flag_enable(v, BM_ELEM_TAG); - } - } + + /* adjust cap poly loopstart indices */ + mp = CDDM_get_polys(result) + cap_polys_index; + for (i = 0; i < cap_npolys; i++, mp++) { + mp->loopstart += cap_loops_index; } -} -static void merge_first_last(BMesh *bm, - const ArrayModifierData *amd, - BMOperator *dupe_first, - BMOperator *dupe_last, - BMOperator *weld_op) -{ - BMOperator find_op; - BMOIter oiter; - BMVert *v, *v2; - BMOpSlot *slot_targetmap; - - BMO_op_initf(bm, &find_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), - "find_doubles verts=%s dist=%f keep_verts=%s", - dupe_first, "geom", amd->merge_dist, - dupe_first, "geom"); - - /* append the last dupe's geom to the findop input verts */ - BMO_slot_buffer_append(&find_op, slots_in, "verts", - dupe_last, slots_out, "geom.out"); - - BMO_op_exec(bm, &find_op); - - /* 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) { - 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); - } + /* adjust cap loop vertex and edge indices */ + ml = CDDM_get_loops(result) + cap_loops_index; + for (i = 0; i < cap_nloops; i++, ml++) { + ml->v += cap_verts_index; + ml->e += cap_edges_index; } - BMO_op_finish(bm, &find_op); + /* set origindex */ + index_orig = result->getVertDataArray(result, CD_ORIGINDEX); + if (index_orig) { + fill_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE); + } + + index_orig = result->getEdgeDataArray(result, CD_ORIGINDEX); + if (index_orig) { + fill_vn_i(index_orig + cap_edges_index, cap_nedges, ORIGINDEX_NONE); + } + + index_orig = result->getPolyDataArray(result, CD_ORIGINDEX); + if (index_orig) { + fill_vn_i(index_orig + cap_polys_index, cap_npolys, ORIGINDEX_NONE); + } + + index_orig = result->getLoopDataArray(result, CD_ORIGINDEX); + if (index_orig) { + fill_vn_i(index_orig + cap_loops_index, cap_nloops, ORIGINDEX_NONE); + } } -static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, - Scene *scene, Object *ob, DerivedMesh *dm, - ModifierApplyFlag flag) +static DerivedMesh *arrayModifier_doArray( + ArrayModifierData *amd, + Scene *scene, Object *ob, DerivedMesh *dm, + ModifierApplyFlag flag) { - DerivedMesh *result; - BMesh *bm = DM_to_bmesh(dm, false); - BMOperator first_dupe_op, dupe_op, old_dupe_op, weld_op; - BMVert **first_geom = NULL; - int i, j; - int index_len = -1; /* initialize to an invalid value */ + const float eps = 1e-6f; + const MVert *src_mvert; + MVert *mv, *mv_prev, *result_dm_verts; + + MEdge *me; + MLoop *ml; + MPoly *mp; + int i, j, c, count; + float length = amd->length; /* offset matrix */ float offset[4][4]; + float scale[3]; + bool offset_has_scale; + float current_offset[4][4]; float final_offset[4][4]; - float length = amd->length; - int count = amd->count, maxVerts; - int *indexMap = NULL; - DerivedMesh *start_cap = NULL, *end_cap = NULL; - MVert *src_mvert; - 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) - start_cap = get_dm_for_modifier(amd->start_cap, flag); - if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH) - end_cap = get_dm_for_modifier(amd->end_cap, flag); + int *full_doubles_map = NULL; + int tot_doubles; + + int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0; + int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0; + int result_nverts = 0, result_nedges = 0, result_npolys = 0, result_nloops = 0; + int chunk_nverts, chunk_nedges, chunk_nloops, chunk_npolys; + int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts; + + DerivedMesh *result, *start_cap_dm = NULL, *end_cap_dm = NULL; + + chunk_nverts = dm->getNumVerts(dm); + chunk_nedges = dm->getNumEdges(dm); + chunk_nloops = dm->getNumLoops(dm); + chunk_npolys = dm->getNumPolys(dm); + + count = amd->count; + + if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH) { + start_cap_dm = get_dm_for_modifier(amd->start_cap, flag); + if (start_cap_dm) { + start_cap_nverts = start_cap_dm->getNumVerts(start_cap_dm); + start_cap_nedges = start_cap_dm->getNumEdges(start_cap_dm); + start_cap_nloops = start_cap_dm->getNumLoops(start_cap_dm); + start_cap_npolys = start_cap_dm->getNumPolys(start_cap_dm); + } + } + if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH) { + end_cap_dm = get_dm_for_modifier(amd->end_cap, flag); + if (end_cap_dm) { + end_cap_nverts = end_cap_dm->getNumVerts(end_cap_dm); + end_cap_nedges = end_cap_dm->getNumEdges(end_cap_dm); + end_cap_nloops = end_cap_dm->getNumLoops(end_cap_dm); + end_cap_npolys = end_cap_dm->getNumPolys(end_cap_dm); + } + } - unit_m4(offset); + /* Build up offset array, cumulating all settings options */ + unit_m4(offset); src_mvert = dm->getVertArray(dm); - maxVerts = dm->getNumVerts(dm); if (amd->offset_type & MOD_ARR_OFF_CONST) add_v3_v3v3(offset[3], offset[3], amd->offset); + if (amd->offset_type & MOD_ARR_OFF_RELATIVE) { for (j = 0; j < 3; j++) - offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, maxVerts, j); + offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, chunk_nverts, j); } if ((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) { @@ -370,12 +460,15 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, else unit_m4(obinv); - mul_serie_m4(result_mat, offset, - obinv, amd->offset_ob->obmat, - NULL, NULL, NULL, NULL, NULL); + mul_m4_series(result_mat, offset, + obinv, amd->offset_ob->obmat); copy_m4_m4(offset, result_mat); } + /* Check if there is some scaling. If scaling, then we will not translate mapping */ + mat4_to_size(scale, offset); + offset_has_scale = !is_one_v3(scale); + if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) { Curve *cu = amd->curve_ob->data; if (cu) { @@ -397,195 +490,236 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) { float dist = len_v3(offset[3]); - if (dist > 1e-6f) + if (dist > eps) { /* this gives length = first copy start to last copy end * add a tiny offset for floating point rounding errors */ - count = (length + 1e-6f) / dist; - else + count = (length + eps) / dist; + } + else { /* if the offset has no translation, just make one copy */ count = 1; + } } if (count < 1) count = 1; - /* calculate the offset matrix of the final copy (for merging) */ - unit_m4(final_offset); + /* The number of verts, edges, loops, polys, before eventually merging doubles */ + result_nverts = chunk_nverts * count + start_cap_nverts + end_cap_nverts; + result_nedges = chunk_nedges * count + start_cap_nedges + end_cap_nedges; + result_nloops = chunk_nloops * count + start_cap_nloops + end_cap_nloops; + result_npolys = chunk_npolys * count + start_cap_npolys + end_cap_npolys; + + /* Initialize a result dm */ + result = CDDM_from_template(dm, result_nverts, result_nedges, 0, result_nloops, result_npolys); + result_dm_verts = CDDM_get_verts(result); - for (j = 0; j < count - 1; j++) { - float tmp_mat[4][4]; - mul_m4_m4m4(tmp_mat, offset, final_offset); - copy_m4_m4(final_offset, tmp_mat); + if (amd->flags & MOD_ARR_MERGE) { + /* Will need full_doubles_map for handling merge */ + full_doubles_map = MEM_mallocN(sizeof(int) * result_nverts, "mod array doubles map"); + fill_vn_i(full_doubles_map, result_nverts, -1); } - /* BMESH_TODO: bumping up the stack level avoids computing the normals - * after every top-level operator execution (and this modifier has the - * potential to execute a *lot* of top-level BMOps. There should be a - * cleaner way to do this. One possibility: a "mirror" BMOp would - * certainly help by compressing it all into one top-level BMOp that - * executes a lot of second-level BMOps. */ - BM_mesh_elem_toolflags_ensure(bm); - BMO_push(bm, NULL); - bmesh_edit_begin(bm, 0); + /* copy customdata to original geometry */ + DM_copy_vert_data(dm, result, 0, 0, chunk_nverts); + DM_copy_edge_data(dm, result, 0, 0, chunk_nedges); + DM_copy_loop_data(dm, result, 0, 0, chunk_nloops); + DM_copy_poly_data(dm, result, 0, 0, chunk_npolys); - if (amd->flags & MOD_ARR_MERGE) { - BMO_op_init(bm, &weld_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), - "weld_verts"); + /* subsurf for eg wont have mesh data in the + * now add mvert/medge/mface layers */ - slot_targetmap = BMO_slot_get(weld_op.slots_in, "targetmap"); + if (!CustomData_has_layer(&dm->vertData, CD_MVERT)) { + dm->copyVertArray(dm, result_dm_verts); + } + if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE)) { + dm->copyEdgeArray(dm, CDDM_get_edges(result)); + } + if (!CustomData_has_layer(&dm->polyData, CD_MPOLY)) { + dm->copyLoopArray(dm, CDDM_get_loops(result)); + dm->copyPolyArray(dm, CDDM_get_polys(result)); } - BMO_op_initf(bm, &dupe_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), - "duplicate geom=%avef"); - first_dupe_op = dupe_op; - - for (j = 0; j < count - 1; j++) { - BMVert *v, *v2, *v3; - BMOpSlot *geom_slot; - BMOpSlot *geom_out_slot; - BMOIter oiter; + /* Remember first chunk, in case of cap merge */ + first_chunk_start = 0; + first_chunk_nverts = chunk_nverts; - if (j != 0) { - BMO_op_initf(bm, &dupe_op, - (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), - "duplicate geom=%S", &old_dupe_op, "geom.out"); - } - BMO_op_exec(bm, &dupe_op); - - geom_slot = BMO_slot_get(dupe_op.slots_in, "geom"); - geom_out_slot = BMO_slot_get(dupe_op.slots_out, "geom.out"); - - if ((amd->flags & MOD_ARR_MERGEFINAL) && j == 0) { - int first_geom_bytes = sizeof(BMVert *) * geom_slot->len; - - /* make a copy of the initial geometry ordering so the - * last duplicate can be merged into it */ - first_geom = MEM_mallocN(first_geom_bytes, "first_geom"); - memcpy(first_geom, geom_slot->data.buf, first_geom_bytes); - } + unit_m4(current_offset); + for (c = 1; c < count; c++) { + /* copy customdata to new geometry */ + DM_copy_vert_data(result, result, 0, c * chunk_nverts, chunk_nverts); + DM_copy_edge_data(result, result, 0, c * chunk_nedges, chunk_nedges); + DM_copy_loop_data(result, result, 0, c * chunk_nloops, chunk_nloops); + DM_copy_poly_data(result, result, 0, c * chunk_npolys, chunk_npolys); - /* apply transformation matrix */ - BMO_ITER (v, &oiter, dupe_op.slots_out, "geom.out", BM_VERT) { - mul_m4_v3(offset, v->co); - } + mv_prev = result_dm_verts; + mv = mv_prev + c * chunk_nverts; - if (amd->flags & MOD_ARR_MERGE) { - /*calculate merge mapping*/ - if (j == 0) { - indexMap = find_doubles_index_map(bm, &dupe_op, - amd, &index_len); - } + /* recalculate cumulative offset here */ + mul_m4_m4m4(current_offset, current_offset, offset); -#define _E(s, i) ((BMVert **)(s)->data.buf)[i] + /* apply offset to all new verts */ + for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) { + mul_m4_v3(current_offset, mv->co); + } - /* ensure this is set */ - BLI_assert(index_len != -1); + /* adjust edge vertex indices */ + me = CDDM_get_edges(result) + c * chunk_nedges; + for (i = 0; i < chunk_nedges; i++, me++) { + me->v1 += c * chunk_nverts; + me->v2 += c * chunk_nverts; + } - for (i = 0; i < index_len; i++) { - if (!indexMap[i]) continue; + mp = CDDM_get_polys(result) + c * chunk_npolys; + for (i = 0; i < chunk_npolys; i++, mp++) { + mp->loopstart += c * chunk_nloops; + } - /* merge v (from 'geom.out') into v2 (from old 'geom') */ - v = _E(geom_out_slot, i - geom_slot->len); - v2 = _E(geom_slot, indexMap[i] - 1); + /* adjust loop vertex and edge indices */ + ml = CDDM_get_loops(result) + c * chunk_nloops; + for (i = 0; i < chunk_nloops; i++, ml++) { + ml->v += c * chunk_nverts; + ml->e += c * chunk_nedges; + } - /* check in case the target vertex (v2) is already marked - * for merging */ - while ((v3 = BMO_slot_map_elem_get(slot_targetmap, v2))) { - v2 = v3; + /* Handle merge between chunk n and n-1 */ + if ((amd->flags & MOD_ARR_MERGE) && (c >= 1)) { + if (!offset_has_scale && (c >= 2)) { + /* Mapping chunk 3 to chunk 2 is a translation of mapping 2 to 1 + * ... that is except if scaling makes the distance grow */ + int k; + int this_chunk_index = c * chunk_nverts; + int prev_chunk_index = (c - 1) * chunk_nverts; + for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) { + int target = full_doubles_map[prev_chunk_index]; + if (target != -1) { + target += chunk_nverts; /* translate mapping */ + /* The rule here is to not follow mapping to chunk N-2, which could be too far + * so if target vertex was itself mapped, then this vertex is not mapped */ + if (full_doubles_map[target] != -1) { + target = -1; + } + } + full_doubles_map[this_chunk_index] = target; } - - BMO_slot_map_elem_insert(&weld_op, slot_targetmap, v, v2); } - -#undef _E + else { + dm_mvert_map_doubles( + full_doubles_map, + result_dm_verts, + (c - 1) * chunk_nverts, + chunk_nverts, + c * chunk_nverts, + chunk_nverts, + amd->merge_dist, + false); + } } - - /* already copied earlier, but after executation more slot - * memory may be allocated */ - if (j == 0) - first_dupe_op = dupe_op; - - if (j >= 2) - BMO_op_finish(bm, &old_dupe_op); - old_dupe_op = dupe_op; } + last_chunk_start = (count - 1) * chunk_nverts; + last_chunk_nverts = chunk_nverts; + + copy_m4_m4(final_offset, current_offset); + if ((amd->flags & MOD_ARR_MERGE) && (amd->flags & MOD_ARR_MERGEFINAL) && (count > 1)) { - /* Merge first and last copies. Note that we can't use the - * indexMap for this because (unless the array is forming a - * loop) the offset between first and last is different from - * dupe X to dupe X+1. */ - - merge_first_last(bm, amd, &first_dupe_op, &dupe_op, &weld_op); + /* Merge first and last copies */ + dm_mvert_map_doubles( + full_doubles_map, + result_dm_verts, + last_chunk_start, + last_chunk_nverts, + first_chunk_start, + first_chunk_nverts, + amd->merge_dist, + false); } /* start capping */ - if (start_cap || end_cap) { - BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false); - - if (start_cap) { - float startoffset[4][4]; - invert_m4_m4(startoffset, offset); - bm_merge_dm_transform(bm, start_cap, startoffset, amd, - &first_dupe_op, first_dupe_op.slots_in, "geom", &weld_op); + if (start_cap_dm) { + float start_offset[4][4]; + int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts; + invert_m4_m4(start_offset, offset); + dm_merge_transform( + result, start_cap_dm, start_offset, + result_nverts - start_cap_nverts - end_cap_nverts, + result_nedges - start_cap_nedges - end_cap_nedges, + result_nloops - start_cap_nloops - end_cap_nloops, + result_npolys - start_cap_npolys - end_cap_npolys, + start_cap_nverts, start_cap_nedges, start_cap_nloops, start_cap_npolys); + /* Identify doubles with first chunk */ + if (amd->flags & MOD_ARR_MERGE) { + dm_mvert_map_doubles( + full_doubles_map, + result_dm_verts, + first_chunk_start, + first_chunk_nverts, + start_cap_start, + start_cap_nverts, + amd->merge_dist, + false); } + } - if (end_cap) { - float endoffset[4][4]; - mul_m4_m4m4(endoffset, offset, final_offset); - bm_merge_dm_transform(bm, end_cap, endoffset, amd, - &dupe_op, (count == 1) ? dupe_op.slots_in : dupe_op.slots_out, - (count == 1) ? "geom" : "geom.out", &weld_op); + if (end_cap_dm) { + float end_offset[4][4]; + int end_cap_start = result_nverts - end_cap_nverts; + mul_m4_m4m4(end_offset, current_offset, offset); + dm_merge_transform( + result, end_cap_dm, end_offset, + result_nverts - end_cap_nverts, + result_nedges - end_cap_nedges, + result_nloops - end_cap_nloops, + result_npolys - end_cap_npolys, + end_cap_nverts, end_cap_nedges, end_cap_nloops, end_cap_npolys); + /* Identify doubles with last chunk */ + if (amd->flags & MOD_ARR_MERGE) { + dm_mvert_map_doubles( + full_doubles_map, + result_dm_verts, + last_chunk_start, + last_chunk_nverts, + end_cap_start, + end_cap_nverts, + amd->merge_dist, + false); } } /* done capping */ - /* free remaining dupe operators */ - BMO_op_finish(bm, &first_dupe_op); - if (count > 2) - BMO_op_finish(bm, &dupe_op); - - /* run merge operator */ - if (amd->flags & MOD_ARR_MERGE) { - BMO_op_exec(bm, &weld_op); - BMO_op_finish(bm, &weld_op); - } - - /* Bump the stack level back down to match the adjustment up above */ - BMO_pop(bm); - - result = CDDM_from_bmesh(bm, false); - - if ((dm->dirty & DM_DIRTY_NORMALS) || - ((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob))) - { - /* Update normals in case offset object has rotation. */ + /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new dm! + * TODO: we may need to set other dirty flags as well? + */ + if ((dm->dirty & DM_DIRTY_NORMALS) || full_doubles_map) { result->dirty |= DM_DIRTY_NORMALS; } - BM_mesh_free(bm); - - if (indexMap) - MEM_freeN(indexMap); - if (first_geom) - MEM_freeN(first_geom); - + /* Handle merging */ + tot_doubles = 0; + if (full_doubles_map) { + for (i = 0; i < result_nverts; i++) { + if (full_doubles_map[i] != -1) { + tot_doubles++; + } + } + if (tot_doubles > 0) { + result = CDDM_merge_verts(result, full_doubles_map, tot_doubles, CDDM_MERGE_VERTS_DUMP_IF_EQUAL); + } + MEM_freeN(full_doubles_map); + } return result; } + static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag flag) { - DerivedMesh *result; ArrayModifierData *amd = (ArrayModifierData *) md; - - result = arrayModifier_doArray(amd, md->scene, ob, dm, flag); - - return result; + return arrayModifier_doArray(amd, md->scene, ob, dm, flag); } diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index fc65990df20..2de3220e683 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -57,6 +57,7 @@ static void initData(ModifierData *md) bmd->val_flags = MOD_BEVEL_AMT_OFFSET; bmd->lim_flags = 0; bmd->e_flags = 0; + bmd->mat = -1; bmd->profile = 0.5f; bmd->bevel_angle = DEG2RADF(30.0f); bmd->defgrp_name[0] = '\0'; @@ -73,6 +74,7 @@ static void copyData(ModifierData *md, ModifierData *target) tbmd->val_flags = bmd->val_flags; tbmd->lim_flags = bmd->lim_flags; tbmd->e_flags = bmd->e_flags; + tbmd->mat = bmd->mat; tbmd->profile = bmd->profile; tbmd->bevel_angle = bmd->bevel_angle; BLI_strncpy(tbmd->defgrp_name, bmd->defgrp_name, sizeof(tbmd->defgrp_name)); @@ -109,6 +111,7 @@ static DerivedMesh *applyModifier(ModifierData *md, struct Object *ob, const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0; const bool do_clamp = !(bmd->flags & MOD_BEVEL_OVERLAP_OK); const int offset_type = bmd->val_flags; + const int mat = CLAMPIS(bmd->mat, -1, ob->totcol - 1); bm = DM_to_bmesh(dm, true); if ((bmd->lim_flags & MOD_BEVEL_VGROUP) && bmd->defgrp_name[0]) @@ -165,7 +168,7 @@ static DerivedMesh *applyModifier(ModifierData *md, struct Object *ob, BM_mesh_bevel(bm, bmd->value, offset_type, bmd->res, bmd->profile, vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp, - dvert, vgroup); + dvert, vgroup, mat); result = CDDM_from_bmesh(bm, true); diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index ec077631c85..c4654287cfc 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -151,8 +151,8 @@ static void sphere_do( * we use its location, transformed to ob's local space */ if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { - invert_m4_m4(ctrl_ob->imat, ctrl_ob->obmat); - mul_m4_m4m4(mat, ctrl_ob->imat, ob->obmat); + invert_m4_m4(imat, ctrl_ob->obmat); + mul_m4_m4m4(mat, imat, ob->obmat); invert_m4_m4(imat, mat); } @@ -275,8 +275,8 @@ static void cuboid_do( if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { - invert_m4_m4(ctrl_ob->imat, ctrl_ob->obmat); - mul_m4_m4m4(mat, ctrl_ob->imat, ob->obmat); + invert_m4_m4(imat, ctrl_ob->obmat); + mul_m4_m4m4(mat, imat, ob->obmat); invert_m4_m4(imat, mat); } diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index c89bc8c1d41..f6d7c03df32 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -156,8 +156,7 @@ static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm, copy_m4_m4(dmat, hmd->object->obmat); } invert_m4_m4(ob->imat, ob->obmat); - mul_serie_m4(mat, ob->imat, dmat, hmd->parentinv, - NULL, NULL, NULL, NULL, NULL); + mul_m4_series(mat, ob->imat, dmat, hmd->parentinv); modifier_get_vgroup(ob, dm, hmd->name, &dvert, &defgrp_index); max_dvert = (dvert) ? numVerts : 0; diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c index 7f21376ef48..838336a8f8a 100644 --- a/source/blender/modifiers/intern/MOD_mask.c +++ b/source/blender/modifiers/intern/MOD_mask.c @@ -153,7 +153,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, const int defbase_tot = BLI_countlist(&ob->defbase); /* check that there is armature object with bones to use, otherwise return original mesh */ - if (ELEM3(NULL, oba, oba->pose, ob->defbase.first)) + if (ELEM(NULL, oba, oba->pose, ob->defbase.first)) return dm; /* determine whether each vertexgroup is associated with a selected bone or not diff --git a/source/blender/modifiers/intern/MOD_meshcache_mdd.c b/source/blender/modifiers/intern/MOD_meshcache_mdd.c index 0cbf07ca907..90fc750de3b 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_mdd.c +++ b/source/blender/modifiers/intern/MOD_meshcache_mdd.c @@ -30,9 +30,11 @@ #include "BLI_sys_types.h" #include "BLI_utildefines.h" -#include "BLI_endian_switch.h" #include "BLI_fileops.h" #include "BLI_math.h" +#ifdef __LITTLE_ENDIAN__ +# include "BLI_endian_switch.h" +#endif #include "MOD_meshcache_util.h" /* own include */ diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c index ac0363f8673..3ef0ee54886 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c +++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c @@ -32,6 +32,9 @@ #include "BLI_utildefines.h" #include "BLI_fileops.h" #include "BLI_math.h" +#ifdef __BIG_ENDIAN__ +# include "BLI_endian_switch.h" +#endif #include "MOD_meshcache_util.h" /* own include */ diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index 5cece9d349f..5de4a76dcbe 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -290,7 +290,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, /* slow - so only call if one or more merge verts are found, * users may leave this on and not realize there is nothing to merge - campbell */ if (tot_vtargetmap) { - result = CDDM_merge_verts(result, vtargetmap, tot_vtargetmap); + result = CDDM_merge_verts(result, vtargetmap, tot_vtargetmap, CDDM_MERGE_VERTS_DUMP_IF_MAPPED); } MEM_freeN(vtargetmap); } diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index ff7cc01232b..5900baaf537 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -362,7 +362,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) { for (i = 0, mv_orig = mvert_orig; i < totvert; i++, mv_orig++) { - const float v = dist_squared_to_plane_v3(mv_orig->co, uv_axis_plane); + const float v = dist_signed_squared_to_plane_v3(mv_orig->co, uv_axis_plane); uv_v_minmax[0] = min_ff(v, uv_v_minmax[0]); uv_v_minmax[1] = max_ff(v, uv_v_minmax[1]); } @@ -897,8 +897,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, } if (has_mloop_orig == false && mloopuv_layers_tot) { - uv_v_offset_a = dist_to_plane_v3(mvert_new[medge_new[i].v1].co, uv_axis_plane); - uv_v_offset_b = dist_to_plane_v3(mvert_new[medge_new[i].v2].co, uv_axis_plane); + uv_v_offset_a = dist_signed_to_plane_v3(mvert_new[medge_new[i].v1].co, uv_axis_plane); + uv_v_offset_b = dist_signed_to_plane_v3(mvert_new[medge_new[i].v2].co, uv_axis_plane); if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) { uv_v_offset_a = (uv_v_offset_a - uv_v_minmax[0]) * uv_v_range_inv; diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c index eebb687aa8d..229f4911ab4 100644 --- a/source/blender/modifiers/intern/MOD_shrinkwrap.c +++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c @@ -37,6 +37,7 @@ #include "DNA_object_types.h" +#include "BLI_math.h" #include "BLI_string.h" #include "BLI_utildefines.h" diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c index ccba2097264..3314196b776 100644 --- a/source/blender/modifiers/intern/MOD_simpledeform.c +++ b/source/blender/modifiers/intern/MOD_simpledeform.c @@ -42,7 +42,6 @@ #include "BKE_cdderivedmesh.h" #include "BKE_modifier.h" #include "BKE_deform.h" -#include "BKE_shrinkwrap.h" #include "depsgraph_private.h" @@ -166,7 +165,7 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object /* Calculate matrixs do convert between coordinate spaces */ if (smd->origin) { transf = &tmp_transf; - space_transform_from_matrixs(transf, ob->obmat, smd->origin->obmat); + BLI_SPACE_TRANSFORM_SETUP(transf, ob, smd->origin); } /* Setup vars, @@ -182,7 +181,9 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object float tmp[3]; copy_v3_v3(tmp, vertexCos[i]); - if (transf) space_transform_apply(transf, tmp); + if (transf) { + BLI_space_transform_apply(transf, tmp); + } lower = min_ff(lower, tmp[limit_axis]); upper = max_ff(upper, tmp[limit_axis]); @@ -220,7 +221,7 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object float co[3], dcut[3] = {0.0f, 0.0f, 0.0f}; if (transf) { - space_transform_apply(transf, vertexCos[i]); + BLI_space_transform_apply(transf, vertexCos[i]); } copy_v3_v3(co, vertexCos[i]); @@ -236,7 +237,7 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight); /* Use vertex weight has coef of linear interpolation */ if (transf) { - space_transform_invert(transf, vertexCos[i]); + BLI_space_transform_invert(transf, vertexCos[i]); } } } diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index 95b0c37933c..813ef285058 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -20,6 +20,7 @@ * * Contributor(s): Campbell Barton * Shinsuke Irie + * Martin Felke * * ***** END GPL LICENSE BLOCK ***** * @@ -208,7 +209,6 @@ static DerivedMesh *applyModifier( DerivedMesh *dm, ModifierApplyFlag UNUSED(flag)) { - unsigned int i; DerivedMesh *result; const SolidifyModifierData *smd = (SolidifyModifierData *) md; @@ -220,7 +220,7 @@ static DerivedMesh *applyModifier( const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm); const unsigned int numFaces = (unsigned int)dm->getNumPolys(dm); const unsigned int numLoops = (unsigned int)dm->getNumLoops(dm); - unsigned int newLoops = 0, newFaces = 0, newEdges = 0; + unsigned int newLoops = 0, newFaces = 0, newEdges = 0, newVerts = 0; /* only use material offsets if we have 2 or more materials */ const short mat_nr_max = ob->totcol > 1 ? ob->totcol - 1 : 0; @@ -251,12 +251,16 @@ static DerivedMesh *applyModifier( const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg; const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0; const bool do_clamp = (smd->offset_clamp != 0.0f); + const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == 0; /* weights */ - MDeformVert *dvert, *dv = NULL; + MDeformVert *dvert; const int defgrp_invert = ((smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0); int defgrp_index; + /* array size is doubled in case of using a shell */ + const unsigned int stride = do_shell ? 2 : 1; + modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index); orig_mvert = dm->getVertArray(dm); @@ -280,6 +284,7 @@ static DerivedMesh *applyModifier( if (smd->flag & MOD_SOLIDIFY_RIM) { BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__); unsigned int eidx; + unsigned int i; #define INVALID_UNUSED ((unsigned int)-1) #define INVALID_PAIR ((unsigned int)-2) @@ -334,15 +339,15 @@ static DerivedMesh *applyModifier( } } -#undef INVALID_UNUSED -#undef INVALID_PAIR - for (i = 0; i < numVerts; i++) { if (BLI_BITMAP_TEST(orig_mvert_tag, i)) { old_vert_arr[i] = STACK_SIZE(new_vert_arr); STACK_PUSH(new_vert_arr, i); newEdges++; } + else { + old_vert_arr[i] = INVALID_UNUSED; + } } MEM_freeN(orig_mvert_tag); @@ -353,64 +358,126 @@ static DerivedMesh *applyModifier( dm_calc_normal(dm, face_nors, vert_nors); } + newVerts = do_shell ? 0 : newEdges; + result = CDDM_from_template(dm, - (int)(numVerts * 2), - (int)((numEdges * 2) + newEdges), 0, - (int)((numLoops * 2) + newLoops), - (int)((numFaces * 2) + newFaces)); + (int)((numVerts * stride) + newVerts), + (int)((numEdges * stride) + newEdges + newVerts), 0, + (int)((numLoops * stride) + newLoops), + (int)((numFaces * stride) + newFaces)); mpoly = CDDM_get_polys(result); mloop = CDDM_get_loops(result); medge = CDDM_get_edges(result); mvert = CDDM_get_verts(result); - DM_copy_edge_data(dm, result, 0, 0, (int)numEdges); - DM_copy_edge_data(dm, result, 0, (int)numEdges, (int)numEdges); + if (do_shell) { + DM_copy_vert_data(dm, result, 0, 0, (int)numVerts); + DM_copy_vert_data(dm, result, 0, (int)numVerts, (int)numVerts); - DM_copy_vert_data(dm, result, 0, 0, (int)numVerts); - DM_copy_vert_data(dm, result, 0, (int)numVerts, (int)numVerts); + DM_copy_edge_data(dm, result, 0, 0, (int)numEdges); + DM_copy_edge_data(dm, result, 0, (int)numEdges, (int)numEdges); - DM_copy_loop_data(dm, result, 0, 0, (int)numLoops); - DM_copy_loop_data(dm, result, 0, (int)numLoops, (int)numLoops); + DM_copy_loop_data(dm, result, 0, 0, (int)numLoops); + DM_copy_loop_data(dm, result, 0, (int)numLoops, (int)numLoops); - DM_copy_poly_data(dm, result, 0, 0, (int)numFaces); - DM_copy_poly_data(dm, result, 0, (int)numFaces, (int)numFaces); - - /* flip normals */ - mp = mpoly + numFaces; - for (i = 0; i < dm->numPolyData; i++, mp++) { - MLoop *ml2; - unsigned int e; - int j; - - ml2 = mloop + mp->loopstart + dm->numLoopData; - for (j = 0; j < mp->totloop; j++) { - CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j, - mp->loopstart + (mp->totloop - j - 1) + dm->numLoopData, 1); + DM_copy_poly_data(dm, result, 0, 0, (int)numFaces); + DM_copy_poly_data(dm, result, 0, (int)numFaces, (int)numFaces); + } + else { + int i, j; + DM_copy_vert_data(dm, result, 0, 0, (int)numVerts); + for (i = 0, j = (int)numVerts; i < numVerts; i++) { + if (old_vert_arr[i] != INVALID_UNUSED) { + DM_copy_vert_data(dm, result, i, j, 1); + j++; + } } - if (mat_ofs) { - mp->mat_nr += mat_ofs; - CLAMP(mp->mat_nr, 0, mat_nr_max); - } + DM_copy_edge_data(dm, result, 0, 0, (int)numEdges); - e = ml2[0].e; - for (j = 0; j < mp->totloop - 1; j++) { - ml2[j].e = ml2[j + 1].e; + for (i = 0, j = (int)numEdges; i < numEdges; i++) { + if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) { + MEdge *ed_src, *ed_dst; + DM_copy_edge_data(dm, result, i, j, 1); + + ed_src = &medge[i]; + ed_dst = &medge[j]; + ed_dst->v1 = old_vert_arr[ed_src->v1] + numVerts; + ed_dst->v2 = old_vert_arr[ed_src->v2] + numVerts; + j++; + } } - ml2[mp->totloop - 1].e = e; - mp->loopstart += dm->numLoopData; + /* will be created later */ + DM_copy_loop_data(dm, result, 0, 0, (int)numLoops); + DM_copy_poly_data(dm, result, 0, 0, (int)numFaces); + } + +#undef INVALID_UNUSED +#undef INVALID_PAIR + + + /* initializes: (i_end, do_shell_align, mv) */ +#define INIT_VERT_ARRAY_OFFSETS(test) \ + if (((ofs_new >= ofs_orig) == do_flip) == test) { \ + i_end = numVerts; \ + do_shell_align = true; \ + mv = mvert; \ + } \ + else { \ + if (do_shell) { \ + i_end = numVerts; \ + do_shell_align = true; \ + } \ + else { \ + i_end = newVerts ; \ + do_shell_align = false; \ + } \ + mv = &mvert[numVerts]; \ + } (void)0 + + + /* flip normals */ + + if (do_shell) { + unsigned int i; - for (j = 0; j < mp->totloop; j++) { - ml2[j].e += numEdges; - ml2[j].v += numVerts; + mp = mpoly + numFaces; + for (i = 0; i < dm->numPolyData; i++, mp++) { + MLoop *ml2; + unsigned int e; + int j; + + ml2 = mloop + mp->loopstart + dm->numLoopData; + for (j = 0; j < mp->totloop; j++) { + CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j, + mp->loopstart + (mp->totloop - j - 1) + dm->numLoopData, 1); + } + + if (mat_ofs) { + mp->mat_nr += mat_ofs; + CLAMP(mp->mat_nr, 0, mat_nr_max); + } + + e = ml2[0].e; + for (j = 0; j < mp->totloop - 1; j++) { + ml2[j].e = ml2[j + 1].e; + } + ml2[mp->totloop - 1].e = e; + + mp->loopstart += dm->numLoopData; + + for (j = 0; j < mp->totloop; j++) { + ml2[j].e += numEdges; + ml2[j].v += numVerts; + } } - } - for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) { - ed->v1 += numVerts; - ed->v2 += numVerts; + for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) { + ed->v1 += numVerts; + ed->v2 += numVerts; + } } /* note, copied vertex layers don't have flipped normals yet. do this after applying offset */ @@ -425,6 +492,8 @@ static DerivedMesh *applyModifier( const float offset_sq = offset * offset; if (do_clamp) { + unsigned int i; + vert_lens = MEM_mallocN(sizeof(float) * numVerts, "vert_lens"); fill_vn_fl(vert_lens, (int)numVerts, FLT_MAX); for (i = 0; i < numEdges; i++) { @@ -435,19 +504,24 @@ static DerivedMesh *applyModifier( } if (ofs_new != 0.0f) { + unsigned int i_orig, i_end; + bool do_shell_align; + scalar_short = scalar_short_vgroup = ofs_new / 32767.0f; - mv = mvert + (((ofs_new >= ofs_orig) == do_flip) ? numVerts : 0); - dv = dvert; - for (i = 0; i < numVerts; i++, mv++) { - if (dv) { + + INIT_VERT_ARRAY_OFFSETS(false); + + for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { + const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; + if (dvert) { + MDeformVert *dv = &dvert[i]; if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index); else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index); scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short; - dv++; } if (do_clamp) { /* always reset becaise we may have set before */ - if (dv == NULL) { + if (dvert == NULL) { scalar_short_vgroup = scalar_short; } if (vert_lens[i] < offset_sq) { @@ -460,19 +534,25 @@ static DerivedMesh *applyModifier( } if (ofs_orig != 0.0f) { + unsigned int i_orig, i_end; + bool do_shell_align; + scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f; - mv = mvert + (((ofs_new >= ofs_orig) == do_flip) ? 0 : numVerts); /* as above but swapped */ - dv = dvert; - for (i = 0; i < numVerts; i++, mv++) { - if (dv) { + + /* as above but swapped */ + INIT_VERT_ARRAY_OFFSETS(true); + + for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { + const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; + if (dvert) { + MDeformVert *dv = &dvert[i]; if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index); else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index); scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short; - dv++; } if (do_clamp) { /* always reset becaise we may have set before */ - if (dv == NULL) { + if (dvert == NULL) { scalar_short_vgroup = scalar_short; } if (vert_lens[i] < offset_sq) { @@ -496,6 +576,7 @@ static DerivedMesh *applyModifier( float *vert_angles = MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */ float *vert_accum = vert_angles + numVerts; unsigned int vidx; + unsigned int i; if (vert_nors == NULL) { vert_nors = MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno"); @@ -558,9 +639,9 @@ static DerivedMesh *applyModifier( /* vertex group support */ if (dvert) { + MDeformVert *dv = dvert; float scalar; - dv = dvert; if (defgrp_invert) { for (i = 0; i < numVerts; i++, dv++) { scalar = 1.0f - defvert_find_weight(dv, defgrp_index); @@ -596,21 +677,29 @@ static DerivedMesh *applyModifier( MEM_freeN(vert_lens_sq); } - if (ofs_new) { - mv = mvert + (((ofs_new >= ofs_orig) == do_flip) ? numVerts : 0); + if (ofs_new != 0.0f) { + unsigned int i_orig, i_end; + bool do_shell_align; + + INIT_VERT_ARRAY_OFFSETS(false); - for (i = 0; i < numVerts; i++, mv++) { + for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { + const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (vert_accum[i]) { /* zero if unselected */ madd_v3_v3fl(mv->co, vert_nors[i], ofs_new * (vert_angles[i] / vert_accum[i])); } } } - if (ofs_orig) { + if (ofs_orig != 0.0f) { + unsigned int i_orig, i_end; + bool do_shell_align; + /* same as above but swapped, intentional use of 'ofs_new' */ - mv = mvert + (((ofs_new >= ofs_orig) == do_flip) ? 0 : numVerts); + INIT_VERT_ARRAY_OFFSETS(true); - for (i = 0; i < numVerts; i++, mv++) { + for (i_orig = 0; i_orig < i_end; i_orig++, mv++) { + const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig]; if (vert_accum[i]) { /* zero if unselected */ madd_v3_v3fl(mv->co, vert_nors[i], ofs_orig * (vert_angles[i] / vert_accum[i])); } @@ -627,7 +716,8 @@ static DerivedMesh *applyModifier( if ((dm->dirty & DM_DIRTY_NORMALS) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) { result->dirty |= DM_DIRTY_NORMALS; } - else { + else if (do_shell) { + unsigned int i; /* flip vertex normals for copied verts */ mv = mvert + numVerts; for (i = 0; i < numVerts; i++, mv++) { @@ -636,6 +726,7 @@ static DerivedMesh *applyModifier( } if (smd->flag & MOD_SOLIDIFY_RIM) { + unsigned int i; /* bugger, need to re-calculate the normals for the new edge faces. * This could be done in many ways, but probably the quickest way @@ -668,11 +759,11 @@ static DerivedMesh *applyModifier( /* add faces & edges */ origindex_edge = result->getEdgeDataArray(result, CD_ORIGINDEX); - ed = &medge[numEdges * 2]; - orig_ed = &origindex_edge[numEdges * 2]; + ed = &medge[(numEdges * stride) + newVerts]; /* start after copied edges */ + orig_ed = &origindex_edge[(numEdges * stride) + newVerts]; for (i = 0; i < newEdges; i++, ed++, orig_ed++) { ed->v1 = new_vert_arr[i]; - ed->v2 = new_vert_arr[i] + numVerts; + ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts; ed->flag |= ME_EDGEDRAW; *orig_ed = ORIGINDEX_NONE; @@ -683,8 +774,8 @@ static DerivedMesh *applyModifier( } /* faces */ - mp = mpoly + (numFaces * 2); - ml = mloop + (numLoops * 2); + mp = mpoly + (numFaces * stride); + ml = mloop + (numLoops * stride); j = 0; for (i = 0; i < newFaces; i++, mp++) { unsigned int eidx = new_edge_arr[i]; @@ -703,8 +794,8 @@ static DerivedMesh *applyModifier( ed = medge + eidx; /* copy most of the face settings */ - DM_copy_poly_data(dm, result, (int)fidx, (int)((numFaces * 2) + i), 1); - mp->loopstart = (int)(j + numLoops * 2); + DM_copy_poly_data(dm, result, (int)fidx, (int)((numFaces * stride) + i), 1); + mp->loopstart = (int)(j + (numLoops * stride)); mp->flag = mpoly[fidx].flag; /* notice we use 'mp->totloop' which is later overwritten, @@ -715,36 +806,36 @@ static DerivedMesh *applyModifier( mp->totloop = 4; - CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)(numLoops * 2 + j + 0), 1); - CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)(numLoops * 2 + j + 1), 1); - CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)(numLoops * 2 + j + 2), 1); - CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)(numLoops * 2 + j + 3), 1); + CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 0), 1); + CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 1), 1); + CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 2), 1); + CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 3), 1); if (flip == false) { ml[j].v = ed->v1; ml[j++].e = eidx; ml[j].v = ed->v2; - ml[j++].e = numEdges * 2 + old_vert_arr[ed->v2]; + ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newVerts; - ml[j].v = ed->v2 + numVerts; - ml[j++].e = eidx + numEdges; + ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts; + ml[j++].e = (do_shell ? eidx : i) + numEdges; - ml[j].v = ed->v1 + numVerts; - ml[j++].e = numEdges * 2 + old_vert_arr[ed->v1]; + ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts; + ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newVerts; } else { ml[j].v = ed->v2; ml[j++].e = eidx; ml[j].v = ed->v1; - ml[j++].e = numEdges * 2 + old_vert_arr[ed->v1]; + ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newVerts; - ml[j].v = ed->v1 + numVerts; - ml[j++].e = eidx + numEdges; + ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts; + ml[j++].e = (do_shell ? eidx : i) + numEdges; - ml[j].v = ed->v2 + numVerts; - ml[j++].e = numEdges * 2 + old_vert_arr[ed->v2]; + ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts; + ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newVerts; } origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE; @@ -757,14 +848,14 @@ static DerivedMesh *applyModifier( } if (crease_outer) { /* crease += crease_outer; without wrapping */ - unsigned char *cr = (unsigned char *)&(ed->crease); + char *cr = &(ed->crease); int tcr = *cr + crease_outer; *cr = tcr > 255 ? 255 : tcr; } if (crease_inner) { /* crease += crease_inner; without wrapping */ - unsigned char *cr = (unsigned char *)&(medge[numEdges + eidx].crease); + char *cr = &(medge[numEdges + (do_shell ? eidx : i)].crease); int tcr = *cr + crease_inner; *cr = tcr > 255 ? 255 : tcr; } @@ -785,7 +876,7 @@ static DerivedMesh *applyModifier( #ifdef SOLIDIFY_SIDE_NORMALS if (do_side_normals) { - ed = medge + (numEdges * 2); + ed = medge + (numEdges * stride); for (i = 0; i < newEdges; i++, ed++) { float nor_cpy[3]; short *nor_short; diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index 386d6d985fb..829c2b88995 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -198,7 +198,7 @@ DerivedMesh *get_dm(Object *ob, struct BMEditMesh *em, DerivedMesh *dm, DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob)); } } - else if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { dm = CDDM_from_curve(ob); } diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c index 12ecae8ad4f..744b6b62c2a 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.c +++ b/source/blender/modifiers/intern/MOD_weightvg_util.c @@ -66,9 +66,9 @@ void weightvg_do_map(int num, float *new_w, short falloff_type, CurveMapping *cm /* Return immediately, if we have nothing to do! */ /* Also security checks... */ if (((falloff_type == MOD_WVG_MAPPING_CURVE) && (cmap == NULL)) || - !ELEM7(falloff_type, MOD_WVG_MAPPING_CURVE, MOD_WVG_MAPPING_SHARP, MOD_WVG_MAPPING_SMOOTH, - MOD_WVG_MAPPING_ROOT, MOD_WVG_MAPPING_SPHERE, MOD_WVG_MAPPING_RANDOM, - MOD_WVG_MAPPING_STEP)) + !ELEM(falloff_type, MOD_WVG_MAPPING_CURVE, MOD_WVG_MAPPING_SHARP, MOD_WVG_MAPPING_SMOOTH, + MOD_WVG_MAPPING_ROOT, MOD_WVG_MAPPING_SPHERE, MOD_WVG_MAPPING_RANDOM, + MOD_WVG_MAPPING_STEP)) { return; } diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index f5ae8561300..71d4742980e 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -43,7 +43,6 @@ #include "BKE_deform.h" #include "BKE_library.h" #include "BKE_modifier.h" -#include "BKE_shrinkwrap.h" /* For SpaceTransform stuff. */ #include "BKE_texture.h" /* Texture masking. */ #include "depsgraph_private.h" @@ -73,12 +72,12 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3], DerivedMesh *target, const SpaceTransform *loc2trgt) { int i; - BVHTreeFromMesh treeData_v = NULL_BVHTreeFromMesh; - BVHTreeFromMesh treeData_e = NULL_BVHTreeFromMesh; - BVHTreeFromMesh treeData_f = NULL_BVHTreeFromMesh; - BVHTreeNearest nearest_v = NULL_BVHTreeNearest; - BVHTreeNearest nearest_e = NULL_BVHTreeNearest; - BVHTreeNearest nearest_f = NULL_BVHTreeNearest; + BVHTreeFromMesh treeData_v = {NULL}; + BVHTreeFromMesh treeData_e = {NULL}; + BVHTreeFromMesh treeData_f = {NULL}; + BVHTreeNearest nearest_v = {0}; + BVHTreeNearest nearest_e = {0}; + BVHTreeNearest nearest_f = {0}; if (dist_v) { /* Create a bvh-tree of the given target's verts. */ @@ -120,7 +119,7 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3], /* Convert the vertex to tree coordinates. */ copy_v3_v3(tmp_co, v_cos[i]); - space_transform_apply(loc2trgt, tmp_co); + BLI_space_transform_apply(loc2trgt, tmp_co); /* Use local proximity heuristics (to reduce the nearest search). * @@ -465,7 +464,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der DerivedMesh *target_dm = obr->derivedFinal; bool free_target_dm = false; if (!target_dm) { - if (ELEM3(obr->type, OB_CURVE, OB_SURF, OB_FONT)) + if (ELEM(obr->type, OB_CURVE, OB_SURF, OB_FONT)) target_dm = CDDM_from_curve(obr); else if (obr->type == OB_MESH) { Mesh *me = (Mesh *)obr->data; @@ -484,7 +483,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der float *dists_e = use_trgt_edges ? MEM_mallocN(sizeof(float) * numIdx, "dists_e") : NULL; float *dists_f = use_trgt_faces ? MEM_mallocN(sizeof(float) * numIdx, "dists_f") : NULL; - SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr); + BLI_SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr); get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f, target_dm, &loc2trgt); for (i = 0; i < numIdx; i++) { diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 3899b3dce30..9eb6c1674a3 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -106,6 +106,7 @@ set(SRC composite/nodes/node_composite_setalpha.c composite/nodes/node_composite_splitViewer.c composite/nodes/node_composite_stabilize2d.c + composite/nodes/node_composite_sunbeams.c composite/nodes/node_composite_texture.c composite/nodes/node_composite_tonemap.c composite/nodes/node_composite_trackpos.c @@ -184,6 +185,7 @@ set(SRC shader/nodes/node_shader_output_lamp.c shader/nodes/node_shader_output_material.c shader/nodes/node_shader_output_world.c + shader/nodes/node_shader_output_linestyle.c shader/nodes/node_shader_particle_info.c shader/nodes/node_shader_script.c shader/nodes/node_shader_subsurface_scattering.c @@ -202,6 +204,7 @@ set(SRC shader/nodes/node_shader_tex_wave.c shader/nodes/node_shader_volume_scatter.c shader/nodes/node_shader_volume_absorption.c + shader/nodes/node_shader_uvAlongStroke.c shader/nodes/node_shader_uvmap.c shader/node_shader_tree.c shader/node_shader_util.c @@ -279,4 +282,8 @@ endif() add_definitions(${GL_DEFINITIONS}) +if(WITH_FREESTYLE) + add_definitions(-DWITH_FREESTYLE) +endif() + blender_add_lib(bf_nodes "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index ad5f35b8faa..961fdbfc0fb 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -125,7 +125,7 @@ void register_node_type_cmp_mask(void); void register_node_type_cmp_glare(void); void register_node_type_cmp_tonemap(void); void register_node_type_cmp_lensdist(void); - +void register_node_type_cmp_sunbeams(void); void register_node_type_cmp_colorcorrection(void); void register_node_type_cmp_boxmask(void); diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 255ad568bad..595a3b12bc6 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -114,10 +114,12 @@ void register_node_type_sh_subsurface_scattering(void); void register_node_type_sh_mix_shader(void); void register_node_type_sh_add_shader(void); void register_node_type_sh_uvmap(void); +void register_node_type_sh_uvalongstroke(void); void register_node_type_sh_output_lamp(void); void register_node_type_sh_output_material(void); void register_node_type_sh_output_world(void); +void register_node_type_sh_output_linestyle(void); void register_node_type_sh_tex_image(void); void register_node_type_sh_tex_environment(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 8d6c4abaef6..166fa29fca0 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -69,6 +69,7 @@ DefNode( ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_S DefNode( ShaderNode, SH_NODE_OUTPUT_MATERIAL, def_sh_output, "OUTPUT_MATERIAL", OutputMaterial, "Material Output", "" ) DefNode( ShaderNode, SH_NODE_OUTPUT_LAMP, def_sh_output, "OUTPUT_LAMP", OutputLamp, "Lamp Output", "" ) DefNode( ShaderNode, SH_NODE_OUTPUT_WORLD, def_sh_output, "OUTPUT_WORLD", OutputWorld, "World Output", "" ) +DefNode( ShaderNode, SH_NODE_OUTPUT_LINESTYLE, def_sh_output_linestyle,"OUTPUT_LINESTYLE", OutputLineStyle, "Line Style Output", "" ) DefNode( ShaderNode, SH_NODE_FRESNEL, 0, "FRESNEL", Fresnel, "Fresnel", "" ) DefNode( ShaderNode, SH_NODE_LAYER_WEIGHT, 0, "LAYER_WEIGHT", LayerWeight, "Layer Weight", "" ) DefNode( ShaderNode, SH_NODE_MIX_SHADER, 0, "MIX_SHADER", MixShader, "Mix Shader", "" ) @@ -120,6 +121,7 @@ DefNode( ShaderNode, SH_NODE_VECT_TRANSFORM, def_sh_vect_transform, "VE DefNode( ShaderNode, SH_NODE_SEPHSV, 0, "SEPHSV", SeparateHSV, "Separate HSV", "" ) DefNode( ShaderNode, SH_NODE_COMBHSV, 0, "COMBHSV", CombineHSV, "Combine HSV", "" ) DefNode( ShaderNode, SH_NODE_UVMAP, def_sh_uvmap, "UVMAP", UVMap, "UV Map", "" ) +DefNode( ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UVALONGSTROKE", UVAlongStroke, "UV Along Stroke", "" ) DefNode( ShaderNode, SH_NODE_SEPXYZ, 0, "SEPXYZ", SeparateXYZ, "Separate XYZ", "" ) DefNode( ShaderNode, SH_NODE_COMBXYZ, 0, "COMBXYZ", CombineXYZ, "Combine XYZ", "" ) @@ -208,6 +210,7 @@ DefNode( CompositorNode, CMP_NODE_TRACKPOS, def_cmp_trackpos, "TRACK DefNode( CompositorNode, CMP_NODE_PIXELATE, 0, "PIXELATE", Pixelate, "Pixelate", "" ) DefNode( CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" ) DefNode( CompositorNode, CMP_NODE_CORNERPIN, 0, "CORNERPIN", CornerPin, "Corner Pin", "" ) +DefNode( CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" ) 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/SConscript b/source/blender/nodes/SConscript index 683a1c475e4..becf6e79d44 100644 --- a/source/blender/nodes/SConscript +++ b/source/blender/nodes/SConscript @@ -72,6 +72,9 @@ if env['WITH_BF_COMPOSITOR']: incs += ' ../compositor ' defs.append("WITH_COMPOSITOR") +if env['WITH_BF_FREESTYLE']: + defs.append('WITH_FREESTYLE') + env.BlenderLib ( libname = 'bf_nodes', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [190,105] ) env.BlenderLib ( libname = 'bf_cmpnodes', sources = cmpsources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [175,101] ) env.BlenderLib ( libname = 'bf_shdnodes', sources = shdsources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [175,101] ) diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c index cd69cf4982d..6d5b85da569 100644 --- a/source/blender/nodes/composite/node_composite_tree.c +++ b/source/blender/nodes/composite/node_composite_tree.c @@ -104,9 +104,9 @@ static void free_cache(bNodeTree *ntree) } /* local tree then owns all compbufs */ -static void localize(bNodeTree *localtree, bNodeTree *ntree) +static void localize(bNodeTree *UNUSED(localtree), bNodeTree *ntree) { - bNode *node, *node_next; + bNode *node; bNodeSocket *sock; for (node = ntree->nodes.first; node; node = node->next) { @@ -132,26 +132,6 @@ static void localize(bNodeTree *localtree, bNodeTree *ntree) sock->new_sock->new_sock = sock; } } - - /* replace muted nodes and reroute nodes by internal links */ - for (node = localtree->nodes.first; node; node = node_next) { - node_next = node->next; - - if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) { - /* make sure the update tag isn't lost when removing the muted node. - * propagate this to all downstream nodes. - */ - if (node->need_exec) { - bNodeLink *link; - for (link = localtree->links.first; link; link = link->next) - if (link->fromnode == node && link->tonode) - link->tonode->need_exec = 1; - } - - nodeInternalRelink(localtree, node); - nodeFreeNode(localtree, node); - } - } } static void local_sync(bNodeTree *localtree, bNodeTree *ntree) diff --git a/source/blender/nodes/composite/nodes/node_composite_sunbeams.c b/source/blender/nodes/composite/nodes/node_composite_sunbeams.c new file mode 100644 index 00000000000..4d937d63b75 --- /dev/null +++ b/source/blender/nodes/composite/nodes/node_composite_sunbeams.c @@ -0,0 +1,63 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Lukas Toenne + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/nodes/composite/nodes/node_composite_sunbeams.c + * \ingroup cmpnodes + */ + +#include "node_composite_util.h" + +static bNodeSocketTemplate inputs[] = { + { SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketTemplate outputs[] = { + { SOCK_RGBA, 0, N_("Image")}, + { -1, 0, "" } +}; + +static void init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeSunBeams *data = MEM_callocN(sizeof(NodeSunBeams), "sun beams node"); + + data->source[0] = 0.5f; + data->source[1] = 0.5f; + + node->storage = data; +} + +void register_node_type_cmp_sunbeams(void) +{ + static bNodeType ntype; + + cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER, 0); + node_type_socket_templates(&ntype, inputs, outputs); + node_type_init(&ntype, init); + node_type_storage(&ntype, "NodeSunBeams", node_free_standard_storage, node_copy_standard_storage); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c index ae834f9e7cc..c58c9c902ec 100644 --- a/source/blender/nodes/intern/node_common.c +++ b/source/blender/nodes/intern/node_common.c @@ -336,6 +336,40 @@ void ntree_update_reroute_nodes(bNodeTree *ntree) node_reroute_inherit_type_recursive(ntree, node); } +static bool node_is_connected_to_output_recursive(bNodeTree *ntree, bNode *node) +{ + bNodeLink *link; + + /* avoid redundant checks, and infinite loops in case of cyclic node links */ + if (node->done) + return false; + node->done = 1; + + /* main test, done before child loop so it catches output nodes themselves as well */ + if (node->typeinfo->nclass == NODE_CLASS_OUTPUT && node->flag & NODE_DO_OUTPUT) + return true; + + /* test all connected nodes, first positive find is sufficient to return true */ + for (link = ntree->links.first; link; link = link->next) { + if (link->fromnode == node) { + if (node_is_connected_to_output_recursive(ntree, link->tonode)) + return true; + } + } + return false; +} + +bool BKE_node_is_connected_to_output(bNodeTree *ntree, bNode *node) +{ + bNode *tnode; + + /* clear flags */ + for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) + tnode->done = 0; + + return node_is_connected_to_output_recursive(ntree, node); +} + void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree) { bNode *node; diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c index 0e5f72c831b..0893d2022a0 100644 --- a/source/blender/nodes/intern/node_exec.c +++ b/source/blender/nodes/intern/node_exec.c @@ -47,7 +47,7 @@ /* supported socket types in old nodes */ int node_exec_socket_use_stack(bNodeSocket *sock) { - return ELEM4(sock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER); + return ELEM(sock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER); } /* for a given socket, find the actual stack entry */ @@ -159,6 +159,8 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, bNodeTree *ntree, bNo int index; bNode **nodelist; int totnodes, n; + /* XXX texnodes have threading issues with muting, have to disable it there ... */ + bool use_muting = (ntree->type != NTREE_TEXTURE); /* ensure all sock->link pointers and node levels are correct */ ntreeUpdateTree(G.main, ntree); @@ -182,7 +184,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, bNodeTree *ntree, bNo for (sock = node->inputs.first; sock; sock = sock->next) node_init_input_index(sock, &index); - if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) { + if (use_muting && (node->flag & NODE_MUTED || node->type == NODE_REROUTE)) { for (sock = node->outputs.first; sock; sock = sock->next) node_init_output_index(sock, &index, &node->internal_links); } diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 4288b8fbcdc..299172ae4cc 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -38,6 +38,7 @@ #include "DNA_scene_types.h" #include "DNA_space_types.h" #include "DNA_world_types.h" +#include "DNA_linestyle_types.h" #include "BLI_listbase.h" #include "BLI_math.h" @@ -48,6 +49,7 @@ #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_linestyle.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_scene.h" @@ -97,6 +99,16 @@ static void shader_get_from_context(const bContext *C, bNodeTreeType *UNUSED(tre } } } +#ifdef WITH_FREESTYLE + else if (snode->shaderfrom == SNODE_SHADER_LINESTYLE) { + FreestyleLineStyle *linestyle = BKE_linestyle_active_from_scene(scene); + if (linestyle) { + *r_from = NULL; + *r_id = &linestyle->id; + *r_ntree = linestyle->nodetree; + } + } +#endif else { /* SNODE_SHADER_WORLD */ if (scene->world) { *r_from = NULL; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c index 55dafaeca35..75ca4b87f09 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c @@ -30,7 +30,7 @@ /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_bsdf_glass_in[] = { - { SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f}, { SOCK_FLOAT, 1, N_("Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, { SOCK_FLOAT, 1, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.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}, diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c new file mode 100644 index 00000000000..2eb68f23912 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c @@ -0,0 +1,54 @@ +/* + * ***** 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_output_linestyle_in[] = { + { SOCK_RGBA, 1, N_("Color"), 1.0f, 0.0f, 1.0f, 1.0f }, + { SOCK_FLOAT, 1, N_("Color Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR }, + { SOCK_FLOAT, 1, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR }, + { SOCK_FLOAT, 1, N_("Alpha Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR }, + { -1, 0, "" } +}; + +/* node type definition */ +void register_node_type_sh_output_linestyle(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_OUTPUT_LINESTYLE, "Line Style Output", NODE_CLASS_OUTPUT, 0); + node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_socket_templates(&ntype, sh_node_output_linestyle_in, NULL); + node_type_init(&ntype, NULL); + + /* Do not allow muting output node. */ + node_type_internal_links(&ntype, NULL); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c b/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c new file mode 100644 index 00000000000..48eb4cadba4 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c @@ -0,0 +1,50 @@ +/* + * ***** 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" + +#include "DNA_customdata_types.h" + +/* **************** OUTPUT ******************** */ + +static bNodeSocketTemplate sh_node_uvalongstroke_out[] = { + { SOCK_VECTOR, 0, N_("UV"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +/* node type definition */ +void register_node_type_sh_uvalongstroke(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_UVALONGSTROKE, "UV Along Stroke", NODE_CLASS_INPUT, 0); + node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_socket_templates(&ntype, NULL, sh_node_uvalongstroke_out); + node_type_init(&ntype, NULL); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.c b/source/blender/nodes/shader/nodes/node_shader_uvmap.c index fff1bc1df95..0f96cb45fe0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_uvmap.c +++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.c @@ -42,6 +42,14 @@ static void node_shader_init_uvmap(bNodeTree *UNUSED(ntree), bNode *node) node->storage = attr; } +static int node_shader_gpu_uvmap(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + NodeShaderUVMap *attr = node->storage; + GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, attr->uv_map); + + return GPU_stack_link(mat, "node_uvmap", in, out, mtface); +} + /* node type definition */ void register_node_type_sh_uvmap(void) { @@ -53,6 +61,7 @@ void register_node_type_sh_uvmap(void) node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_init(&ntype, node_shader_init_uvmap); node_type_storage(&ntype, "NodeShaderUVMap", node_free_standard_storage, node_copy_standard_storage); + node_type_gpu(&ntype, node_shader_gpu_uvmap); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c index 882c843f317..02f15705ad1 100644 --- a/source/blender/nodes/texture/node_texture_tree.c +++ b/source/blender/nodes/texture/node_texture_tree.c @@ -44,6 +44,7 @@ #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_linestyle.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_paint.h" @@ -110,7 +111,7 @@ static void texture_get_from_context(const bContext *C, bNodeTreeType *UNUSED(tr } } else if (snode->texfrom == SNODE_TEX_LINESTYLE) { - FreestyleLineStyle *linestyle = CTX_data_linestyle_from_scene(scene); + FreestyleLineStyle *linestyle = BKE_linestyle_active_from_scene(scene); if (linestyle) { *r_from = (ID *)linestyle; tx = give_current_linestyle_texture(linestyle); @@ -136,6 +137,10 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa func(calldata, NODE_CLASS_LAYOUT, N_("Layout")); } +/* XXX muting disabled in previews because of threading issues with the main execution + * it works here, but disabled for consistency + */ +#if 0 static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree)) { bNode *node, *node_next; @@ -150,6 +155,11 @@ static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree)) } } } +#else +static void localize(bNodeTree *UNUSED(localtree), bNodeTree *UNUSED(ntree)) +{ +} +#endif static void local_sync(bNodeTree *localtree, bNodeTree *ntree) { diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index c2b496f914b..a31345cd7f5 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -645,7 +645,7 @@ static int bpy_bmfaceseq_active_set(BPy_BMElem *self, PyObject *value, void *UNU return 0; } else if (BPy_BMFace_Check(value)) { - BPY_BM_CHECK_SOURCE_INT(value, bm, "faces.active = f"); + BPY_BM_CHECK_SOURCE_INT(bm, "faces.active = f", value); bm->act_face = ((BPy_BMFace *)value)->f; return 0; @@ -1217,6 +1217,44 @@ static PyObject *bpy_bmesh_calc_volume(BPy_BMElem *self, PyObject *args, PyObjec } } +PyDoc_STRVAR(bpy_bmesh_calc_tessface_doc, +".. method:: calc_tessface()\n" +"\n" +" Calculate triangle tessellation from quads/ngons.\n" +"\n" +" :return: The triangulated faces.\n" +" :rtype: list of :class:`BMLoop` tuples\n" +); +static PyObject *bpy_bmesh_calc_tessface(BPy_BMElem *self) +{ + BMesh *bm; + + int looptris_tot; + int tottri; + BMLoop *(*looptris)[3]; + + PyObject *ret; + int i; + + BPY_BM_CHECK_OBJ(self); + + bm = self->bm; + + looptris_tot = poly_to_tri_count(bm->totface, bm->totloop); + looptris = PyMem_MALLOC(sizeof(*looptris) * looptris_tot); + + BM_bmesh_calc_tessellation(bm, looptris, &tottri); + + ret = PyList_New(tottri); + for (i = 0; i < tottri; i++) { + PyList_SET_ITEM(ret, i, BPy_BMLoop_Array_As_Tuple(bm, looptris[i], 3)); + } + + PyMem_FREE(looptris); + + return ret; +} + /* Elem * ---- */ @@ -1373,7 +1411,7 @@ static PyObject *bpy_bmvert_copy_from_face_interp(BPy_BMVert *self, PyObject *ar else { BMesh *bm = self->bm; - BPY_BM_CHECK_SOURCE_OBJ(py_face, bm, "copy_from_face_interp()"); + BPY_BM_CHECK_SOURCE_OBJ(bm, "copy_from_face_interp()", py_face); BM_vert_interp_from_face(bm, self->v, py_face->f); @@ -1519,7 +1557,7 @@ static PyObject *bpy_bmedge_other_vert(BPy_BMEdge *self, BPy_BMVert *value) return NULL; } - BPY_BM_CHECK_SOURCE_OBJ(value, self->bm, "BMEdge.other_vert(vert)"); + BPY_BM_CHECK_SOURCE_OBJ(self->bm, "BMEdge.other_vert(vert)", value); other = BM_edge_other_vert(self->e, value->v); @@ -1576,7 +1614,7 @@ static PyObject *bpy_bmface_copy_from_face_interp(BPy_BMFace *self, PyObject *ar else { BMesh *bm = self->bm; - BPY_BM_CHECK_SOURCE_OBJ(py_face, bm, "BMFace.copy_from_face_interp(face)"); + BPY_BM_CHECK_SOURCE_OBJ(bm, "BMFace.copy_from_face_interp(face)", py_face); BM_face_interp_from_face(bm, self->f, py_face->f, do_vertex); @@ -1773,7 +1811,7 @@ static PyObject *bpy_bmloop_copy_from_face_interp(BPy_BMLoop *self, PyObject *ar else { BMesh *bm = self->bm; - BPY_BM_CHECK_SOURCE_OBJ(py_face, bm, "BMLoop.copy_from_face_interp(face)"); + BPY_BM_CHECK_SOURCE_OBJ(bm, "BMLoop.copy_from_face_interp(face)", py_face); BM_loop_interp_from_face(bm, self->l, py_face->f, do_vertex, do_multires); @@ -2056,7 +2094,7 @@ static PyObject *bpy_bmvertseq_remove(BPy_BMElemSeq *self, BPy_BMVert *value) else { BMesh *bm = self->bm; - BPY_BM_CHECK_SOURCE_OBJ(value, bm, "verts.remove(vert)"); + BPY_BM_CHECK_SOURCE_OBJ(bm, "verts.remove(vert)", value); BM_vert_kill(bm, value->v); bpy_bm_generic_invalidate((BPy_BMGeneric *)value); @@ -2080,7 +2118,7 @@ static PyObject *bpy_bmedgeseq_remove(BPy_BMElemSeq *self, BPy_BMEdge *value) else { BMesh *bm = self->bm; - BPY_BM_CHECK_SOURCE_OBJ(value, bm, "edges.remove(edges)"); + BPY_BM_CHECK_SOURCE_OBJ(bm, "edges.remove(edges)", value); BM_edge_kill(bm, value->e); bpy_bm_generic_invalidate((BPy_BMGeneric *)value); @@ -2104,7 +2142,7 @@ static PyObject *bpy_bmfaceseq_remove(BPy_BMElemSeq *self, BPy_BMFace *value) else { BMesh *bm = self->bm; - BPY_BM_CHECK_SOURCE_OBJ(value, bm, "faces.remove(face)"); + BPY_BM_CHECK_SOURCE_OBJ(bm, "faces.remove(face)", value); BM_face_kill(bm, value->f); bpy_bm_generic_invalidate((BPy_BMGeneric *)value); @@ -2488,6 +2526,7 @@ static struct PyMethodDef bpy_bmesh_methods[] = { /* calculations */ {"calc_volume", (PyCFunction)bpy_bmesh_calc_volume, METH_VARARGS | METH_KEYWORDS, bpy_bmesh_calc_volume_doc}, + {"calc_tessface", (PyCFunction)bpy_bmesh_calc_tessface, METH_NOARGS, bpy_bmesh_calc_tessface_doc}, {NULL, NULL, 0, NULL} }; @@ -3545,18 +3584,34 @@ int bpy_bm_generic_valid_check(BPy_BMGeneric *self) } } -int bpy_bm_generic_valid_check_source(BPy_BMGeneric *self, BMesh *bm_source, const char *error_prefix) +int bpy_bm_generic_valid_check_source(BMesh *bm_source, const char *error_prefix, void **args, unsigned int args_tot) { - int ret = bpy_bm_generic_valid_check(self); - if (LIKELY(ret == 0)) { - if (UNLIKELY(self->bm != bm_source)) { - /* could give more info here */ - PyErr_Format(PyExc_ValueError, - "%.200s: BMesh data of type %.200s is from another mesh", - error_prefix, Py_TYPE(self)->tp_name); - ret = -1; + int ret = 0; + + while (args_tot--) { + BPy_BMGeneric *py_bm_elem = args[args_tot]; + if (py_bm_elem) { + + BLI_assert(BPy_BMesh_Check(py_bm_elem) || + BPy_BMElem_Check(py_bm_elem)); + + ret = bpy_bm_generic_valid_check(py_bm_elem); + if (UNLIKELY(ret == -1)) { + break; + } + else { + if (UNLIKELY(py_bm_elem->bm != bm_source)) { + /* could give more info here */ + PyErr_Format(PyExc_ValueError, + "%.200s: BMesh data of type %.200s is from another mesh", + error_prefix, Py_TYPE(py_bm_elem)->tp_name); + ret = -1; + break; + } + } } } + return ret; } @@ -3669,7 +3724,6 @@ err_cleanup: } } - PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len) { Py_ssize_t i; @@ -3677,6 +3731,44 @@ PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_ for (i = 0; i < elem_len; i++) { PyTuple_SET_ITEM(ret, i, BPy_BMElem_CreatePyObject(bm, elem[i])); } + return ret; +} +PyObject *BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_len) +{ + Py_ssize_t i; + PyObject *ret = PyTuple_New(elem_len); + for (i = 0; i < elem_len; i++) { + PyTuple_SET_ITEM(ret, i, BPy_BMVert_CreatePyObject(bm, elem[i])); + } + return ret; +} +PyObject *BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_len) +{ + Py_ssize_t i; + PyObject *ret = PyTuple_New(elem_len); + for (i = 0; i < elem_len; i++) { + PyTuple_SET_ITEM(ret, i, BPy_BMEdge_CreatePyObject(bm, elem[i])); + } + + return ret; +} +PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_len) +{ + Py_ssize_t i; + PyObject *ret = PyTuple_New(elem_len); + for (i = 0; i < elem_len; i++) { + PyTuple_SET_ITEM(ret, i, BPy_BMFace_CreatePyObject(bm, elem[i])); + } + + return ret; +} +PyObject *BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop **elem, Py_ssize_t elem_len) +{ + Py_ssize_t i; + PyObject *ret = PyTuple_New(elem_len); + for (i = 0; i < elem_len; i++) { + PyTuple_SET_ITEM(ret, i, BPy_BMLoop_CreatePyObject(bm, elem[i])); + } return ret; } diff --git a/source/blender/python/bmesh/bmesh_py_types.h b/source/blender/python/bmesh/bmesh_py_types.h index 0909ce0d26a..a2c2c312e71 100644 --- a/source/blender/python/bmesh/bmesh_py_types.h +++ b/source/blender/python/bmesh/bmesh_py_types.h @@ -164,13 +164,18 @@ void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ const char *error_prefix); PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len); +PyObject *BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_len); +PyObject *BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_len); +PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_len); +PyObject *BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop **elem, Py_ssize_t elem_len); + int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype); char *BPy_BMElem_StringFromHType_ex(const char htype, char ret[32]); char *BPy_BMElem_StringFromHType(const char htype); // void bpy_bm_generic_invalidate(BPy_BMGeneric *self); int bpy_bm_generic_valid_check(BPy_BMGeneric *self); -int bpy_bm_generic_valid_check_source(BPy_BMGeneric *self, BMesh *bm_source, const char *error_prefix); +int bpy_bm_generic_valid_check_source(BMesh *bm_source, const char *error_prefix, void **args, unsigned int args_n) ATTR_NONNULL(1, 2); #define BPY_BM_CHECK_OBJ(obj) \ if (UNLIKELY(bpy_bm_generic_valid_check((BPy_BMGeneric *)obj) == -1)) { return NULL; } (void)0 @@ -178,10 +183,18 @@ int bpy_bm_generic_valid_check_source(BPy_BMGeneric *self, BMesh *bm_source, co if (UNLIKELY(bpy_bm_generic_valid_check((BPy_BMGeneric *)obj) == -1)) { return -1; } (void)0 /* macros like BPY_BM_CHECK_OBJ/BPY_BM_CHECK_INT that ensure we're from the right BMesh */ -#define BPY_BM_CHECK_SOURCE_OBJ(obj, bm, errmsg) \ - if (UNLIKELY(bpy_bm_generic_valid_check_source((BPy_BMGeneric *)obj, bm, errmsg) == -1)) { return NULL; } (void)0 -#define BPY_BM_CHECK_SOURCE_INT(obj, bm, errmsg) \ - if (UNLIKELY(bpy_bm_generic_valid_check_source((BPy_BMGeneric *)obj, bm, errmsg) == -1)) { return -1; } (void)0 +#define BPY_BM_CHECK_SOURCE_OBJ(bm, errmsg, ...) { \ + void *_args[] = {__VA_ARGS__}; \ + if (UNLIKELY(bpy_bm_generic_valid_check_source(bm, errmsg, _args, ARRAY_SIZE(_args)) == -1)) { \ + return NULL; \ + } \ +} (void)0 +#define BPY_BM_CHECK_SOURCE_INT(bm, errmsg, ...) { \ + void *_args[] = {__VA_ARGS__}; \ + if (UNLIKELY(bpy_bm_generic_valid_check_source(bm, errmsg, _args, ARRAY_SIZE(_args)) == -1)) { \ + return -1; \ + } \ +} (void)0 #define BPY_BM_IS_VALID(obj) (LIKELY((obj)->bm != NULL)) diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c index dfb3ae75df4..6ecb01a8528 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c @@ -281,7 +281,7 @@ static PyObject *bpy_bmlayeritem_copy_from(BPy_BMLayerItem *self, BPy_BMLayerIte } BPY_BM_CHECK_OBJ(self); - BPY_BM_CHECK_SOURCE_OBJ(value, self->bm, "layer.copy_from()"); + BPY_BM_CHECK_SOURCE_OBJ(self->bm, "layer.copy_from()", value); if ((self->htype != value->htype) || (self->type != value->type)) diff --git a/source/blender/python/bmesh/bmesh_py_types_select.c b/source/blender/python/bmesh/bmesh_py_types_select.c index b8e04a0cab8..3c72112e7ce 100644 --- a/source/blender/python/bmesh/bmesh_py_types_select.c +++ b/source/blender/python/bmesh/bmesh_py_types_select.c @@ -112,7 +112,7 @@ static PyObject *bpy_bmeditselseq_add(BPy_BMEditSelSeq *self, BPy_BMElem *value) return NULL; } - BPY_BM_CHECK_SOURCE_OBJ(value, self->bm, "select_history.add()"); + BPY_BM_CHECK_SOURCE_OBJ(self->bm, "select_history.add()", value); BM_select_history_store(self->bm, value->ele); @@ -137,7 +137,7 @@ static PyObject *bpy_bmeditselseq_remove(BPy_BMEditSelSeq *self, BPy_BMElem *val return NULL; } - BPY_BM_CHECK_SOURCE_OBJ(value, self->bm, "select_history.remove()"); + BPY_BM_CHECK_SOURCE_OBJ(self->bm, "select_history.remove()", value); if (BM_select_history_remove(self->bm, value->ele) == false) { PyErr_SetString(PyExc_ValueError, diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c index 4f1ca568bb0..88e369af8bb 100644 --- a/source/blender/python/bmesh/bmesh_py_utils.c +++ b/source/blender/python/bmesh/bmesh_py_utils.c @@ -198,6 +198,65 @@ static PyObject *bpy_bm_utils_vert_dissolve(PyObject *UNUSED(self), PyObject *ar return PyBool_FromLong((BM_vert_dissolve(bm, py_vert->v))); } +PyDoc_STRVAR(bpy_bm_utils_vert_splice_doc, +".. method:: vert_splice(vert, vert_target)\n" +"\n" +" Splice vert into vert_target.\n" +"\n" +" :arg vert: The vertex to be removed.\n" +" :type vert: :class:`bmesh.types.BMVert`\n" +" :arg vert_target: The vertex to use.\n" +" :type vert_target: :class:`bmesh.types.BMVert`\n" +"\n" +" .. note:: The verts mustn't share an edge or face.\n" +); +static PyObject *bpy_bm_utils_vert_splice(PyObject *UNUSED(self), PyObject *args) +{ + BPy_BMVert *py_vert; + BPy_BMVert *py_vert_target; + + BMesh *bm; + + bool ok; + + if (!PyArg_ParseTuple(args, "O!O!:vert_splice", + &BPy_BMVert_Type, &py_vert, + &BPy_BMVert_Type, &py_vert_target)) + { + return NULL; + } + + BPY_BM_CHECK_OBJ(py_vert); + BPY_BM_CHECK_OBJ(py_vert_target); + + bm = py_vert->bm; + BPY_BM_CHECK_SOURCE_OBJ(bm, "vert_splice", py_vert_target); + + if (py_vert->v == py_vert_target->v) { + PyErr_SetString(PyExc_ValueError, + "vert_splice(...): vert arguments match"); + return NULL; + } + + if (BM_edge_exists(py_vert->v, py_vert_target->v)) { + PyErr_SetString(PyExc_ValueError, + "vert_splice(...): verts can't share an edge"); + return NULL; + } + + if (BM_vert_pair_share_face_check(py_vert->v, py_vert_target->v)) { + PyErr_SetString(PyExc_ValueError, + "vert_splice(...): verts can't share a face"); + return NULL; + } + + /* should always succeed */ + ok = BM_vert_splice(bm, py_vert->v, py_vert_target->v); + BLI_assert(ok == true); + + Py_RETURN_NONE; +} + PyDoc_STRVAR(bpy_bm_utils_vert_separate_doc, ".. method:: vert_separate(vert, edges)\n" "\n" @@ -247,7 +306,7 @@ static PyObject *bpy_bm_utils_vert_separate(PyObject *UNUSED(self), PyObject *ar BM_vert_separate(bm, py_vert->v, &elem, &elem_len, edge_array, edge_array_len); /* return collected verts */ - ret = BPy_BMElem_Array_As_Tuple(bm, (BMHeader **)elem, elem_len); + ret = BPy_BMVert_Array_As_Tuple(bm, elem, elem_len); MEM_freeN(elem); PyMem_FREE(edge_array); @@ -477,6 +536,78 @@ static PyObject *bpy_bm_utils_face_split(PyObject *UNUSED(self), PyObject *args, } +PyDoc_STRVAR(bpy_bm_utils_face_split_edgenet_doc, +".. method:: face_split_edgenet(face, edgenet)\n" +"\n" +" Splits a face into any number of regions defined by an edgenet.\n" +"\n" +" :arg face: The face to split.\n" +" :type face: :class:`bmesh.types.BMFace`\n" +" :arg face: The face to split.\n" +" :type face: :class:`bmesh.types.BMFace`\n" +" :arg edgenet: Sequence of edges.\n" +" :type edgenet: :class:`bmesh.types.BMEdge`\n" +" :return: The newly created faces.\n" +" :rtype: tuple of (:class:`bmesh.types.BMFace`)\n" +); +static PyObject *bpy_bm_utils_face_split_edgenet(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + static const char *kwlist[] = {"face", "edgenet", NULL}; + + BPy_BMFace *py_face; + PyObject *edge_seq; + + BMEdge **edge_array; + Py_ssize_t edge_array_len; + + BMesh *bm; + + BMFace **face_arr; + int face_arr_len; + bool ok; + + + if (!PyArg_ParseTupleAndKeywords(args, kw, "O!O:face_split_edgenet", (char **)kwlist, + &BPy_BMFace_Type, &py_face, + &edge_seq)) + { + return NULL; + } + + BPY_BM_CHECK_OBJ(py_face); + + bm = py_face->bm; + + edge_array = BPy_BMElem_PySeq_As_Array(&bm, edge_seq, 1, PY_SSIZE_T_MAX, + &edge_array_len, BM_EDGE, + true, true, "face_split_edgenet(...)"); + + if (edge_array == NULL) { + return NULL; + } + + /* --- main function body --- */ + + ok = BM_face_split_edgenet(bm, py_face->f, edge_array, edge_array_len, + &face_arr, &face_arr_len); + + PyMem_FREE(edge_array); + + if (ok) { + PyObject *ret = BPy_BMFace_Array_As_Tuple(bm, face_arr, face_arr_len); + if (face_arr) { + MEM_freeN(face_arr); + } + return ret; + } + else { + PyErr_SetString(PyExc_ValueError, + "face_split_edgenet(...): couldn't split the face, internal error"); + return NULL; + } +} + + PyDoc_STRVAR(bpy_bm_utils_face_join_doc, ".. method:: face_join(faces, remove=True)\n" "\n" @@ -560,7 +691,7 @@ static PyObject *bpy_bm_utils_face_vert_separate(PyObject *UNUSED(self), PyObjec bm = py_face->bm; BPY_BM_CHECK_OBJ(py_face); - BPY_BM_CHECK_SOURCE_OBJ(py_vert, bm, "face_vert_separate()"); + BPY_BM_CHECK_SOURCE_OBJ(bm, "face_vert_separate()", py_vert); l = BM_face_vert_share_loop(py_face->f, py_vert->v); @@ -648,10 +779,12 @@ static struct PyMethodDef BPy_BM_utils_methods[] = { {"vert_collapse_edge", (PyCFunction)bpy_bm_utils_vert_collapse_edge, METH_VARARGS, bpy_bm_utils_vert_collapse_edge_doc}, {"vert_collapse_faces", (PyCFunction)bpy_bm_utils_vert_collapse_faces, METH_VARARGS, bpy_bm_utils_vert_collapse_faces_doc}, {"vert_dissolve", (PyCFunction)bpy_bm_utils_vert_dissolve, METH_VARARGS, bpy_bm_utils_vert_dissolve_doc}, /* could use METH_O */ + {"vert_splice", (PyCFunction)bpy_bm_utils_vert_splice, METH_VARARGS, bpy_bm_utils_vert_splice_doc}, {"vert_separate", (PyCFunction)bpy_bm_utils_vert_separate, METH_VARARGS, bpy_bm_utils_vert_separate_doc}, {"edge_split", (PyCFunction)bpy_bm_utils_edge_split, METH_VARARGS, bpy_bm_utils_edge_split_doc}, {"edge_rotate", (PyCFunction)bpy_bm_utils_edge_rotate, METH_VARARGS, bpy_bm_utils_edge_rotate_doc}, {"face_split", (PyCFunction)bpy_bm_utils_face_split, METH_VARARGS | METH_KEYWORDS, bpy_bm_utils_face_split_doc}, + {"face_split_edgenet", (PyCFunction)bpy_bm_utils_face_split_edgenet, METH_VARARGS | METH_KEYWORDS, bpy_bm_utils_face_split_edgenet_doc}, {"face_join", (PyCFunction)bpy_bm_utils_face_join, METH_VARARGS, bpy_bm_utils_face_join_doc}, {"face_vert_separate", (PyCFunction)bpy_bm_utils_face_vert_separate, METH_VARARGS, bpy_bm_utils_face_vert_separate_doc}, {"face_flip", (PyCFunction)bpy_bm_utils_face_flip, METH_O, bpy_bm_utils_face_flip_doc}, diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index d18720598d1..08b8fa28db4 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -303,7 +303,7 @@ static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject if (!PyArg_ParseTuple(args, "iO|O: bgl.Buffer", &type, &length_ob, &init)) { return NULL; } - if (!ELEM5(type, GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE)) { + if (!ELEM(type, GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE)) { PyErr_SetString(PyExc_AttributeError, "invalid first argument type, should be one of " "GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT or GL_DOUBLE"); @@ -1900,9 +1900,20 @@ PyObject *BPyInit_bgl(void) EXPP_ADDCONST(GL_TEXTURE7); EXPP_ADDCONST(GL_TEXTURE8); + EXPP_ADDCONST(GL_MAX_TEXTURE_UNITS); + EXPP_ADDCONST(GL_DEPTH_COMPONENT32); EXPP_ADDCONST(GL_TEXTURE_COMPARE_MODE); + EXPP_ADDCONST(GL_MAX_VARYING_FLOATS); + EXPP_ADDCONST(GL_MAX_VERTEX_ATTRIBS); + EXPP_ADDCONST(GL_MAX_VARYING_FLOATS); + EXPP_ADDCONST(GL_MAX_VERTEX_UNIFORM_COMPONENTS); + EXPP_ADDCONST(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS); + EXPP_ADDCONST(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS); + EXPP_ADDCONST(GL_MAX_TEXTURE_IMAGE_UNITS); + EXPP_ADDCONST(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS); + return submodule; } diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index dcdda2c440e..8c9e84af8ed 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -1541,7 +1541,7 @@ PyObject *BPyInit_idprop(void) } -#ifdef DEBUG +#ifndef NDEBUG /* -------------------------------------------------------------------- */ /* debug only function */ diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 5fd19d3ed88..134e718bce5 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -51,12 +51,15 @@ #include "bpy_operator.h" #include "bpy_utils_units.h" +#include "../generic/py_capi_utils.h" + #include "MEM_guardedalloc.h" /* external util modules */ #include "../generic/idprop_py_api.h" #include "../generic/bgl.h" #include "../generic/blf_py_api.h" +#include "../generic/blf_py_api.h" #include "../mathutils/mathutils.h" #ifdef WITH_FREESTYLE @@ -80,11 +83,11 @@ static PyObject *bpy_script_paths(PyObject *UNUSED(self)) const char *path; path = BLI_get_folder(BLENDER_SYSTEM_SCRIPTS, NULL); - item = PyUnicode_DecodeFSDefault(path ? path : ""); + item = PyC_UnicodeFromByte(path ? path : ""); BLI_assert(item != NULL); PyTuple_SET_ITEM(ret, 0, item); path = BLI_get_folder(BLENDER_USER_SCRIPTS, NULL); - item = PyUnicode_DecodeFSDefault(path ? path : ""); + item = PyC_UnicodeFromByte(path ? path : ""); BLI_assert(item != NULL); PyTuple_SET_ITEM(ret, 1, item); @@ -94,7 +97,7 @@ static PyObject *bpy_script_paths(PyObject *UNUSED(self)) static bool bpy_blend_paths_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src) { PyObject *list = (PyObject *)userdata; - PyObject *item = PyUnicode_DecodeFSDefault(path_src); + PyObject *item = PyC_UnicodeFromByte(path_src); PyList_Append(list, item); Py_DECREF(item); return false; /* never edits the path */ @@ -171,7 +174,7 @@ static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObj if (!path) path = BLI_get_user_folder_notest(folder_id, subdir); - return PyUnicode_DecodeFSDefault(path ? path : ""); + return PyC_UnicodeFromByte(path ? path : ""); } PyDoc_STRVAR(bpy_resource_path_doc, @@ -210,7 +213,7 @@ static PyObject *bpy_resource_path(PyObject *UNUSED(self), PyObject *args, PyObj path = BLI_get_folder_version(folder_id, (major * 100) + minor, false); - return PyUnicode_DecodeFSDefault(path ? path : ""); + return PyC_UnicodeFromByte(path ? path : ""); } PyDoc_STRVAR(bpy_escape_identifier_doc, diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c index 0c13230c365..41ca2d49ed6 100644 --- a/source/blender/python/intern/bpy_app_handlers.c +++ b/source/blender/python/intern/bpy_app_handlers.c @@ -49,6 +49,7 @@ static PyStructSequence_Field app_cb_info_fields[] = { {(char *)"render_pre", (char *)"Callback list - on render (before)"}, {(char *)"render_post", (char *)"Callback list - on render (after)"}, {(char *)"render_stats", (char *)"Callback list - on printing render statistics"}, + {(char *)"render_init", (char *)"Callback list - on initialization of a render job"}, {(char *)"render_complete", (char *)"Callback list - on completion of render job"}, {(char *)"render_cancel", (char *)"Callback list - on canceling a render job"}, {(char *)"load_pre", (char *)"Callback list - on loading a new blend file (before)"}, @@ -59,6 +60,7 @@ static PyStructSequence_Field app_cb_info_fields[] = { {(char *)"scene_update_post", (char *)"Callback list - on updating the scenes data (after)"}, {(char *)"game_pre", (char *)"Callback list - on starting the game engine"}, {(char *)"game_post", (char *)"Callback list - on ending the game engine"}, + {(char *)"version_update", (char *)"Callback list - on ending the versioning code"}, /* sets the permanent tag */ # define APP_CB_OTHER_FIELDS 1 diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 2c526601fcd..1e97d7aeada 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -58,7 +58,7 @@ #include "BKE_report.h" #include "BKE_context.h" -/* so operators called can spawn threads which aquire the GIL */ +/* so operators called can spawn threads which acquire the GIL */ #define BPY_RELEASE_GIL diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 440af035bcd..a24f73c8f17 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -604,18 +604,34 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) #ifdef USE_MATHUTILS int subtype, totdim; int len; - bool is_thick; const int flag = RNA_property_flag(prop); + const int type = RNA_property_type(prop); + const bool is_thick = (flag & PROP_THICK_WRAP) != 0; /* disallow dynamic sized arrays to be wrapped since the size could change * to a size mathutils does not support */ - if ((RNA_property_type(prop) != PROP_FLOAT) || (flag & PROP_DYNAMIC)) + if (flag & PROP_DYNAMIC) { return NULL; + } len = RNA_property_array_length(ptr, prop); + if (type == PROP_FLOAT) { + /* pass */ + } + else if (type == PROP_INT) { + if (is_thick) { + goto thick_wrap_slice; + } + else { + return NULL; + } + } + else { + return NULL; + } + subtype = RNA_property_subtype(prop); totdim = RNA_property_array_dimension(ptr, prop, NULL); - is_thick = (flag & PROP_THICK_WRAP) != 0; if (totdim == 1 || (totdim == 2 && subtype == PROP_MATRIX)) { if (!is_thick) @@ -712,6 +728,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) if (is_thick) { /* this is an array we cant reference (since its not thin wrappable) * and cannot be coerced into a mathutils type, so return as a list */ +thick_wrap_slice: ret = pyrna_prop_array_subscript_slice(NULL, ptr, prop, 0, len, len); } else { @@ -1363,7 +1380,7 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) if (subtype == PROP_BYTESTRING) { ret = PyBytes_FromStringAndSize(buf, buf_len); } - else if (ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { + else if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { ret = PyC_UnicodeFromByteAndSize(buf, buf_len); } else { @@ -1629,7 +1646,7 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb /* Unicode String */ #ifdef USE_STRING_COERCE PyObject *value_coerce = NULL; - if (ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { + if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { /* TODO, get size */ param = PyC_UnicodeAsByte(value, &value_coerce); } @@ -2312,12 +2329,11 @@ static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, Po int count, totdim; PyObject *tuple; - PYRNA_PROP_CHECK_OBJ((BPy_PropertyRNA *)self); + /* isn't needed, internal use only */ + // PYRNA_PROP_CHECK_OBJ((BPy_PropertyRNA *)self); tuple = PyTuple_New(stop - start); - /* PYRNA_PROP_CHECK_OBJ(self); isn't needed, internal use only */ - totdim = RNA_property_array_dimension(ptr, prop, NULL); if (totdim > 1) { @@ -4894,7 +4910,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat if (subtype == PROP_BYTESTRING) { ret = PyBytes_FromString(data_ch); } - else if (ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { + else if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { ret = PyC_UnicodeFromByte(data_ch); } else { diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c index 5d8252d3c72..f6d124938a4 100644 --- a/source/blender/python/mathutils/mathutils_Euler.c +++ b/source/blender/python/mathutils/mathutils_Euler.c @@ -83,14 +83,23 @@ static const char *euler_order_str(EulerObject *self) short euler_order_from_string(const char *str, const char *error_prefix) { if ((str[0] && str[1] && str[2] && str[3] == '\0')) { + +#ifdef __LITTLE_ENDIAN__ +# define MAKE_ID3(a, b, c) (((a)) | ((b) << 8) | ((c) << 16)) +#else +# define MAKE_ID3(a, b, c) (((a) << 24) | ((b) << 16) | ((c) << 8)) +#endif + switch (*((PY_INT32_T *)str)) { - case 'X' | 'Y' << 8 | 'Z' << 16: return EULER_ORDER_XYZ; - case 'X' | 'Z' << 8 | 'Y' << 16: return EULER_ORDER_XZY; - case 'Y' | 'X' << 8 | 'Z' << 16: return EULER_ORDER_YXZ; - case 'Y' | 'Z' << 8 | 'X' << 16: return EULER_ORDER_YZX; - case 'Z' | 'X' << 8 | 'Y' << 16: return EULER_ORDER_ZXY; - case 'Z' | 'Y' << 8 | 'X' << 16: return EULER_ORDER_ZYX; + case MAKE_ID3('X', 'Y', 'Z'): return EULER_ORDER_XYZ; + case MAKE_ID3('X', 'Z', 'Y'): return EULER_ORDER_XZY; + case MAKE_ID3('Y', 'X', 'Z'): return EULER_ORDER_YXZ; + case MAKE_ID3('Y', 'Z', 'X'): return EULER_ORDER_YZX; + case MAKE_ID3('Z', 'X', 'Y'): return EULER_ORDER_ZXY; + case MAKE_ID3('Z', 'Y', 'X'): return EULER_ORDER_ZYX; } + +#undef MAKE_ID3 } PyErr_Format(PyExc_ValueError, @@ -203,7 +212,7 @@ static PyObject *Euler_rotate_axis(EulerObject *self, PyObject *args) return NULL; } - if (!(ELEM3(axis, 'X', 'Y', 'Z'))) { + if (!(ELEM(axis, 'X', 'Y', 'Z'))) { PyErr_SetString(PyExc_ValueError, "Euler.rotate_axis(): " "expected axis to be 'X', 'Y' or 'Z'"); diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 34564007478..282f29b4934 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -910,56 +910,141 @@ static float matrix_determinant_internal(const MatrixObject *self) } } +static void adjoint_matrix_n(float *mat_dst, const float *mat_src, const unsigned short dim) +{ + /* calculate the classical adjoint */ + switch (dim) { + case 2: + { + adjoint_m2_m2((float (*)[2])mat_dst, (float (*)[2])mat_src); + break; + } + case 3: + { + adjoint_m3_m3((float (*)[3])mat_dst, (float (*)[3])mat_src); + break; + } + case 4: + { + adjoint_m4_m4((float (*)[4])mat_dst, (float (*)[4])mat_src); + break; + } + default: + BLI_assert(0); + } +} + +static void matrix_invert_with_det_n_internal(float *mat_dst, const float *mat_src, const float det, const unsigned short dim) +{ + float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM]; + unsigned short i, j, k; + + BLI_assert(det != 0.0f); + + adjoint_matrix_n(mat, mat_src, dim); + + /* divide by determinant & set values */ + k = 0; + for (i = 0; i < dim; i++) { /* num_col */ + for (j = 0; j < dim; j++) { /* num_row */ + mat_dst[MATRIX_ITEM_INDEX_NUMROW(dim, j, i)] = mat[k++] / det; + } + } +} + /** - * \param r_mat can be from ``self->matrix`` or not. */ + * \param r_mat can be from ``self->matrix`` or not. + */ static bool matrix_invert_internal(const MatrixObject *self, float *r_mat) { float det; - + BLI_assert(self->num_col == self->num_row); det = matrix_determinant_internal(self); if (det != 0.0f) { - float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM]; - int x, y, z; + matrix_invert_with_det_n_internal(r_mat, self->matrix, det, self->num_col); + return true; + } + else { + return false; + } +} + +/** + * Similar to ``matrix_invert_internal`` but should never error. + * \param r_mat can be from ``self->matrix`` or not. + */ +static void matrix_invert_safe_internal(const MatrixObject *self, float *r_mat) +{ + float det; + float *in_mat = self->matrix; + BLI_assert(self->num_col == self->num_row); + det = matrix_determinant_internal(self); + + if (det == 0.0f) { + const float eps = PSEUDOINVERSE_EPSILON; + + /* We will copy self->matrix into r_mat (if needed), and modify it in place to add diagonal epsilon. */ + in_mat = r_mat; - /* calculate the classical adjoint */ switch (self->num_col) { case 2: { - adjoint_m2_m2((float (*)[2])mat, (float (*)[2])self->matrix); + float (*mat)[2] = (float (*)[2])in_mat; + + if (in_mat != self->matrix) { + copy_m2_m2(mat, (float (*)[2])self->matrix); + } + mat[0][0] += eps; + mat[1][1] += eps; + + if (UNLIKELY((det = determinant_m2(mat[0][0], mat[0][1], mat[1][0], mat[1][1])) == 0.0f)) { + unit_m2(mat); + det = 1.0f; + } break; } case 3: { - adjoint_m3_m3((float (*)[3])mat, (float (*)[3])self->matrix); + float (*mat)[3] = (float (*)[3])in_mat; + + if (in_mat != self->matrix) { + copy_m3_m3(mat, (float (*)[3])self->matrix); + } + mat[0][0] += eps; + mat[1][1] += eps; + mat[2][2] += eps; + + if (UNLIKELY((det = determinant_m3_array(mat)) == 0.0f)) { + unit_m3(mat); + det = 1.0f; + } break; } case 4: { - adjoint_m4_m4((float (*)[4])mat, (float (*)[4])self->matrix); + float (*mat)[4] = (float (*)[4])in_mat; + + if (in_mat != self->matrix) { + copy_m4_m4(mat, (float (*)[4])self->matrix); + } + mat[0][0] += eps; + mat[1][1] += eps; + mat[2][2] += eps; + mat[3][3] += eps; + + if (UNLIKELY(det = determinant_m4(mat)) == 0.0f) { + unit_m4(mat); + det = 1.0f; + } break; } default: BLI_assert(0); } - /* divide by determinate */ - for (x = 0; x < (self->num_col * self->num_row); x++) { - mat[x] /= det; - } - /* set values */ - z = 0; - for (x = 0; x < self->num_col; x++) { - for (y = 0; y < self->num_row; y++) { - r_mat[MATRIX_ITEM_INDEX(self, y, x)] = mat[z]; - z++; - } - } - - return true; - } - else { - return false; } + + matrix_invert_with_det_n_internal(r_mat, in_mat, det, self->num_col); } @@ -1398,6 +1483,56 @@ static PyObject *Matrix_inverted_noargs(MatrixObject *self) Py_RETURN_NONE; } +PyDoc_STRVAR(Matrix_invert_safe_doc, +".. method:: invert_safe()\n" +"\n" +" Set the matrix to its inverse, will never error.\n" +" If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, to get an invertible one.\n" +" If tweaked matrix is still degenerated, set to the identity matrix instead.\n" +"\n" +" .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n" +); +static PyObject *Matrix_invert_safe(MatrixObject *self) +{ + if (BaseMath_ReadCallback(self) == -1) + return NULL; + + if (matrix_invert_is_compat(self) == false) { + return NULL; + } + + matrix_invert_safe_internal(self, self->matrix); + + (void)BaseMath_WriteCallback(self); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Matrix_inverted_safe_doc, +".. method:: inverted_safe()\n" +"\n" +" Return an inverted copy of the matrix, will never error.\n" +" If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, to get an invertible one.\n" +" If tweaked matrix is still degenerated, return the identity matrix instead.\n" +"\n" +" :return: the inverted matrix.\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *Matrix_inverted_safe(MatrixObject *self) +{ + float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM]; + + if (BaseMath_ReadCallback(self) == -1) + return NULL; + + if (matrix_invert_is_compat(self) == false) { + return NULL; + } + + matrix_invert_safe_internal(self, mat); + + return Matrix_copy_notest(self, mat); +} + /*---------------------------matrix.adjugate() ---------------------*/ PyDoc_STRVAR(Matrix_adjugate_doc, ".. method:: adjugate()\n" @@ -1421,34 +1556,16 @@ static PyObject *Matrix_adjugate(MatrixObject *self) } /* calculate the classical adjoint */ - switch (self->num_col) { - case 2: - { - float mat[2][2]; - adjoint_m2_m2(mat, (float (*)[2])self->matrix); - copy_v4_v4((float *)self->matrix, (float *)mat); - break; - } - case 3: - { - float mat[3][3]; - adjoint_m3_m3(mat, (float (*)[3])self->matrix); - copy_m3_m3((float (*)[3])self->matrix, mat); - break; - } - case 4: - { - float mat[4][4]; - adjoint_m4_m4(mat, (float (*)[4])self->matrix); - copy_m4_m4((float (*)[4])self->matrix, mat); - break; - } - default: - PyErr_Format(PyExc_ValueError, - "Matrix adjugate(d): size (%d) unsupported", - (int)self->num_col); - return NULL; + if (self->num_col <= 4) { + adjoint_matrix_n(self->matrix, self->matrix, self->num_col); } + else { + PyErr_Format(PyExc_ValueError, + "Matrix adjugate(d): size (%d) unsupported", + (int)self->num_col); + return NULL; + } + (void)BaseMath_WriteCallback(self); Py_RETURN_NONE; @@ -1755,10 +1872,7 @@ static PyObject *Matrix_identity(MatrixObject *self) } if (self->num_col == 2) { - MATRIX_ITEM(self, 0, 0) = 1.0f; - MATRIX_ITEM(self, 0, 1) = 0.0f; - MATRIX_ITEM(self, 1, 0) = 0.0f; - MATRIX_ITEM(self, 1, 1) = 1.0f; + unit_m2((float (*)[2])self->matrix); } else if (self->num_col == 3) { unit_m3((float (*)[3])self->matrix); @@ -2559,6 +2673,8 @@ static struct PyMethodDef Matrix_methods[] = { {"normalized", (PyCFunction) Matrix_normalized, METH_NOARGS, Matrix_normalized_doc}, {"invert", (PyCFunction) Matrix_invert, METH_VARARGS, Matrix_invert_doc}, {"inverted", (PyCFunction) Matrix_inverted, METH_VARARGS, Matrix_inverted_doc}, + {"invert_safe", (PyCFunction) Matrix_invert_safe, METH_NOARGS, Matrix_invert_safe_doc}, + {"inverted_safe", (PyCFunction) Matrix_inverted_safe, METH_NOARGS, Matrix_inverted_safe_doc}, {"adjugate", (PyCFunction) Matrix_adjugate, METH_NOARGS, Matrix_adjugate_doc}, {"adjugated", (PyCFunction) Matrix_adjugated, METH_NOARGS, Matrix_adjugated_doc}, {"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc}, diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h index c7fb23d8776..f94af9e540e 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.h +++ b/source/blender/python/mathutils/mathutils_Matrix.h @@ -41,6 +41,7 @@ extern PyTypeObject matrix_access_Type; # define MATRIX_ITEM_ASSERT(_mat, _row, _col) (void)0 #endif +#define MATRIX_ITEM_INDEX_NUMROW(_totrow, _row, _col) ((_totrow * (_col)) + (_row)) #define MATRIX_ITEM_INDEX(_mat, _row, _col) (MATRIX_ITEM_ASSERT(_mat, _row, _col),(((_mat)->num_row * (_col)) + (_row))) #define MATRIX_ITEM_PTR( _mat, _row, _col) ((_mat)->matrix + MATRIX_ITEM_INDEX(_mat, _row, _col)) #define MATRIX_ITEM( _mat, _row, _col) ((_mat)->matrix [MATRIX_ITEM_INDEX(_mat, _row, _col)]) diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index a719691d5d4..15a9860be0a 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -814,17 +814,20 @@ static PyObject *Vector_orthogonal(VectorObject *self) { float vec[3]; - if (self->size != 3) { + if (self->size > 3) { PyErr_SetString(PyExc_TypeError, "Vector.orthogonal(): " - "Vector must be 3D"); + "Vector must be 3D or 2D"); return NULL; } if (BaseMath_ReadCallback(self) == -1) return NULL; - ortho_v3_v3(vec, self->vec); + if (self->size == 3) + ortho_v3_v3(vec, self->vec); + else + ortho_v2_v2(vec, self->vec); return Vector_CreatePyObject(vec, self->size, Py_NEW, Py_TYPE(self)); } diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index 139764abb00..b4add0fc615 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -229,6 +229,11 @@ static PyObject *M_Geometry_intersect_line_line(PyObject *UNUSED(self), PyObject } result = isect_line_line_v3(v1, v2, v3, v4, i1, i2); + /* The return-code isnt exposed, + * this way we can check know how close the lines are. */ + if (result == 1) { + closest_to_line_v3(i2, i1, v3, v4); + } if (result == 0) { /* colinear */ @@ -597,7 +602,7 @@ static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObjec return NULL; } - if (ELEM4(2, line_a->size, line_b->size, plane_co->size, plane_no->size)) { + if (ELEM(2, line_a->size, line_b->size, plane_co->size, plane_no->size)) { PyErr_SetString(PyExc_ValueError, "geometry.intersect_line_plane(...): " " can't use 2D Vectors"); @@ -654,7 +659,7 @@ static PyObject *M_Geometry_intersect_plane_plane(PyObject *UNUSED(self), PyObje return NULL; } - if (ELEM4(2, plane_a_co->size, plane_a_no->size, plane_b_co->size, plane_b_no->size)) { + if (ELEM(2, plane_a_co->size, plane_a_no->size, plane_b_co->size, plane_b_no->size)) { PyErr_SetString(PyExc_ValueError, "geometry.intersect_plane_plane(...): " " can't use 2D Vectors"); @@ -726,7 +731,7 @@ static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObje return NULL; } - if (ELEM3(2, line_a->size, line_b->size, sphere_co->size)) { + if (ELEM(2, line_a->size, line_b->size, sphere_co->size)) { PyErr_SetString(PyExc_ValueError, "geometry.intersect_line_sphere(...): " " can't use 2D Vectors"); @@ -893,13 +898,69 @@ static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObjec return ret; } +PyDoc_STRVAR(M_Geometry_intersect_point_tri_doc, +".. function:: intersect_point_tri(pt, tri_p1, tri_p2, tri_p3)\n" +"\n" +" Takes 4 vectors: one is the point and the next 3 define the triangle.\n" +"\n" +" :arg pt: Point\n" +" :type pt: :class:`mathutils.Vector`\n" +" :arg tri_p1: First point of the triangle\n" +" :type tri_p1: :class:`mathutils.Vector`\n" +" :arg tri_p2: Second point of the triangle\n" +" :type tri_p2: :class:`mathutils.Vector`\n" +" :arg tri_p3: Third point of the triangle\n" +" :type tri_p3: :class:`mathutils.Vector`\n" +" :return: Point on the triangles plane or None if its outside the triangle\n" +" :rtype: :class:`mathutils.Vector` or None\n" +); +static PyObject *M_Geometry_intersect_point_tri(PyObject *UNUSED(self), PyObject *args) +{ + VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3; + float vi[3]; + + if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_point_tri", + &vector_Type, &pt_vec, + &vector_Type, &tri_p1, + &vector_Type, &tri_p2, + &vector_Type, &tri_p3)) + { + return NULL; + } + + if (BaseMath_ReadCallback(pt_vec) == -1 || + BaseMath_ReadCallback(tri_p1) == -1 || + BaseMath_ReadCallback(tri_p2) == -1 || + BaseMath_ReadCallback(tri_p3) == -1) + { + return NULL; + } + + if (pt_vec->size < 3 || + tri_p1->size < 3 || + tri_p2->size < 3 || + tri_p3->size < 3) + { + PyErr_SetString(PyExc_ValueError, + "One of more of the vector arguments wasn't a 3D vector"); + return NULL; + } + + if (isect_point_tri_v3(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec, vi)) { + return Vector_CreatePyObject(vi, 3, Py_NEW, NULL); + } + else { + Py_RETURN_NONE; + } +} + PyDoc_STRVAR(M_Geometry_intersect_point_tri_2d_doc, ".. function:: intersect_point_tri_2d(pt, tri_p1, tri_p2, tri_p3)\n" "\n" " Takes 4 vectors (using only the x and y coordinates): one is the point and the next 3 define the triangle. Returns 1 if the point is within the triangle, otherwise 0.\n" "\n" " :arg pt: Point\n" -" :type v1: :class:`mathutils.Vector`\n" +" :type pt: :class:`mathutils.Vector`\n" " :arg tri_p1: First point of the triangle\n" " :type tri_p1: :class:`mathutils.Vector`\n" " :arg tri_p2: Second point of the triangle\n" @@ -1021,7 +1082,7 @@ static PyObject *M_Geometry_distance_point_to_plane(PyObject *UNUSED(self), PyOb } plane_from_point_normal_v3(plane, plane_co->vec, plane_no->vec); - return PyFloat_FromDouble(dist_to_plane_v3(pt->vec, plane)); + return PyFloat_FromDouble(dist_signed_to_plane_v3(pt->vec, plane)); } PyDoc_STRVAR(M_Geometry_barycentric_transform_doc, @@ -1053,7 +1114,7 @@ static PyObject *M_Geometry_barycentric_transform(PyObject *UNUSED(self), PyObje VectorObject *vec_t1_src, *vec_t2_src, *vec_t3_src; float vec[3]; - if (!PyArg_ParseTuple(args, "O!O!O!O!O!O!O!:barycentric_transform", + if (!PyArg_ParseTuple(args, "O!O!O!O!O!O!O!::barycentric_transform", &vector_Type, &vec_pt, &vector_Type, &vec_t1_src, &vector_Type, &vec_t2_src, @@ -1089,9 +1150,10 @@ static PyObject *M_Geometry_barycentric_transform(PyObject *UNUSED(self), PyObje 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); + transform_point_by_tri_v3( + vec, vec_pt->vec, + vec_t1_tar->vec, vec_t2_tar->vec, vec_t3_tar->vec, + vec_t1_src->vec, vec_t2_src->vec, vec_t3_src->vec); return Vector_CreatePyObject(vec, 3, Py_NEW, NULL); } @@ -1606,6 +1668,7 @@ static PyObject *M_Geometry_convex_hull_2d(PyObject *UNUSED(self), PyObject *poi static PyMethodDef M_Geometry_methods[] = { {"intersect_ray_tri", (PyCFunction) M_Geometry_intersect_ray_tri, METH_VARARGS, M_Geometry_intersect_ray_tri_doc}, {"intersect_point_line", (PyCFunction) M_Geometry_intersect_point_line, METH_VARARGS, M_Geometry_intersect_point_line_doc}, + {"intersect_point_tri", (PyCFunction) M_Geometry_intersect_point_tri, METH_VARARGS, M_Geometry_intersect_point_tri_doc}, {"intersect_point_tri_2d", (PyCFunction) M_Geometry_intersect_point_tri_2d, METH_VARARGS, M_Geometry_intersect_point_tri_2d_doc}, {"intersect_point_quad_2d", (PyCFunction) M_Geometry_intersect_point_quad_2d, METH_VARARGS, M_Geometry_intersect_point_quad_2d_doc}, {"intersect_line_line", (PyCFunction) M_Geometry_intersect_line_line, METH_VARARGS, M_Geometry_intersect_line_line_doc}, diff --git a/source/blender/render/extern/include/RE_bake.h b/source/blender/render/extern/include/RE_bake.h index 8f2a0e382a4..481da452529 100644 --- a/source/blender/render/extern/include/RE_bake.h +++ b/source/blender/render/extern/include/RE_bake.h @@ -39,7 +39,7 @@ typedef struct BakeImage { struct Image *image; int width; int height; - int offset; + size_t offset; } BakeImage; typedef struct BakeImages { @@ -72,35 +72,35 @@ bool RE_bake_has_engine(struct Render *re); bool RE_bake_engine( struct Render *re, struct Object *object, const BakePixel pixel_array[], - const int num_pixels, const int depth, const ScenePassType pass_type, float result[]); + const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]); /* bake.c */ int RE_pass_depth(const ScenePassType pass_type); bool RE_bake_internal( struct Render *re, struct Object *object, const BakePixel pixel_array[], - const int num_pixels, const int depth, const ScenePassType pass_type, float result[]); + const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]); bool RE_bake_pixels_populate_from_objects( struct Mesh *me_low, BakePixel pixel_array_from[], - BakeHighPolyData highpoly[], const int tot_highpoly, const int num_pixels, const bool is_custom_cage, + BakeHighPolyData highpoly[], const int tot_highpoly, const size_t num_pixels, const bool is_custom_cage, const float cage_extrusion, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage); void RE_bake_pixels_populate( struct Mesh *me, struct BakePixel *pixel_array, - const int num_pixels, const struct BakeImages *bake_images, const char *uv_layer); + const size_t num_pixels, const struct BakeImages *bake_images, const char *uv_layer); -void RE_bake_mask_fill(const BakePixel pixel_array[], const int num_pixels, char *mask); +void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, char *mask); void RE_bake_margin(struct ImBuf *ibuf, char *mask, const int margin); void RE_bake_normal_world_to_object( - const BakePixel pixel_array[], const int num_pixels, const int depth, float result[], + const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], struct Object *ob, const BakeNormalSwizzle normal_swizzle[3]); void RE_bake_normal_world_to_tangent( - const BakePixel pixel_array[], const int num_pixels, const int depth, float result[], + const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], struct Mesh *me, const BakeNormalSwizzle normal_swizzle[3], float mat[4][4]); void RE_bake_normal_world_to_world( - const BakePixel pixel_array[], const int num_pixels, const int depth, float result[], + const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], const BakeNormalSwizzle normal_swizzle[3]); void RE_bake_ibuf_clear(struct Image *image, const bool is_tangent); diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 68ac0cd3073..3b54de4c943 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -194,6 +194,7 @@ void RE_InitState(struct Render *re, struct Render *source, struct RenderData *r struct SceneRenderLayer *srl, int winx, int winy, rcti *disprect); void RE_ChangeResolution(struct Render *re, int winx, int winy, rcti *disprect); +void RE_ChangeModeFlag(struct Render *re, int flag, bool clear); /* set up the viewplane/perspective matrix, three choices */ struct Object *RE_GetCamera(struct Render *re); /* return camera override if set */ @@ -234,6 +235,7 @@ void RE_BlenderAnim(struct Render *re, struct Main *bmain, struct Scene *scene, 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); +void RE_RenderFreestyleExternal(struct Render *re); #endif /* error reporting */ diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 536a2b8a85f..b87b1e6f367 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -595,7 +595,9 @@ typedef struct LampRen { float imat[3][3]; float spottexfac; float sh_invcampos[3], sh_zfac; /* sh_= spothalo */ - + + float lampmat[4][4]; /* worls space lamp matrix, used for scene rotation */ + float mat[3][3]; /* 3x3 part from lampmat x viewmat */ float area[8][3], areasize; diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c index f2793a9bc5b..15634c93491 100644 --- a/source/blender/render/intern/source/bake.c +++ b/source/blender/render/intern/source/bake.c @@ -174,7 +174,7 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua /* only do AO for a full bake (and obviously AO bakes) * AO for light bakes is a leftover and might not be needed */ - if (ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT)) + if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT)) shade_samples_do_AO(ssamp); if (shi->mat->nodetree && shi->mat->use_nodes) { @@ -303,7 +303,7 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua rgb_float_to_uchar(col, shr.combined); } - if (ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) { + if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) { col[3] = FTOCHAR(shr.alpha); } else { diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c index efa8c9b98f4..90deac2de32 100644 --- a/source/blender/render/intern/source/bake_api.c +++ b/source/blender/render/intern/source/bake_api.c @@ -120,7 +120,7 @@ static void store_bake_pixel(void *handle, int x, int y, float u, float v) BakePixel *pixel; const int width = bd->bk_image->width; - const int offset = bd->bk_image->offset; + const size_t offset = bd->bk_image->offset; const int i = offset + y * width + x; pixel = &bd->pixel_array[i]; @@ -134,9 +134,9 @@ static void store_bake_pixel(void *handle, int x, int y, float u, float v) pixel->dv_dy = bd->dv_dy; } -void RE_bake_mask_fill(const BakePixel pixel_array[], const int num_pixels, char *mask) +void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, char *mask) { - int i; + size_t i; if (!mask) return; @@ -356,7 +356,7 @@ static void mesh_calc_tri_tessface( MFace *mface; MVert *mvert; TSpace *tspace; - float *precomputed_normals; + float *precomputed_normals = NULL; bool calculate_normal; mface = CustomData_get_layer(&me->fdata, CD_MFACE); @@ -379,7 +379,7 @@ static void mesh_calc_tri_tessface( p_id = -1; for (i = 0; i < me->totface; i++) { MFace *mf = &mface[i]; - TSpace *ts = &tspace[i * 4]; + TSpace *ts = tangent ? &tspace[i * 4] : NULL; p_id++; @@ -438,10 +438,10 @@ static void mesh_calc_tri_tessface( bool RE_bake_pixels_populate_from_objects( struct Mesh *me_low, BakePixel pixel_array_from[], - BakeHighPolyData highpoly[], const int tot_highpoly, const int num_pixels, const bool is_custom_cage, + BakeHighPolyData highpoly[], const int tot_highpoly, const size_t num_pixels, const bool is_custom_cage, const float cage_extrusion, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage) { - int i; + size_t i; int primitive_id; float u, v; float imat_low [4][4]; @@ -461,7 +461,7 @@ bool RE_bake_pixels_populate_from_objects( tris_high = MEM_callocN(sizeof(TriTessFace *) * tot_highpoly, "MVerts Highpoly Mesh Array"); /* assume all highpoly tessfaces are triangles */ - dm_highpoly = MEM_callocN(sizeof(DerivedMesh *) * tot_highpoly, "Highpoly Derived Meshes"); + dm_highpoly = MEM_mallocN(sizeof(DerivedMesh *) * tot_highpoly, "Highpoly Derived Meshes"); treeData = MEM_callocN(sizeof(BVHTreeFromMesh) * tot_highpoly, "Highpoly BVH Trees"); if (!is_cage) { @@ -594,11 +594,11 @@ static void bake_differentials(BakeDataZSpan *bd, const float *uv1, const float void RE_bake_pixels_populate( Mesh *me, BakePixel pixel_array[], - const int num_pixels, const BakeImages *bake_images, const char *uv_layer) + const size_t num_pixels, const BakeImages *bake_images, const char *uv_layer) { BakeDataZSpan bd; - int i, a; - int p_id; + size_t i; + int a, p_id; MTFace *mtface; MFace *mface; @@ -725,11 +725,11 @@ static void normal_compress(float out[3], const float in[3], const BakeNormalSwi * This function converts an object space normal map to a tangent space normal map for a given low poly mesh */ void RE_bake_normal_world_to_tangent( - const BakePixel pixel_array[], const int num_pixels, const int depth, + const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], Mesh *me, const BakeNormalSwizzle normal_swizzle[3], float mat[4][4]) { - int i; + size_t i; TriTessFace *triangles; @@ -756,7 +756,7 @@ void RE_bake_normal_world_to_tangent( float tsm[3][3]; /* tangent space matrix */ float itsm[3][3]; - int offset; + size_t offset; float nor[3]; /* texture normal */ bool is_smooth; @@ -834,16 +834,16 @@ void RE_bake_normal_world_to_tangent( } void RE_bake_normal_world_to_object( - const BakePixel pixel_array[], const int num_pixels, const int depth, + const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], struct Object *ob, const BakeNormalSwizzle normal_swizzle[3]) { - int i; + size_t i; float iobmat[4][4]; invert_m4_m4(iobmat, ob->obmat); for (i = 0; i < num_pixels; i++) { - int offset; + size_t offset; float nor[3]; if (pixel_array[i].primitive_id == -1) @@ -852,7 +852,8 @@ void RE_bake_normal_world_to_object( offset = i * depth; normal_uncompress(nor, &result[offset]); - mul_m4_v3(iobmat, nor); + /* rotates only without translation */ + mul_mat3_m4_v3(iobmat, nor); normalize_v3(nor); /* save back the values */ @@ -861,13 +862,13 @@ void RE_bake_normal_world_to_object( } void RE_bake_normal_world_to_world( - const BakePixel pixel_array[], const int num_pixels, const int depth, + const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], const BakeNormalSwizzle normal_swizzle[3]) { - int i; + size_t i; for (i = 0; i < num_pixels; i++) { - int offset; + size_t offset; float nor[3]; if (pixel_array[i].primitive_id == -1) @@ -907,12 +908,12 @@ void RE_bake_ibuf_clear(Image *image, const bool is_tangent) /** * not the real UV, but the internal per-face UV instead * I'm using it to test if everything is correct */ -static bool bake_uv(const BakePixel pixel_array[], const int num_pixels, const int depth, float result[]) +static bool bake_uv(const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[]) { - int i; + size_t i; for (i=0; i < num_pixels; i++) { - int offset = i * depth; + size_t offset = i * depth; copy_v2_v2(&result[offset], pixel_array[i].uv); } @@ -921,7 +922,7 @@ static bool bake_uv(const BakePixel pixel_array[], const int num_pixels, const i bool RE_bake_internal( Render *UNUSED(re), Object *UNUSED(object), const BakePixel pixel_array[], - const int num_pixels, const int depth, const ScenePassType pass_type, float result[]) + const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]) { switch (pass_type) { case SCE_PASS_UV: diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 36fd1b2d6af..e6f054583b1 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -2930,8 +2930,7 @@ static struct edgesort *make_mesh_edge_lookup(DerivedMesh *dm, int *totedgesort) /* make sorted table with edges and face indices in it */ for (a= totface, mf= mface; a>0; a--, mf++) { - if (mf->v4) totedge+=4; - else if (mf->v3) totedge+=3; + totedge += mf->v4 ? 4 : 3; } if (totedge==0) @@ -2946,8 +2945,9 @@ static struct edgesort *make_mesh_edge_lookup(DerivedMesh *dm, int *totedgesort) to_edgesort(ed++, 2, 3, mf->v3, mf->v4, a); to_edgesort(ed++, 3, 0, mf->v4, mf->v1, a); } - else if (mf->v3) + else { to_edgesort(ed++, 2, 3, mf->v3, mf->v1, a); + } } qsort(edsort, totedge, sizeof(struct edgesort), vergedgesort); @@ -3650,6 +3650,7 @@ static GroupObject *add_render_lamp(Render *re, Object *ob) mul_m4_m4m4(mat, re->viewmat, ob->obmat); invert_m4_m4(ob->imat, mat); + copy_m4_m4(lar->lampmat, ob->obmat); copy_m3_m4(lar->mat, mat); copy_m3_m4(lar->imat, ob->imat); @@ -3704,8 +3705,8 @@ static GroupObject *add_render_lamp(Render *re, Object *ob) /* Annoying, lamp UI does this, but the UI might not have been used? - add here too. * make sure this matches buttons_shading.c's logic */ - if (ELEM4(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY)) - if (ELEM3(la->type, LA_SPOT, LA_SUN, LA_LOCAL)) + if (ELEM(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY)) + if (ELEM(la->type, LA_SPOT, LA_SUN, LA_LOCAL)) if (la->ray_samp_method == LA_SAMP_CONSTANT) la->ray_samp_method = LA_SAMP_HALTON; lar->ray_samp_method= la->ray_samp_method; @@ -4546,8 +4547,7 @@ static void set_dupli_tex_mat(Render *re, ObjectInstanceRen *obi, DupliObject *d obi->duplitexmat= BLI_memarena_alloc(re->memArena, sizeof(float)*4*4); invert_m4_m4(imat, dob->mat); - mul_serie_m4(obi->duplitexmat, re->viewmat, omat, imat, re->viewinv, - NULL, NULL, NULL, NULL); + mul_m4_series(obi->duplitexmat, re->viewmat, omat, imat, re->viewinv); } copy_v3_v3(obi->dupliorco, dob->orco); @@ -4791,13 +4791,12 @@ static int allow_render_object(Render *re, Object *ob, int nolamps, int onlysele { if (is_object_hidden(re, ob)) return 0; - - /* override not showing object when duplis are used with particles */ - if (ob->transflag & OB_DUPLIPARTS) { - /* pass */ /* let particle system(s) handle showing vs. not showing */ - } - else if ((ob->transflag & OB_DUPLI) && !(ob->transflag & OB_DUPLIFRAMES)) { - return 0; + + /* Only handle dupli-hiding here if there is no particle systems. Else, let those handle show/noshow. */ + if (!ob->particlesystem.first) { + if ((ob->transflag & OB_DUPLI) && !(ob->transflag & OB_DUPLIFRAMES)) { + return 0; + } } /* don't add non-basic meta objects, ends up having renderobjects with no geometry */ @@ -4832,7 +4831,7 @@ static int allow_render_dupli_instance(Render *UNUSED(re), DupliObject *dob, Obj } for (psys=obd->particlesystem.first; psys; psys=psys->next) - if (!ELEM5(psys->part->ren_as, PART_DRAW_BB, PART_DRAW_LINE, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)) + if (!ELEM(psys->part->ren_as, PART_DRAW_BB, PART_DRAW_LINE, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)) return 0; /* don't allow lamp, animated duplis, or radio render */ @@ -5834,8 +5833,8 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, Object *camera; float mat[4][4]; float amb[3]; - const short onlyselected= !ELEM5(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO, RE_BAKE_VERTEX_COLORS); - const short nolamps= ELEM5(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS); + const short onlyselected= !ELEM(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO, RE_BAKE_VERTEX_COLORS); + const short nolamps= ELEM(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS); re->main= bmain; re->scene= scene; @@ -5859,7 +5858,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, if (type==RE_BAKE_VERTEX_COLORS) re->flag |= R_NEED_VCOL; - if (!actob && ELEM6(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS)) { + if (!actob && ELEM(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS)) { re->r.mode &= ~R_SHADOW; re->r.mode &= ~R_RAYTRACE; } diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c index 28b29261e4e..06be00a5a5e 100644 --- a/source/blender/render/intern/source/envmap.c +++ b/source/blender/render/intern/source/envmap.c @@ -329,9 +329,9 @@ void env_rotate_scene(Render *re, float mat[4][4], int do_rotate) /* copy from add_render_lamp */ if (do_rotate == 1) - mul_m4_m4m4(tmpmat, re->viewmat, go->ob->obmat); + mul_m4_m4m4(tmpmat, re->viewmat, lar->lampmat); else - mul_m4_m4m4(tmpmat, re->viewmat_orig, go->ob->obmat); + mul_m4_m4m4(tmpmat, re->viewmat_orig, lar->lampmat); invert_m4_m4(go->ob->imat, tmpmat); copy_m3_m4(lar->mat, tmpmat); diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 58e3038682c..888f1330373 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -425,7 +425,7 @@ bool RE_bake_has_engine(Render *re) bool RE_bake_engine( Render *re, Object *object, const BakePixel pixel_array[], - const int num_pixels, const int depth, + const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]) { RenderEngineType *type = RE_engines_find(re->r.engine); @@ -454,8 +454,8 @@ bool RE_bake_engine( engine->resolution_y = re->winy; RE_parts_init(re, false); - engine->tile_x = re->partx; - engine->tile_y = re->party; + engine->tile_x = re->r.tilex; + engine->tile_y = re->r.tiley; /* update is only called so we create the engine.session */ if (type->update) @@ -676,6 +676,11 @@ int RE_engine_render(Render *re, int do_all) if (BKE_reports_contain(re->reports, RPT_ERROR)) G.is_break = true; +#ifdef WITH_FREESTYLE + if (re->r.mode & R_EDGE_FRS) + RE_RenderFreestyleExternal(re); +#endif + return 1; } diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c index 7d4b70cea15..12701099e18 100644 --- a/source/blender/render/intern/source/imagetexture.c +++ b/source/blender/render/intern/source/imagetexture.c @@ -791,176 +791,39 @@ static void area_sample(TexResult *texr, ImBuf *ibuf, float fx, float fy, afdata texr->ta = texr->talpha ? texr->ta*xsd : (clip ? cw*xsd : 1.f); } -/* table of (exp(ar) - exp(a)) / (1 - exp(a)) for r in range [0, 1] and a = -2 - * used instead of actual gaussian, otherwise at high texture magnifications circular artifacts are visible */ -#define EWA_MAXIDX 255 -static const float EWA_WTS[EWA_MAXIDX + 1] = { - 1.f, 0.990965f, 0.982f, 0.973105f, 0.96428f, 0.955524f, 0.946836f, 0.938216f, 0.929664f, - 0.921178f, 0.912759f, 0.904405f, 0.896117f, 0.887893f, 0.879734f, 0.871638f, 0.863605f, - 0.855636f, 0.847728f, 0.839883f, 0.832098f, 0.824375f, 0.816712f, 0.809108f, 0.801564f, - 0.794079f, 0.786653f, 0.779284f, 0.771974f, 0.76472f, 0.757523f, 0.750382f, 0.743297f, - 0.736267f, 0.729292f, 0.722372f, 0.715505f, 0.708693f, 0.701933f, 0.695227f, 0.688572f, - 0.68197f, 0.67542f, 0.66892f, 0.662471f, 0.656073f, 0.649725f, 0.643426f, 0.637176f, - 0.630976f, 0.624824f, 0.618719f, 0.612663f, 0.606654f, 0.600691f, 0.594776f, 0.588906f, - 0.583083f, 0.577305f, 0.571572f, 0.565883f, 0.56024f, 0.55464f, 0.549084f, 0.543572f, - 0.538102f, 0.532676f, 0.527291f, 0.521949f, 0.516649f, 0.511389f, 0.506171f, 0.500994f, - 0.495857f, 0.490761f, 0.485704f, 0.480687f, 0.475709f, 0.470769f, 0.465869f, 0.461006f, - 0.456182f, 0.451395f, 0.446646f, 0.441934f, 0.437258f, 0.432619f, 0.428017f, 0.42345f, - 0.418919f, 0.414424f, 0.409963f, 0.405538f, 0.401147f, 0.39679f, 0.392467f, 0.388178f, - 0.383923f, 0.379701f, 0.375511f, 0.371355f, 0.367231f, 0.363139f, 0.359079f, 0.355051f, - 0.351055f, 0.347089f, 0.343155f, 0.339251f, 0.335378f, 0.331535f, 0.327722f, 0.323939f, - 0.320186f, 0.316461f, 0.312766f, 0.3091f, 0.305462f, 0.301853f, 0.298272f, 0.294719f, - 0.291194f, 0.287696f, 0.284226f, 0.280782f, 0.277366f, 0.273976f, 0.270613f, 0.267276f, - 0.263965f, 0.26068f, 0.257421f, 0.254187f, 0.250979f, 0.247795f, 0.244636f, 0.241502f, - 0.238393f, 0.235308f, 0.232246f, 0.229209f, 0.226196f, 0.223206f, 0.220239f, 0.217296f, - 0.214375f, 0.211478f, 0.208603f, 0.20575f, 0.20292f, 0.200112f, 0.197326f, 0.194562f, - 0.191819f, 0.189097f, 0.186397f, 0.183718f, 0.18106f, 0.178423f, 0.175806f, 0.17321f, - 0.170634f, 0.168078f, 0.165542f, 0.163026f, 0.16053f, 0.158053f, 0.155595f, 0.153157f, - 0.150738f, 0.148337f, 0.145955f, 0.143592f, 0.141248f, 0.138921f, 0.136613f, 0.134323f, - 0.132051f, 0.129797f, 0.12756f, 0.125341f, 0.123139f, 0.120954f, 0.118786f, 0.116635f, - 0.114501f, 0.112384f, 0.110283f, 0.108199f, 0.106131f, 0.104079f, 0.102043f, 0.100023f, - 0.0980186f, 0.09603f, 0.094057f, 0.0920994f, 0.0901571f, 0.08823f, 0.0863179f, 0.0844208f, - 0.0825384f, 0.0806708f, 0.0788178f, 0.0769792f, 0.0751551f, 0.0733451f, 0.0715493f, 0.0697676f, - 0.0679997f, 0.0662457f, 0.0645054f, 0.0627786f, 0.0610654f, 0.0593655f, 0.0576789f, 0.0560055f, - 0.0543452f, 0.0526979f, 0.0510634f, 0.0494416f, 0.0478326f, 0.0462361f, 0.0446521f, 0.0430805f, - 0.0415211f, 0.039974f, 0.0384389f, 0.0369158f, 0.0354046f, 0.0339052f, 0.0324175f, 0.0309415f, - 0.029477f, 0.0280239f, 0.0265822f, 0.0251517f, 0.0237324f, 0.0223242f, 0.020927f, 0.0195408f, - 0.0181653f, 0.0168006f, 0.0154466f, 0.0141031f, 0.0127701f, 0.0114476f, 0.0101354f, 0.00883339f, - 0.00754159f, 0.00625989f, 0.00498819f, 0.00372644f, 0.00247454f, 0.00123242f, 0.f -}; - /* test if a float value is 'nan' * there is a C99 function for this: isnan(), but blender seems to use C90 (according to gcc warns), * and may not be supported by other compilers either */ +/* TODO(sergey): Consider using isnan(), it's used in the other areas. */ #ifndef ISNAN -#define ISNAN(x) ((x) != (x)) +# define ISNAN(x) ((x) != (x)) #endif -//static int ISNAN(float x) { return (x != x); } -static void radangle2imp(float a2, float b2, float th, float *A, float *B, float *C, float *F) -{ - float ct2 = cosf(th); - const float st2 = 1.0f - ct2 * ct2; /* <- sin(th)^2 */ - ct2 *= ct2; - *A = a2*st2 + b2*ct2; - *B = (b2 - a2)*sinf(2.f*th); - *C = a2*ct2 + b2*st2; - *F = a2*b2; -} +typedef struct ReadEWAData { + ImBuf *ibuf; + afdata_t *AFD; +} ReadEWAData; -/* all tests here are done to make sure possible overflows are hopefully minimized */ -static void imp2radangle(float A, float B, float C, float F, float *a, float *b, float *th, float *ecc) +static void ewa_read_pixel_cb(void *userdata, int x, int y, float result[4]) { - if (F <= 1e-5f) { /* use arbitrary major radius, zero minor, infinite eccentricity */ - *a = sqrtf(A > C ? A : C); - *b = 0.f; - *ecc = 1e10f; - *th = 0.5f*(atan2f(B, A - C) + (float)M_PI); - } - else { - const float AmC = A - C, ApC = A + C, F2 = F*2.f; - const float r = sqrtf(AmC*AmC + B*B); - float d = ApC - r; - *a = (d <= 0.f) ? sqrtf(A > C ? A : C) : sqrtf(F2 / d); - d = ApC + r; - if (d <= 0.f) { - *b = 0.f; - *ecc = 1e10f; - } - else { - *b = sqrtf(F2 / d); - *ecc = *a / *b; - } - /* incr theta by 0.5*pi (angle of major axis) */ - *th = 0.5f*(atan2f(B, AmC) + (float)M_PI); - } + ReadEWAData *data = (ReadEWAData *) userdata; + ibuf_get_color_clip(result, data->ibuf, x, y, data->AFD->extflag); } static void ewa_eval(TexResult *texr, ImBuf *ibuf, float fx, float fy, afdata_t *AFD) { - /* scaling dxt/dyt by full resolution can cause overflow because of huge A/B/C and esp. F values, - * scaling by aspect ratio alone does the opposite, so try something in between instead... */ - const float ff2 = ibuf->x, ff = sqrtf(ff2), q = ibuf->y / ff; - const float Ux = AFD->dxt[0]*ff, Vx = AFD->dxt[1]*q, Uy = AFD->dyt[0]*ff, Vy = AFD->dyt[1]*q; - float A = Vx*Vx + Vy*Vy; - float B = -2.f*(Ux*Vx + Uy*Vy); - float C = Ux*Ux + Uy*Uy; - float F = A*C - B*B*0.25f; - float a, b, th, ecc, a2, b2, ue, ve, U0, V0, DDQ, U, ac1, ac2, BU, d; /* TXF alpha: cw = 0.f; */ - int u, v, u1, u2, v1, v2; /* TXF alpha: clip = 0; */ - - /* The so-called 'high' quality ewa method simply adds a constant of 1 to both A & C, - * so the ellipse always covers at least some texels. But since the filter is now always larger, - * it also means that everywhere else it's also more blurry then ideally should be the case. - * So instead here the ellipse radii are modified instead whenever either is too low. - * Use a different radius based on interpolation switch, just enough to anti-alias when interpolation is off, - * and slightly larger to make result a bit smoother than bilinear interpolation when interpolation is on - * (minimum values: const float rmin = intpol ? 1.f : 0.5f;) */ - const float rmin = (AFD->intpol ? 1.5625f : 0.765625f)/ff2; - imp2radangle(A, B, C, F, &a, &b, &th, &ecc); - if ((b2 = b*b) < rmin) { - if ((a2 = a*a) < rmin) { - B = 0.f; - A = C = rmin; - F = A*C; - } - else { - b2 = rmin; - radangle2imp(a2, b2, th, &A, &B, &C, &F); - } - } - - ue = ff*sqrtf(C); - ve = ff*sqrtf(A); - d = (float)(EWA_MAXIDX + 1) / (F*ff2); - A *= d; - B *= d; - C *= d; - - U0 = fx*ibuf->x; - V0 = fy*ibuf->y; - u1 = (int)(floorf(U0 - ue)); - u2 = (int)(ceilf(U0 + ue)); - v1 = (int)(floorf(V0 - ve)); - v2 = (int)(ceilf(V0 + ve)); - U0 -= 0.5f; - V0 -= 0.5f; - DDQ = 2.f*A; - U = u1 - U0; - ac1 = A*(2.f*U + 1.f); - ac2 = A*U*U; - BU = B*U; + ReadEWAData data; + float uv[2] = {fx, fy}; + data.ibuf = ibuf; + data.AFD = AFD; + BLI_ewa_filter(ibuf->x, ibuf->y, + AFD->intpol != 0, + texr->talpha, + uv, AFD->dxt, AFD->dyt, + ewa_read_pixel_cb, + &data, + &texr->tr); - d = texr->tr = texr->tb = texr->tg = texr->ta = 0.f; - for (v=v1; v<=v2; ++v) { - const float V = v - V0; - float DQ = ac1 + B*V; - float Q = (C*V + BU)*V + ac2; - for (u=u1; u<=u2; ++u) { - if (Q < (float)(EWA_MAXIDX + 1)) { - float tc[4]; - const float wt = EWA_WTS[(Q < 0.f) ? 0 : (unsigned int)Q]; - /*const int out =*/ ibuf_get_color_clip(tc, ibuf, u, v, AFD->extflag); - /* TXF alpha: clip |= out; - * TXF alpha: cw += out ? 0.f : wt; */ - texr->tr += tc[0]*wt; - texr->tg += tc[1]*wt; - texr->tb += tc[2]*wt; - texr->ta += texr->talpha ? tc[3]*wt : 0.f; - d += wt; - } - Q += DQ; - DQ += DDQ; - } - } - - /* d should hopefully never be zero anymore */ - d = 1.f/d; - texr->tr *= d; - texr->tg *= d; - texr->tb *= d; - /* clipping can be ignored if alpha used, texr->ta already includes filtered edge */ - texr->ta = texr->talpha ? texr->ta*d : 1.f; /* TXF alpha (clip ? cw*d : 1.f); */ } static void feline_eval(TexResult *texr, ImBuf *ibuf, float fx, float fy, afdata_t *AFD) @@ -1304,7 +1167,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex const float C = Ux*Ux + Uy*Uy; const float F = A*C - B*B*0.25f; float a, b, th, ecc; - imp2radangle(A, B, C, F, &a, &b, &th, &ecc); + BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc); if (tex->texfilter == TXF_FELINE) { float fProbes; a *= ff; @@ -1408,7 +1271,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex const float C = Ux*Ux + Uy*Uy; const float F = A*C - B*B*0.25f; float a, b, th, ecc, fProbes; - imp2radangle(A, B, C, F, &a, &b, &th, &ecc); + BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc); a *= ff; b *= ff; a = max_ff(a, 1.0f); diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index f0fe5d054f0..0c6341fe9e5 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -45,6 +45,7 @@ #include "BLF_translation.h" +#include "BKE_node.h" #include "BKE_scene.h" @@ -194,14 +195,19 @@ static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr, } /* init material vars */ - /* note, keep this synced with render_types.h */ - memcpy(&shi->r, &shi->mat->r, 23 * sizeof(float)); - shi->har = shi->mat->har; - + shade_input_init_material(shi); + /* render */ shade_input_set_shade_texco(shi); - shade_material_loop(shi, shr); /* todo: nodes */ - + + if (shi->mat->nodetree && shi->mat->use_nodes) { + ntreeShaderExecTree(shi->mat->nodetree, shi, shr); + shi->mat = vlr->mat; /* shi->mat is being set in nodetree */ + } + else { + shade_material_loop(shi, shr); + } + copy_v3_v3(rad, shr->combined); } diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 2131b820bd4..8469d8c74f0 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -728,6 +728,7 @@ static void render_result_rescale(Render *re) void RE_ChangeResolution(Render *re, int winx, int winy, rcti *disprect) { re_init_resolution(re, NULL, winx, winy, disprect); + RE_parts_clamp(re); if (re->result) { BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); @@ -736,6 +737,20 @@ void RE_ChangeResolution(Render *re, int winx, int winy, rcti *disprect) } } +/* TODO(sergey): This is a bit hackish, used to temporary disable freestyle when + * doing viewport render. Needs some better integration of BI viewport rendering + * into the pipeline. + */ +void RE_ChangeModeFlag(Render *re, int flag, bool clear) +{ + if (clear) { + re->r.mode &= ~flag; + } + else { + re->r.mode |= flag; + } +} + /* update some variables that can be animated, and otherwise wouldn't be due to * RenderData getting copied once at the start of animation render */ void render_update_anim_renderdata(Render *re, RenderData *rd) @@ -1713,7 +1728,7 @@ static int composite_needs_render(Scene *sce, int this_scene) if ((sce->r.scemode & R_DOCOMP) == 0) return 1; for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_R_LAYERS) + if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) if (this_scene == 0 || node->id == NULL || node->id == &sce->id) return 1; } @@ -1852,7 +1867,7 @@ static void tag_scenes_for_render(Render *re) /* check for render-layers nodes using other scenes, we tag them LIB_DOIT */ for (node = re->scene->nodetree->nodes.first; node; node = node->next) { node->flag &= ~NODE_TEST; - if (node->type == CMP_NODE_R_LAYERS) { + if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) { if (node->id) { if (!MAIN_VERSION_ATLEAST(re->main, 265, 5)) { if (rlayer_node_uses_alpha(re->scene->nodetree, node)) { @@ -1901,7 +1916,7 @@ static void ntree_render_scenes(Render *re) /* now foreach render-result node tagged we do a full render */ /* results are stored in a way compisitor will find it */ for (node = re->scene->nodetree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_R_LAYERS) { + if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) { if (node->id && node->id != (ID *)re->scene) { if (node->flag & NODE_TEST) { Scene *scene = (Scene *)node->id; @@ -1935,6 +1950,8 @@ static void add_freestyle(Render *re, int render) { SceneRenderLayer *srl, *actsrl; LinkData *link; + Render *r; + const bool do_link = (re->r.mode & R_MBLUR) == 0 || re->i.curblur == re->r.mblur_samples; actsrl = BLI_findlink(&re->r.layers, re->r.actlay); @@ -1951,15 +1968,17 @@ static void add_freestyle(Render *re, int render) FRS_init_stroke_rendering(re); - for (srl= (SceneRenderLayer *)re->r.layers.first; srl; srl= srl->next) { - - link = (LinkData *)MEM_callocN(sizeof(LinkData), "LinkData to Freestyle render"); - BLI_addtail(&re->freestyle_renders, link); - + for (srl = (SceneRenderLayer *)re->r.layers.first; srl; srl = srl->next) { + if (do_link) { + link = (LinkData *)MEM_callocN(sizeof(LinkData), "LinkData to Freestyle render"); + BLI_addtail(&re->freestyle_renders, link); + } if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl) continue; if (FRS_is_freestyle_enabled(srl)) { - link->data = (void *)FRS_do_stroke_rendering(re, srl, render); + r = FRS_do_stroke_rendering(re, srl, render); + if (do_link) + link->data = (void *)r; } } @@ -2183,7 +2202,7 @@ void RE_MergeFullSample(Render *re, Main *bmain, Scene *sce, bNodeTree *ntree) #endif for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_R_LAYERS) { + if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) { Scene *nodescene = (Scene *)node->id; if (nodescene == NULL) nodescene = sce; @@ -2478,7 +2497,7 @@ static bool check_valid_compositing_camera(Scene *scene, Object *camera_override bNode *node = scene->nodetree->nodes.first; while (node) { - if (node->type == CMP_NODE_R_LAYERS) { + if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) { Scene *sce = node->id ? (Scene *)node->id : scene; if (!sce->camera && !BKE_scene_camera_find(sce)) { @@ -2760,6 +2779,8 @@ void RE_SetReports(Render *re, ReportList *reports) void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *srl, Object *camera_override, unsigned int lay_override, int frame, const bool write_still) { + BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT); + /* ugly global still... is to prevent preview events and signal subsurfs etc to make full resol */ G.is_rendering = true; @@ -2806,6 +2827,16 @@ void RE_RenderFreestyleStrokes(Render *re, Main *bmain, Scene *scene, int render } re->result_ok = 1; } + +void RE_RenderFreestyleExternal(Render *re) +{ + if (!re->test_break(re->tbh)) { + RE_Database_FromScene(re, re->main, re->scene, re->lay, 1); + RE_Database_Preprocess(re); + add_freestyle(re, 1); + RE_Database_Free(re); + } +} #endif static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const char *name_override) @@ -2924,6 +2955,8 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri int cfrao = scene->r.cfra; int nfra, totrendered = 0, totskipped = 0; + BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT); + /* do not fully call for each frame, it initializes & pops output window */ if (!render_initialize_from_main(re, &rd, bmain, scene, NULL, camera_override, lay_override, 0, 1)) return; diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index 253f8a1383f..dd14c2495e8 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -3564,7 +3564,7 @@ Material *RE_init_sample_material(Material *orig_mat, Scene *scene) /* depending of material type, strip non-compatible mapping modes */ if (mat->material_type == MA_TYPE_SURFACE) { - if (!ELEM4(mtex->texco, TEXCO_ORCO, TEXCO_OBJECT, TEXCO_GLOB, TEXCO_UV)) { + if (!ELEM(mtex->texco, TEXCO_ORCO, TEXCO_OBJECT, TEXCO_GLOB, TEXCO_UV)) { /* ignore this texture */ mtex->texco = 0; continue; @@ -3573,7 +3573,7 @@ Material *RE_init_sample_material(Material *orig_mat, Scene *scene) mtex->mapto = (mtex->mapto & MAP_COL) | (mtex->mapto & MAP_ALPHA); } else if (mat->material_type == MA_TYPE_VOLUME) { - if (!ELEM3(mtex->texco, TEXCO_OBJECT, TEXCO_ORCO, TEXCO_GLOB)) { + if (!ELEM(mtex->texco, TEXCO_OBJECT, TEXCO_ORCO, TEXCO_GLOB)) { /* ignore */ mtex->texco = 0; continue; diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c index 9d337e542a1..aa420d7e7c8 100644 --- a/source/blender/render/intern/source/shadbuf.c +++ b/source/blender/render/intern/source/shadbuf.c @@ -784,7 +784,7 @@ void makeshadowbuf(Render *re, LampRen *lar) perspective_m4(shb->winmat, -wsize, wsize, -wsize, wsize, shb->d, shb->clipend); mul_m4_m4m4(shb->persmat, shb->winmat, shb->viewmat); - if (ELEM3(lar->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP)) { + if (ELEM(lar->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP)) { shb->totbuf= lar->buffers; /* jitter, weights - not threadsafe! */ diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index ebf88efb50b..427d0eeed11 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -1706,9 +1706,19 @@ static void wrld_exposure_correct(float diff[3]) void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) { + /* Passes which might need to know material color. + * + * It seems to be faster to just calculate material color + * even if the pass doesn't really need it than trying to + * figure out whether color is really needed or not. + */ + const int color_passes = + SCE_PASS_COMBINED | SCE_PASS_RGBA | SCE_PASS_DIFFUSE | SCE_PASS_SPEC | + SCE_PASS_REFLECT | SCE_PASS_NORMAL | SCE_PASS_REFRACT | SCE_PASS_EMIT; + Material *ma= shi->mat; int passflag= shi->passflag; - + memset(shr, 0, sizeof(ShadeResult)); if (!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f; @@ -1723,7 +1733,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0f; /* material color itself */ - if (passflag & (SCE_PASS_COMBINED|SCE_PASS_RGBA)) { + if (passflag & color_passes) { if (ma->mode & (MA_FACETEXTURE)) { shi->r= shi->vcol[0]; shi->g= shi->vcol[1]; diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index fe3af5b840e..d5c4c407bf6 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -499,7 +499,7 @@ static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) { mul_v3_fl(lacol, vol_get_shadow(shi, lar, co)); } - else if (ELEM3(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) { + else if (ELEM(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) { Isect is; if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) { diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 9886d403f74..35b7fb4b9c9 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -151,7 +151,7 @@ typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata); struct wmEventHandler *WM_event_add_ui_handler( const struct bContext *C, ListBase *handlers, wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove, - void *userdata); + void *userdata, const bool accept_dbl_click); void WM_event_remove_ui_handler( ListBase *handlers, wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove, @@ -241,7 +241,8 @@ int WM_operator_call (struct bContext *C, struct wmOperator *op); int WM_operator_call_notest(struct bContext *C, struct wmOperator *op); int WM_operator_repeat (struct bContext *C, struct wmOperator *op); bool WM_operator_repeat_check(const struct bContext *C, struct wmOperator *op); -int WM_operator_name_call (struct bContext *C, const char *opstring, short context, struct PointerRNA *properties); +int WM_operator_name_call_ptr(struct bContext *C, struct wmOperatorType *ot, short context, struct PointerRNA *properties); +int WM_operator_name_call(struct bContext *C, const char *opstring, short context, struct PointerRNA *properties); int WM_operator_call_py(struct bContext *C, struct wmOperatorType *ot, short context, struct PointerRNA *properties, struct ReportList *reports, const bool is_undo); void WM_operator_properties_alloc(struct PointerRNA **ptr, struct IDProperty **properties, const char *opstring); /* used for keymap and macro items */ @@ -343,8 +344,10 @@ void WM_event_print(const struct wmEvent *event); void WM_operator_region_active_win_set(struct bContext *C); /* drag and drop */ -struct wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value); +struct wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags); void WM_event_drag_image(struct wmDrag *, struct ImBuf *, float scale, int sx, int sy); +void WM_drag_free(struct wmDrag *drag); +void WM_drag_free_list(struct ListBase *lb); struct wmDropBox *WM_dropbox_add(ListBase *lb, const char *idname, int (*poll)(struct bContext *, struct wmDrag *, const struct wmEvent *event), void (*copy)(struct wmDrag *, struct wmDropBox *)); @@ -448,6 +451,9 @@ void WM_event_ndof_rotate_get(const struct wmNDOFMotionData *ndof, float float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]); void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]); +float WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]); +bool WM_event_is_tablet(const struct wmEvent *event); + #ifdef __cplusplus } #endif diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h index 9645c95f62b..c6c7314e963 100644 --- a/source/blender/windowmanager/WM_keymap.h +++ b/source/blender/windowmanager/WM_keymap.h @@ -64,6 +64,8 @@ wmKeyMapItem *WM_keymap_add_item(struct wmKeyMap *keymap, const char *idname, in int val, int modifier, int keymodifier); wmKeyMapItem *WM_keymap_add_menu(struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier); +wmKeyMapItem *WM_keymap_add_menu_pie(struct wmKeyMap *keymap, const char *idname, int type, + int val, int modifier, int keymodifier); bool WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi); int WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, const int len); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 9ad1bc97f4d..090d9516f1f 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -128,7 +128,7 @@ struct ImBuf; #define OPTYPE_UNDO 2 /* do undo push after after */ #define OPTYPE_BLOCKING 4 /* let blender grab all input from the WM (X11) */ #define OPTYPE_MACRO 8 -#define OPTYPE_GRAB_POINTER 16 /* */ +#define OPTYPE_GRAB_POINTER 16 /* grabs the cursor and optionally enables continuous cursor wrapping */ #define OPTYPE_PRESET 32 /* show preset menu */ #define OPTYPE_INTERNAL 64 /* some operators are mainly for internal use * and don't make sense to be accessed from the @@ -597,6 +597,12 @@ typedef struct wmReport { #define WM_DRAG_PATH 2 #define WM_DRAG_NAME 3 #define WM_DRAG_VALUE 4 +#define WM_DRAG_COLOR 5 + +typedef enum wmDragFlags { + WM_DRAG_NOP = 0, + WM_DRAG_FREE_DATA = 1, +} wmDragFlags; /* note: structs need not exported? */ @@ -613,6 +619,7 @@ typedef struct wmDrag { int sx, sy; char opname[200]; /* if set, draws operator name*/ + unsigned int flags; } wmDrag; /* dropboxes are like keymaps, part of the screen/area/region definition */ diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 28bddb47778..d05cc572c45 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -462,7 +462,8 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) BLI_freelistN(&wm->queue); BLI_freelistN(&wm->paintcursors); - BLI_freelistN(&wm->drags); + + WM_drag_free_list(&wm->drags); wm_reports_free(wm); diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 2aa177602cb..e5bba9285b4 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -143,7 +143,7 @@ void wm_dropbox_free(void) /* *********************************** */ /* note that the pointer should be valid allocated and not on stack */ -wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value) +wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags) { wmWindowManager *wm = CTX_wm_manager(C); wmDrag *drag = MEM_callocN(sizeof(struct wmDrag), "new drag"); @@ -152,6 +152,7 @@ wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, /* if multiple drags are added, they're drawn as list */ BLI_addtail(&wm->drags, drag); + drag->flags = flags; drag->icon = icon; drag->type = type; if (type == WM_DRAG_PATH) @@ -171,6 +172,22 @@ void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale, int sx, int sy) drag->sy = sy; } +void WM_drag_free(wmDrag *drag) +{ + if ((drag->flags & WM_DRAG_FREE_DATA) && drag->poin) { + MEM_freeN(drag->poin); + } + + MEM_freeN(drag); +} + +void WM_drag_free_list(struct ListBase *lb) +{ + wmDrag *drag; + while ((drag = BLI_pophead(lb))) { + WM_drag_free(drag); + } +} static const char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag, wmEvent *event) { diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 4116bee4a5f..7440570f4a0 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -592,7 +592,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) bScreen *screen = win->screen; ScrArea *sa; ARegion *ar; - int copytex = 0, paintcursor = 1; + int copytex = 0; if (win->drawdata) { glClearColor(0, 0, 0, 0); @@ -639,7 +639,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) wm_triple_copy_textures(win, triple); } - if (paintcursor && wm->paintcursors.first) { + if (wm->paintcursors.first) { for (sa = screen->areabase.first; sa; sa = sa->next) { for (ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->swinid && ar->swinid == screen->subwinactive) { @@ -685,8 +685,6 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) CTX_wm_menu_set(C, ar); ED_region_do_draw(C, ar); CTX_wm_menu_set(C, NULL); - /* when a menu is being drawn, don't do the paint cursors */ - paintcursor = 0; } } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 4b2ec0ef587..ab4b21d5e33 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -111,10 +111,13 @@ void wm_event_free(wmEvent *event) if (event->customdata) { if (event->customdatafree) { /* note: pointer to listbase struct elsewhere */ - if (event->custom == EVT_DATA_LISTBASE) - BLI_freelistN(event->customdata); - else + if (event->custom == EVT_DATA_DRAGDROP) { + ListBase *lb = event->customdata; + WM_drag_free_list(lb); + } + else { MEM_freeN(event->customdata); + } } } @@ -289,7 +292,7 @@ void wm_event_do_notifiers(bContext *C) do_anim = true; } } - if (ELEM5(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) { + if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) { ED_info_stats_clear(win->screen->scene); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL); } @@ -393,13 +396,17 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *eve ARegion *region = CTX_wm_region(C); ARegion *menu = CTX_wm_menu(C); static bool do_wheel_ui = true; - const bool is_wheel = ELEM3(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN); + const bool is_wheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN); int retval; /* UI code doesn't handle return values - it just always returns break. * to make the DBL_CLICK conversion work, we just don't send this to UI, except mouse clicks */ - if (event->type != LEFTMOUSE && event->val == KM_DBL_CLICK) + if (((handler->flag & WM_HANDLER_ACCEPT_DBL_CLICK) == 0) && + (event->type != LEFTMOUSE) && + (event->val == KM_DBL_CLICK)) + { return WM_HANDLER_CONTINUE; + } /* UI is quite aggressive with swallowing events, like scrollwheel */ /* I realize this is not extremely nice code... when UI gets keymaps it can be maybe smarter */ @@ -1261,11 +1268,17 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA /* invokes operator in context */ +int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, short context, PointerRNA *properties) +{ + BLI_assert(ot == WM_operatortype_find(ot->idname, true)); + return wm_operator_call_internal(C, ot, properties, NULL, context, false); +} int WM_operator_name_call(bContext *C, const char *opstring, short context, PointerRNA *properties) { wmOperatorType *ot = WM_operatortype_find(opstring, 0); - if (ot) - return wm_operator_call_internal(C, ot, properties, NULL, context, false); + if (ot) { + return WM_operator_name_call_ptr(C, ot, context, properties); + } return 0; } @@ -1928,17 +1941,17 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers wmDropBox *drop = handler->dropboxes->first; for (; drop; drop = drop->next) { /* other drop custom types allowed */ - if (event->custom == EVT_DATA_LISTBASE) { + if (event->custom == EVT_DATA_DRAGDROP) { ListBase *lb = (ListBase *)event->customdata; wmDrag *drag; for (drag = lb->first; drag; drag = drag->next) { if (drop->poll(C, drag, event)) { - drop->copy(drag, drop); /* free the drags before calling operator */ - BLI_freelistN(event->customdata); + WM_drag_free_list(lb); + event->customdata = NULL; event->custom = 0; @@ -2004,7 +2017,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) if (CTX_wm_window(C) == NULL) return action; - if (!ELEM3(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE, EVENT_NONE) && !ISTIMER(event->type)) { + if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE, EVENT_NONE) && !ISTIMER(event->type)) { /* test for CLICK events */ if (wm_action_not_handled(action)) { @@ -2140,10 +2153,12 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even return; } - if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) + if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) { win->screen->do_draw_drag = true; + } else if (event->type == ESCKEY) { - BLI_freelistN(&wm->drags); + WM_drag_free_list(&wm->drags); + win->screen->do_draw_drag = true; } else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { @@ -2155,7 +2170,7 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even MEM_freeN(event->customdata); } - event->custom = EVT_DATA_LISTBASE; + event->custom = EVT_DATA_DRAGDROP; event->customdata = &wm->drags; event->customdatafree = 1; @@ -2552,7 +2567,7 @@ void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap) wmEventHandler *WM_event_add_ui_handler( const bContext *C, ListBase *handlers, wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove, - void *userdata) + void *userdata, const bool accept_dbl_click) { wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "event ui handler"); handler->ui_handle = ui_handle; @@ -2569,6 +2584,9 @@ wmEventHandler *WM_event_add_ui_handler( handler->ui_menu = NULL; } + if (accept_dbl_click) { + handler->flag |= WM_HANDLER_ACCEPT_DBL_CLICK; + } BLI_addhead(handlers, handler); @@ -2688,7 +2706,7 @@ bool WM_modal_tweak_exit(const wmEvent *event, int tweak_event) else { /* if the initial event wasn't a tweak event then * ignore USER_RELEASECONFIRM setting: see [#26756] */ - if (ELEM3(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) { + if (ELEM(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) { return 1; } } @@ -3398,4 +3416,39 @@ void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]) axis_angle_to_quat(q, axis, angle); } +/* if this is a tablet event, return tablet pressure and set *pen_flip + * to 1 if the eraser tool is being used, 0 otherwise */ +float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2]) +{ + int erasor = 0; + float pressure = 1; + + if (tilt) + zero_v2(tilt); + + if (event->tablet_data) { + wmTabletData *wmtab = event->tablet_data; + + erasor = (wmtab->Active == EVT_TABLET_ERASER); + if (wmtab->Active != EVT_TABLET_NONE) { + pressure = wmtab->Pressure; + if (tilt) { + tilt[0] = wmtab->Xtilt; + tilt[1] = wmtab->Ytilt; + } + } + } + + if (pen_flip) + (*pen_flip) = erasor; + + return pressure; +} + +bool WM_event_is_tablet(const struct wmEvent *event) +{ + return (event->tablet_data) ? true : false; +} + + /** \} */ diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 0bc6442348c..832fef404e3 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -278,11 +278,13 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist) /* in case UserDef was read, we re-initialize all, and do versioning */ static void wm_init_userdef(bContext *C, const bool from_memory) { + Main *bmain = CTX_data_main(C); + /* versioning is here */ UI_init_userdef(); MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024); - sound_init(CTX_data_main(C)); + sound_init(bmain); /* needed so loading a file from the command line respects user-pref [#26156] */ BKE_BIT_TEST_SET(G.fileflags, U.flag & USER_FILENOUI, G_FILE_NO_UI); @@ -295,7 +297,7 @@ static void wm_init_userdef(bContext *C, const bool from_memory) /* avoid re-saving for every small change to our prefs, allow overrides */ if (from_memory) { - UI_init_userdef_factory(); + BLO_update_defaults_userpref_blend(); } /* update tempdir from user preferences */ @@ -457,6 +459,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) #endif /* important to do before NULL'ing the context */ + BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE); BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); if (!G.background) { @@ -648,6 +651,7 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c #endif /* important to do before NULL'ing the context */ + BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE); BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL); diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index c9ef473a442..3e287a3907b 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -74,7 +74,7 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type) wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy); - if (ELEM5(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK, + if (ELEM(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK, WM_GESTURE_CIRCLE, WM_GESTURE_STRAIGHTLINE)) { rcti *rect = MEM_callocN(sizeof(rcti), "gesture rect new"); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index b2c822f501c..6720bf89c77 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -188,6 +188,8 @@ void WM_init(bContext *C, int argc, const char **argv) (void)argv; /* unused */ #endif + ED_spacemacros_init(); + if (!G.background && !wm_start_with_console) GHOST_toggleConsole(3); @@ -236,6 +238,7 @@ void WM_init(bContext *C, int argc, const char **argv) * * unlikely any handlers are set but its possible, * note that recovering the last session does its own callbacks. */ + BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE); BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); } } diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 0163517545f..7b567142979 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -464,6 +464,13 @@ wmKeyMapItem *WM_keymap_add_menu(wmKeyMap *keymap, const char *idname, int type, return kmi; } +wmKeyMapItem *WM_keymap_add_menu_pie(wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier) +{ + wmKeyMapItem *kmi = WM_keymap_add_item(keymap, "WM_OT_call_menu_pie", type, val, modifier, keymodifier); + RNA_string_set(kmi->ptr, "name", idname); + return kmi; +} + bool WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi) { if (BLI_findindex(&keymap->items, kmi) != -1) { @@ -1108,9 +1115,9 @@ int WM_keymap_item_compare(wmKeyMapItem *k1, wmKeyMapItem *k2) if (k1->val != KM_ANY && k2->val != KM_ANY) { /* take click, press, release conflict into account */ - if (k1->val == KM_CLICK && ELEM3(k2->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) + if (k1->val == KM_CLICK && ELEM(k2->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) return 0; - if (k2->val == KM_CLICK && ELEM3(k1->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) + if (k2->val == KM_CLICK && ELEM(k1->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) return 0; if (k1->val != k2->val) return 0; @@ -1414,46 +1421,73 @@ wmKeyMapItem *WM_keymap_item_find_id(wmKeyMap *keymap, int id) /* Needs to be kept up to date with Keymap and Operator naming */ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) { + /* Op types purposely skipped for now: + * BRUSH_OT + * BOID_OT + * BUTTONS_OT + * CONSTRAINT_OT + * DPAINT_OT + * ED_OT + * FLUID_OT + * TEXTURE_OT + * UI_OT + * VIEW2D_OT + * WORLD_OT + */ + wmKeyMap *km = NULL; SpaceLink *sl = CTX_wm_space_data(C); /* Window */ - if (strstr(opname, "WM_OT")) { + if (STRPREFIX(opname, "WM_OT")) { km = WM_keymap_find_all(C, "Window", 0, 0); } - /* Screen */ - else if (strstr(opname, "SCREEN_OT")) { + /* Screen & Render */ + else if (STRPREFIX(opname, "SCREEN_OT") || + STRPREFIX(opname, "RENDER_OT") || + STRPREFIX(opname, "SOUND_OT") || + STRPREFIX(opname, "SCENE_OT")) + { km = WM_keymap_find_all(C, "Screen", 0, 0); } /* Grease Pencil */ - else if (strstr(opname, "GPENCIL_OT")) { + else if (STRPREFIX(opname, "GPENCIL_OT")) { km = WM_keymap_find_all(C, "Grease Pencil", 0, 0); } /* Markers */ - else if (strstr(opname, "MARKER_OT")) { + else if (STRPREFIX(opname, "MARKER_OT")) { km = WM_keymap_find_all(C, "Markers", 0, 0); } /* Import/Export*/ - else if (strstr(opname, "IMPORT_") || strstr(opname, "EXPORT_")) { + else if (STRPREFIX(opname, "IMPORT_") || + STRPREFIX(opname, "EXPORT_")) + { km = WM_keymap_find_all(C, "Window", 0, 0); } /* 3D View */ - else if (strstr(opname, "VIEW3D_OT")) { + else if (STRPREFIX(opname, "VIEW3D_OT")) { km = WM_keymap_find_all(C, "3D View", sl->spacetype, 0); } - else if (strstr(opname, "OBJECT_OT")) { + else if (STRPREFIX(opname, "OBJECT_OT")) { /* exception, this needs to work outside object mode too */ - if (strstr(opname, "OBJECT_OT_mode_set")) + if (STRPREFIX(opname, "OBJECT_OT_mode_set")) km = WM_keymap_find_all(C, "Object Non-modal", 0, 0); else km = WM_keymap_find_all(C, "Object Mode", 0, 0); } - + /* Object mode related */ + else if (STRPREFIX(opname, "GROUP_OT") || + STRPREFIX(opname, "MATERIAL_OT") || + STRPREFIX(opname, "PTCACHE_OT") || + STRPREFIX(opname, "RIGIDBODY_OT")) + { + km = WM_keymap_find_all(C, "Object Mode", 0, 0); + } /* Editing Modes */ - else if (strstr(opname, "MESH_OT")) { + else if (STRPREFIX(opname, "MESH_OT")) { km = WM_keymap_find_all(C, "Mesh", 0, 0); /* some mesh operators are active in object mode too, like add-prim */ @@ -1461,7 +1495,9 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) km = WM_keymap_find_all(C, "Object Mode", 0, 0); } } - else if (strstr(opname, "CURVE_OT")) { + else if (STRPREFIX(opname, "CURVE_OT") || + STRPREFIX(opname, "SURFACE_OT")) + { km = WM_keymap_find_all(C, "Curve", 0, 0); /* some curve operators are active in object mode too, like add-prim */ @@ -1469,13 +1505,17 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) km = WM_keymap_find_all(C, "Object Mode", 0, 0); } } - else if (strstr(opname, "ARMATURE_OT")) { + else if (STRPREFIX(opname, "ARMATURE_OT") || + STRPREFIX(opname, "SKETCH_OT")) + { km = WM_keymap_find_all(C, "Armature", 0, 0); } - else if (strstr(opname, "POSE_OT")) { + else if (STRPREFIX(opname, "POSE_OT") || + STRPREFIX(opname, "POSELIB_OT")) + { km = WM_keymap_find_all(C, "Pose", 0, 0); } - else if (strstr(opname, "SCULPT_OT")) { + else if (STRPREFIX(opname, "SCULPT_OT")) { switch (CTX_data_mode_enum(C)) { case OB_MODE_SCULPT: km = WM_keymap_find_all(C, "Sculpt", 0, 0); @@ -1485,7 +1525,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) break; } } - else if (strstr(opname, "MBALL_OT")) { + else if (STRPREFIX(opname, "MBALL_OT")) { km = WM_keymap_find_all(C, "Metaball", 0, 0); /* some mball operators are active in object mode too, like add-prim */ @@ -1493,16 +1533,16 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) km = WM_keymap_find_all(C, "Object Mode", 0, 0); } } - else if (strstr(opname, "LATTICE_OT")) { + else if (STRPREFIX(opname, "LATTICE_OT")) { km = WM_keymap_find_all(C, "Lattice", 0, 0); } - else if (strstr(opname, "PARTICLE_OT")) { + else if (STRPREFIX(opname, "PARTICLE_OT")) { km = WM_keymap_find_all(C, "Particle", 0, 0); } - else if (strstr(opname, "FONT_OT")) { + else if (STRPREFIX(opname, "FONT_OT")) { km = WM_keymap_find_all(C, "Font", 0, 0); } - else if (strstr(opname, "PAINT_OT")) { + else if (STRPREFIX(opname, "PAINT_OT")) { /* check for relevant mode */ switch (CTX_data_mode_enum(C)) { @@ -1518,69 +1558,86 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) } } /* Paint Face Mask */ - else if (strstr(opname, "PAINT_OT_face_select")) { + else if (STRPREFIX(opname, "PAINT_OT_face_select")) { km = WM_keymap_find_all(C, "Face Mask", sl->spacetype, 0); } /* Timeline */ - else if (strstr(opname, "TIME_OT")) { + else if (STRPREFIX(opname, "TIME_OT")) { km = WM_keymap_find_all(C, "Timeline", sl->spacetype, 0); } /* Image Editor */ - else if (strstr(opname, "IMAGE_OT")) { + else if (STRPREFIX(opname, "IMAGE_OT")) { km = WM_keymap_find_all(C, "Image", sl->spacetype, 0); } + /* Clip Editor */ + else if (STRPREFIX(opname, "CLIP_OT")) { + km = WM_keymap_find_all(C, "Clip", sl->spacetype, 0); + } + else if (STRPREFIX(opname, "MASK_OT")) { + km = WM_keymap_find_all(C, "Mask Editing", 0, 0); + } /* UV Editor */ - else if (strstr(opname, "UV_OT")) { + else if (STRPREFIX(opname, "UV_OT")) { km = WM_keymap_find_all(C, "UV Editor", sl->spacetype, 0); } /* Node Editor */ - else if (strstr(opname, "NODE_OT")) { + else if (STRPREFIX(opname, "NODE_OT")) { km = WM_keymap_find_all(C, "Node Editor", sl->spacetype, 0); } /* Animation Editor Channels */ - else if (strstr(opname, "ANIM_OT_channels")) { + else if (STRPREFIX(opname, "ANIM_OT_channels")) { km = WM_keymap_find_all(C, "Animation Channels", sl->spacetype, 0); } /* Animation Generic - after channels */ - else if (strstr(opname, "ANIM_OT")) { + else if (STRPREFIX(opname, "ANIM_OT")) { km = WM_keymap_find_all(C, "Animation", 0, 0); } /* Graph Editor */ - else if (strstr(opname, "GRAPH_OT")) { + else if (STRPREFIX(opname, "GRAPH_OT")) { km = WM_keymap_find_all(C, "Graph Editor", sl->spacetype, 0); } /* Dopesheet Editor */ - else if (strstr(opname, "ACTION_OT")) { + else if (STRPREFIX(opname, "ACTION_OT")) { km = WM_keymap_find_all(C, "Dopesheet", sl->spacetype, 0); } /* NLA Editor */ - else if (strstr(opname, "NLA_OT")) { + else if (STRPREFIX(opname, "NLA_OT")) { km = WM_keymap_find_all(C, "NLA Editor", sl->spacetype, 0); } /* Script */ - else if (strstr(opname, "SCRIPT_OT")) { + else if (STRPREFIX(opname, "SCRIPT_OT")) { km = WM_keymap_find_all(C, "Script", sl->spacetype, 0); } /* Text */ - else if (strstr(opname, "TEXT_OT")) { + else if (STRPREFIX(opname, "TEXT_OT")) { km = WM_keymap_find_all(C, "Text", sl->spacetype, 0); } /* Sequencer */ - else if (strstr(opname, "SEQUENCER_OT")) { + else if (STRPREFIX(opname, "SEQUENCER_OT")) { km = WM_keymap_find_all(C, "Sequencer", sl->spacetype, 0); } /* Console */ - else if (strstr(opname, "CONSOLE_OT")) { + else if (STRPREFIX(opname, "CONSOLE_OT")) { km = WM_keymap_find_all(C, "Console", sl->spacetype, 0); } /* Console */ - else if (strstr(opname, "INFO_OT")) { + else if (STRPREFIX(opname, "INFO_OT")) { km = WM_keymap_find_all(C, "Info", sl->spacetype, 0); } - + /* File browser */ + else if (STRPREFIX(opname, "FILE_OT")) { + km = WM_keymap_find_all(C, "File Browser", sl->spacetype, 0); + } + /* Logic Editor */ + else if (STRPREFIX(opname, "LOGIC_OT")) { + km = WM_keymap_find_all(C, "Logic Editor", sl->spacetype, 0); + } + /* Outliner */ + else if (STRPREFIX(opname, "OUTLINER_OT")) { + km = WM_keymap_find_all(C, "Outliner", sl->spacetype, 0); + } /* Transform */ - else if (strstr(opname, "TRANSFORM_OT")) { - + else if (STRPREFIX(opname, "TRANSFORM_OT")) { /* check for relevant editor */ switch (sl->spacetype) { case SPACE_VIEW3D: diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index ba454bb1818..bc79879f1f4 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -56,6 +56,7 @@ #include "PIL_time.h" #include "BLI_blenlib.h" +#include "BLI_dial.h" #include "BLI_dynstr.h" /*for WM_operator_pystring */ #include "BLI_math.h" #include "BLI_utildefines.h" @@ -501,7 +502,7 @@ void WM_operator_py_idname(char *to, const char *from) int ofs = (sep - from); /* note, we use ascii tolower instead of system tolower, because the - * latter depends on the locale, and can lead to idname mistmatch */ + * latter depends on the locale, and can lead to idname mismatch */ memcpy(to, from, sizeof(char) * ofs); BLI_ascii_strtolower(to, ofs); @@ -1312,9 +1313,14 @@ void WM_operator_properties_gesture_border(wmOperatorType *ot, bool extend) void WM_operator_properties_mouse_select(wmOperatorType *ot) { - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first"); - RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from selection"); - RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Selection", "Toggle the selection"); + PropertyRNA *prop; + + prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from selection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Selection", "Toggle the selection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor) @@ -2049,6 +2055,41 @@ static void WM_OT_call_menu(wmOperatorType *ot) RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu"); } +static int wm_call_pie_menu_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + char idname[BKE_ST_MAXNAME]; + RNA_string_get(op->ptr, "name", idname); + + uiPieMenuInvoke(C, idname, event); + + return OPERATOR_CANCELLED; +} + +static int wm_call_pie_menu_exec(bContext *C, wmOperator *op) +{ + char idname[BKE_ST_MAXNAME]; + RNA_string_get(op->ptr, "name", idname); + + uiPieMenuInvoke(C, idname, CTX_wm_window(C)->eventstate); + + return OPERATOR_CANCELLED; +} + +static void WM_OT_call_menu_pie(wmOperatorType *ot) +{ + ot->name = "Call Pie Menu"; + ot->idname = "WM_OT_call_menu_pie"; + ot->description = "Call (draw) a pre-defined pie menu"; + + ot->invoke = wm_call_pie_menu_invoke; + ot->exec = wm_call_pie_menu_exec; + ot->poll = WM_operator_winactive; + + ot->flag = OPTYPE_INTERNAL; + + RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the pie menu"); +} + /* ************ window / screen operator definitions ************** */ /* this poll functions is needed in place of WM_operator_winactive @@ -2336,8 +2377,8 @@ static void WM_OT_open_mainfile(wmOperatorType *ot) WM_operator_properties_filesel(ot, FOLDERFILE | BLENDERFILE, FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); - RNA_def_boolean(ot->srna, "load_ui", 1, "Load UI", "Load user interface setup in the .blend file"); - RNA_def_boolean(ot->srna, "use_scripts", 1, "Trusted Source", + RNA_def_boolean(ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file"); + RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source", "Allow .blend file to execute scripts automatically, default available from system preferences"); } @@ -2348,7 +2389,14 @@ static int wm_revert_mainfile_exec(bContext *C, wmOperator *op) { bool success; - success = wm_file_read_opwrap(C, G.main->name, op->reports, true); + wm_open_init_use_scripts(op, false); + + if (RNA_boolean_get(op->ptr, "use_scripts")) + G.f |= G_SCRIPT_AUTOEXEC; + else + G.f &= ~G_SCRIPT_AUTOEXEC; + + success = wm_file_read_opwrap(C, G.main->name, op->reports, !(G.f & G_SCRIPT_AUTOEXEC)); if (success) { return OPERATOR_FINISHED; @@ -2370,6 +2418,9 @@ static void WM_OT_revert_mainfile(wmOperatorType *ot) ot->description = "Reload the saved file"; ot->invoke = WM_operator_confirm; + RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source", + "Allow .blend file to execute scripts automatically, default available from system preferences"); + ot->exec = wm_revert_mainfile_exec; ot->poll = wm_revert_mainfile_poll; } @@ -2419,7 +2470,7 @@ static short wm_link_append_flag(wmOperator *op) if (RNA_boolean_get(op->ptr, "autoselect")) flag |= FILE_AUTOSELECT; if (RNA_boolean_get(op->ptr, "active_layer")) flag |= FILE_ACTIVELAY; - if (RNA_boolean_get(op->ptr, "relative_path")) flag |= FILE_RELPATH; + if (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path")) flag |= FILE_RELPATH; if (RNA_boolean_get(op->ptr, "link")) flag |= FILE_LINK; if (RNA_boolean_get(op->ptr, "instance_groups")) flag |= FILE_GROUP_INSTANCE; @@ -2550,13 +2601,31 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static void WM_OT_link_append(wmOperatorType *ot) +static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link) { PropertyRNA *prop; - ot->name = "Link/Append from Library"; - ot->idname = "WM_OT_link_append"; - ot->description = "Link or Append from a Library .blend file"; + /* better not save _any_ settings for this operator */ + /* properties */ + prop = RNA_def_boolean(ot->srna, "link", is_link, + "Link", "Link the objects or datablocks rather than appending"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + prop = RNA_def_boolean(ot->srna, "autoselect", true, + "Select", "Select new objects"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "active_layer", true, + "Active Layer", "Put new objects on the active layer"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "instance_groups", is_link, + "Instance Groups", "Create Dupli-Group instances for each group"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +static void WM_OT_link(wmOperatorType *ot) +{ + ot->name = "Link from Library"; + ot->idname = "WM_OT_link"; + ot->description = "Link from a Library .blend file"; ot->invoke = wm_link_append_invoke; ot->exec = wm_link_append_exec; @@ -2569,16 +2638,27 @@ static void WM_OT_link_append(wmOperatorType *ot) WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY); - /* better not save _any_ settings for this operator */ - /* properties */ - prop = RNA_def_boolean(ot->srna, "link", 1, "Link", "Link the objects or datablocks rather than appending"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); - prop = RNA_def_boolean(ot->srna, "autoselect", 1, "Select", "Select the linked objects"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "active_layer", 1, "Active Layer", "Put the linked objects on the active layer"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "instance_groups", 1, "Instance Groups", "Create instances for each group as a DupliGroup"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + wm_link_append_properties_common(ot, true); +} + +static void WM_OT_append(wmOperatorType *ot) +{ + ot->name = "Append from Library"; + ot->idname = "WM_OT_append"; + ot->description = "Append from a Library .blend file"; + + ot->invoke = wm_link_append_invoke; + ot->exec = wm_link_append_exec; + ot->poll = wm_link_append_poll; + + ot->flag |= OPTYPE_UNDO; + + WM_operator_properties_filesel( + ot, FOLDERFILE | BLENDERFILE, FILE_LOADLIB, FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES, + FILE_DEFAULTDISPLAY); + + wm_link_append_properties_common(ot, false); } /* *************** recover last session **************** */ @@ -3291,7 +3371,7 @@ void wm_tweakevent_test(bContext *C, wmEvent *event, int action) if (win->tweak == NULL) { if (CTX_wm_region(C)) { if (event->val == KM_PRESS) { - if (ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) { + if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) { win->tweak = WM_gesture_new(C, event, WM_GESTURE_TWEAK); } } @@ -3642,6 +3722,9 @@ typedef struct { StructRNA *image_id_srna; float initial_value, current_value, min_value, max_value; int initial_mouse[2]; + int slow_mouse[2]; + bool slow_mode; + Dial *dial; unsigned int gltex; ListBase orig_paintcursors; bool use_secondary_tex; @@ -4032,7 +4115,7 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve /* get subtype of property */ rc->subtype = RNA_property_subtype(rc->prop); - if (!ELEM5(rc->subtype, PROP_NONE, PROP_DISTANCE, PROP_FACTOR, PROP_ANGLE, PROP_PIXEL)) { + if (!ELEM(rc->subtype, PROP_NONE, PROP_DISTANCE, PROP_FACTOR, PROP_ANGLE, PROP_PIXEL)) { BKE_report(op->reports, RPT_ERROR, "Property must be a none, distance, a factor, or an angle"); MEM_freeN(rc); return OPERATOR_CANCELLED; @@ -4075,6 +4158,11 @@ static void radial_control_cancel(bContext *C, wmOperator *op) RadialControl *rc = op->customdata; wmWindowManager *wm = CTX_wm_manager(C); + if (rc->dial) { + MEM_freeN(rc->dial); + rc->dial = NULL; + } + WM_paint_cursor_end(wm, rc->cursor); /* restore original paint cursors */ @@ -4094,24 +4182,61 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even { RadialControl *rc = op->customdata; float new_value, dist, zoom[2]; - float delta[2], snap, ret = OPERATOR_RUNNING_MODAL; - + float delta[2], ret = OPERATOR_RUNNING_MODAL; + bool snap; + float angle_precision = 0.0f; /* TODO: fix hardcoded events */ - snap = event->ctrl; + snap = event->ctrl != 0; switch (event->type) { case MOUSEMOVE: - delta[0] = rc->initial_mouse[0] - event->x; - delta[1] = rc->initial_mouse[1] - event->y; - - if (rc->zoom_prop) { - RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); - delta[0] /= zoom[0]; - delta[1] /= zoom[1]; + if (rc->slow_mode) { + if (rc->subtype == PROP_ANGLE) { + float position[2] = {event->x, event->y}; + + /* calculate the initial angle here first */ + delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0]; + delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1]; + + /* precision angle gets calculated from dial and gets added later */ + angle_precision = -0.1f * BLI_dial_angle(rc->dial, position); + } + else { + delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0]; + delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1]; + + if (rc->zoom_prop) { + RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); + delta[0] /= zoom[0]; + delta[1] /= zoom[1]; + } + + dist = len_v2(delta); + + delta[0] = event->x - rc->slow_mouse[0]; + delta[1] = event->y - rc->slow_mouse[1]; + + if (rc->zoom_prop) { + delta[0] /= zoom[0]; + delta[1] /= zoom[1]; + } + + dist = dist + 0.1f * (delta[0] + delta[1]); + } } + else { + delta[0] = rc->initial_mouse[0] - event->x; + delta[1] = rc->initial_mouse[1] - event->y; - dist = len_v2(delta); + if (rc->zoom_prop) { + RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); + delta[0] /= zoom[0]; + delta[1] /= zoom[1]; + } + + dist = len_v2(delta); + } /* calculate new value and apply snapping */ switch (rc->subtype) { @@ -4126,7 +4251,10 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even if (snap) new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f; break; case PROP_ANGLE: - new_value = atan2(delta[1], delta[0]) + M_PI; + new_value = atan2(delta[1], delta[0]) + M_PI + angle_precision; + new_value = fmod(new_value, 2.0f * (float)M_PI); + if (new_value < 0.0f) + new_value += 2.0f * (float)M_PI; if (snap) new_value = DEG2RADF(((int)RAD2DEGF(new_value) + 5) / 10 * 10); break; default: @@ -4153,6 +4281,29 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even RNA_property_update(C, &rc->ptr, rc->prop); ret = OPERATOR_FINISHED; break; + + case LEFTSHIFTKEY: + case RIGHTSHIFTKEY: + if (event->val == KM_PRESS) { + rc->slow_mouse[0] = event->x; + rc->slow_mouse[1] = event->y; + rc->slow_mode = true; + if (rc->subtype == PROP_ANGLE) { + float initial_position[2] = {UNPACK2(rc->initial_mouse)}; + float current_position[2] = {UNPACK2(rc->slow_mouse)}; + rc->dial = BLI_dial_initialize(initial_position, 0.0f); + /* immediately set the position to get a an initial direction */ + BLI_dial_angle(rc->dial, current_position); + } + } + if (event->val == KM_RELEASE) { + rc->slow_mode = false; + if (rc->dial) { + MEM_freeN(rc->dial); + rc->dial = NULL; + } + } + break; } ED_region_tag_redraw(CTX_wm_region(C)); @@ -4165,8 +4316,6 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even static void WM_OT_radial_control(wmOperatorType *ot) { - PropertyRNA *prop; - ot->name = "Radial Control"; ot->idname = "WM_OT_radial_control"; ot->description = "Set some size property (like e.g. brush size) with mouse wheel"; @@ -4178,32 +4327,23 @@ static void WM_OT_radial_control(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; /* all paths relative to the context */ - prop = RNA_def_string(ot->srna, "data_path_primary", NULL, 0, "Primary Data Path", "Primary path of property to be set by the radial control"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "data_path_primary", NULL, 0, "Primary Data Path", "Primary path of property to be set by the radial control"); - prop = RNA_def_string(ot->srna, "data_path_secondary", NULL, 0, "Secondary Data Path", "Secondary path of property to be set by the radial control"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "data_path_secondary", NULL, 0, "Secondary Data Path", "Secondary path of property to be set by the radial control"); - prop = RNA_def_string(ot->srna, "use_secondary", NULL, 0, "Use Secondary", "Path of property to select between the primary and secondary data paths"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "use_secondary", NULL, 0, "Use Secondary", "Path of property to select between the primary and secondary data paths"); - prop = RNA_def_string(ot->srna, "rotation_path", NULL, 0, "Rotation Path", "Path of property used to rotate the texture display"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "rotation_path", NULL, 0, "Rotation Path", "Path of property used to rotate the texture display"); - prop = RNA_def_string(ot->srna, "color_path", NULL, 0, "Color Path", "Path of property used to set the color of the control"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "color_path", NULL, 0, "Color Path", "Path of property used to set the color of the control"); - prop = RNA_def_string(ot->srna, "fill_color_path", NULL, 0, "Fill Color Path", "Path of property used to set the fill color of the control"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "fill_color_path", NULL, 0, "Fill Color Path", "Path of property used to set the fill color of the control"); - prop = RNA_def_string(ot->srna, "zoom_path", NULL, 0, "Zoom Path", "Path of property used to set the zoom level for the control"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "zoom_path", NULL, 0, "Zoom Path", "Path of property used to set the zoom level for the control"); - prop = RNA_def_string(ot->srna, "image_id", NULL, 0, "Image ID", "Path of ID that is used to generate an image for the control"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "image_id", NULL, 0, "Image ID", "Path of ID that is used to generate an image for the control"); - prop = RNA_def_boolean(ot->srna, "secondary_tex", 0, "Secondary Texture", "Tweak brush secondary/mask texture"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_boolean(ot->srna, "secondary_tex", 0, "Secondary Texture", "Tweak brush secondary/mask texture"); } /* ************************** timer for testing ***************** */ @@ -4425,7 +4565,8 @@ void wm_operatortype_init(void) WM_operatortype_append(WM_OT_quit_blender); WM_operatortype_append(WM_OT_open_mainfile); WM_operatortype_append(WM_OT_revert_mainfile); - WM_operatortype_append(WM_OT_link_append); + WM_operatortype_append(WM_OT_link); + WM_operatortype_append(WM_OT_append); WM_operatortype_append(WM_OT_recover_last_session); WM_operatortype_append(WM_OT_recover_auto_save); WM_operatortype_append(WM_OT_save_as_mainfile); @@ -4438,6 +4579,7 @@ void wm_operatortype_init(void) WM_operatortype_append(WM_OT_splash); WM_operatortype_append(WM_OT_search_menu); WM_operatortype_append(WM_OT_call_menu); + WM_operatortype_append(WM_OT_call_menu_pie); WM_operatortype_append(WM_OT_radial_control); #if defined(WIN32) WM_operatortype_append(WM_OT_console_toggle); @@ -4651,10 +4793,8 @@ void wm_window_keymap(wmKeyConfig *keyconf) WM_keymap_add_menu(keymap, "INFO_MT_file_open_recent", OKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); WM_keymap_add_item(keymap, "WM_OT_open_mainfile", OKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "WM_OT_open_mainfile", F1KEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "WM_OT_link_append", OKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); - kmi = WM_keymap_add_item(keymap, "WM_OT_link_append", F1KEY, KM_PRESS, KM_SHIFT, 0); - RNA_boolean_set(kmi->ptr, "link", false); - RNA_boolean_set(kmi->ptr, "instance_groups", false); + WM_keymap_add_item(keymap, "WM_OT_link", OKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); + WM_keymap_add_item(keymap, "WM_OT_append", F1KEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "WM_OT_save_mainfile", SKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "WM_OT_save_mainfile", WKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 1792ea40a1a..db4459b1799 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -308,7 +308,7 @@ void wmSubWindowScissorSet(wmWindow *win, int swinid, const rcti *srct, bool src int scissor_height = BLI_rcti_size_y(srct); /* typically a single pixel doesn't matter, - * but one pixel offset is noticable with viewport border render */ + * but one pixel offset is noticeable with viewport border render */ if (srct_pad) { scissor_width += 1; scissor_height += 1; diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 99f4ec6bd16..d83f876c2e1 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -973,14 +973,15 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr const char *path = GHOST_GetEventData(evt); if (path) { + wmOperatorType *ot = WM_operatortype_find("WM_OT_open_mainfile", false); /* operator needs a valid window in context, ensures * it is correctly set */ oldWindow = CTX_wm_window(C); CTX_wm_window_set(C, win); - WM_operator_properties_create(&props_ptr, "WM_OT_open_mainfile"); + WM_operator_properties_create_ptr(&props_ptr, ot); RNA_string_set(&props_ptr, "filepath", path); - WM_operator_name_call(C, "WM_OT_open_mainfile", WM_OP_EXEC_DEFAULT, &props_ptr); + WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr); WM_operator_properties_free(&props_ptr); CTX_wm_window_set(C, oldWindow); @@ -1014,7 +1015,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr /* make blender drop event with custom data pointing to wm drags */ event.type = EVT_DROP; event.val = KM_RELEASE; - event.custom = EVT_DATA_LISTBASE; + event.custom = EVT_DATA_DRAGDROP; event.customdata = &wm->drags; event.customdatafree = 1; @@ -1033,7 +1034,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr /* try to get icon type from extension */ icon = ED_file_extension_icon((char *)stra->strings[a]); - WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0); + WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0, WM_DRAG_NOP); /* void poin should point to string, it makes a copy */ break; /* only one drop element supported now */ } diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index df084554c54..d1a94194108 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -81,8 +81,9 @@ enum { /* handler flag */ enum { - WM_HANDLER_BLOCKING = 1, /* after this handler all others are ignored */ - WM_HANDLER_DO_FREE = 2 /* handler tagged to be freed in wm_handlers_do() */ + WM_HANDLER_BLOCKING = (1 << 0), /* after this handler all others are ignored */ + WM_HANDLER_DO_FREE = (1 << 1), /* handler tagged to be freed in wm_handlers_do() */ + WM_HANDLER_ACCEPT_DBL_CLICK = (1 << 2), /* handler accepts double key press events */ }; /* wm_event_system.c */ diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 4a274d25170..f50f98ed40c 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -36,92 +36,230 @@ #define __WM_EVENT_TYPES_H__ /* customdata type */ -#define EVT_DATA_GESTURE 1 -#define EVT_DATA_TIMER 2 -#define EVT_DATA_LISTBASE 3 -#define EVT_DATA_NDOF_MOTION 4 +enum { + EVT_DATA_GESTURE = 1, + EVT_DATA_TIMER = 2, + EVT_DATA_DRAGDROP = 3, + EVT_DATA_NDOF_MOTION = 4, +}; /* tablet active, matches GHOST_TTabletMode */ -#define EVT_TABLET_NONE 0 -#define EVT_TABLET_STYLUS 1 -#define EVT_TABLET_ERASER 2 - - -/* *** wmEvent.type *** */ - -/* non-event, for example disabled timer */ -#define EVENT_NONE 0 -/* MOUSE : 0x00x */ -#define LEFTMOUSE 1 -#define MIDDLEMOUSE 2 -#define RIGHTMOUSE 3 -#define MOUSEMOVE 4 - /* only use if you want user option switch possible */ -#define ACTIONMOUSE 5 -#define SELECTMOUSE 6 - /* Extra mouse buttons */ -#define BUTTON4MOUSE 7 -#define BUTTON5MOUSE 8 - /* More mouse buttons - can't use 9 and 10 here (wheel) */ -#define BUTTON6MOUSE 18 -#define BUTTON7MOUSE 19 - /* Extra trackpad gestures */ -#define MOUSEPAN 14 -#define MOUSEZOOM 15 -#define MOUSEROTATE 16 - /* defaults from ghost */ -#define WHEELUPMOUSE 10 -#define WHEELDOWNMOUSE 11 - /* mapped with userdef */ -#define WHEELINMOUSE 12 -#define WHEELOUTMOUSE 13 - /* Successive MOUSEMOVE's are converted to this, so we can easily - * ignore all but the most recent MOUSEMOVE (for better performance), - * paint and drawing tools however will want to handle these. */ -#define INBETWEEN_MOUSEMOVE 17 - - -/* NDOF (from SpaceNavigator & friends) - * These should be kept in sync with GHOST_NDOFManager.h - * Ordering matters, exact values do not. */ - -#define NDOF_MOTION 400 +enum { + EVT_TABLET_NONE = 0, + EVT_TABLET_STYLUS = 1, + EVT_TABLET_ERASER = 2, +}; +/* ********** wmEvent.type ********** */ enum { - // used internally, never sent + /* non-event, for example disabled timer */ + EVENT_NONE = 0x0000, + + /* ********** Start of Input devices. ********** */ + + /* MOUSE : 0x000x, 0x001x */ + LEFTMOUSE = 0x0001, + MIDDLEMOUSE = 0x0002, + RIGHTMOUSE = 0x0003, + MOUSEMOVE = 0x0004, + /* only use if you want user option switch possible */ + ACTIONMOUSE = 0x0005, + SELECTMOUSE = 0x0006, + /* Extra mouse buttons */ + BUTTON4MOUSE = 0x0007, + BUTTON5MOUSE = 0x0008, + /* More mouse buttons - can't use 9 and 10 here (wheel) */ + BUTTON6MOUSE = 0x0012, + BUTTON7MOUSE = 0x0013, + /* Extra trackpad gestures */ + MOUSEPAN = 0x000e, + MOUSEZOOM = 0x000f, + MOUSEROTATE = 0x0010, + /* defaults from ghost */ + WHEELUPMOUSE = 0x000a, + WHEELDOWNMOUSE = 0x000b, + /* mapped with userdef */ + WHEELINMOUSE = 0x000c, + WHEELOUTMOUSE = 0x000d, + /* Successive MOUSEMOVE's are converted to this, so we can easily + * ignore all but the most recent MOUSEMOVE (for better performance), + * paint and drawing tools however will want to handle these. */ + INBETWEEN_MOUSEMOVE = 0x0011, + + /* *** Start of keyboard codes. *** */ + + /* standard keyboard. + * XXX from 0x0020 to 0x00ff, and 0x012c to 0x013f for function keys! */ + AKEY = 0x0061, /* 'a' */ + BKEY = 0x0062, /* 'b' */ + CKEY = 0x0063, /* 'c' */ + DKEY = 0x0064, /* 'd' */ + EKEY = 0x0065, /* 'e' */ + FKEY = 0x0066, /* 'f' */ + GKEY = 0x0067, /* 'g' */ +#ifndef WIN32 + HKEY = 0x0068, /* 'h' */ +#else +#define HKEY 0x0068 +#endif + IKEY = 0x0069, /* 'i' */ + JKEY = 0x006a, /* 'j' */ + KKEY = 0x006b, /* 'k' */ + LKEY = 0x006c, /* 'l' */ + MKEY = 0x006d, /* 'm' */ + NKEY = 0x006e, /* 'n' */ + OKEY = 0x006f, /* 'o' */ + PKEY = 0x0070, /* 'p' */ + QKEY = 0x0071, /* 'q' */ + RKEY = 0x0072, /* 'r' */ + SKEY = 0x0073, /* 's' */ + TKEY = 0x0074, /* 't' */ + UKEY = 0x0075, /* 'u' */ + VKEY = 0x0076, /* 'v' */ + WKEY = 0x0077, /* 'w' */ + XKEY = 0x0078, /* 'x' */ + YKEY = 0x0079, /* 'y' */ + ZKEY = 0x007a, /* 'z' */ + + ZEROKEY = 0x0030, /* '0' */ + ONEKEY = 0x0031, /* '1' */ + TWOKEY = 0x0032, /* '2' */ + THREEKEY = 0x0033, /* '3' */ + FOURKEY = 0x0034, /* '4' */ + FIVEKEY = 0x0035, /* '5' */ + SIXKEY = 0x0036, /* '6' */ + SEVENKEY = 0x0037, /* '7' */ + EIGHTKEY = 0x0038, /* '8' */ + NINEKEY = 0x0039, /* '9' */ + + CAPSLOCKKEY = 0x00d3, /* 211 */ + + LEFTCTRLKEY = 0x00d4, /* 212 */ + LEFTALTKEY = 0x00d5, /* 213 */ + RIGHTALTKEY = 0x00d6, /* 214 */ + RIGHTCTRLKEY = 0x00d7, /* 215 */ + RIGHTSHIFTKEY = 0x00d8, /* 216 */ + LEFTSHIFTKEY = 0x00d9, /* 217 */ + + ESCKEY = 0x00da, /* 218 */ + TABKEY = 0x00db, /* 219 */ + RETKEY = 0x00dc, /* 220 */ + SPACEKEY = 0x00dd, /* 221 */ + LINEFEEDKEY = 0x00de, /* 222 */ + BACKSPACEKEY = 0x00df, /* 223 */ + DELKEY = 0x00e0, /* 224 */ + SEMICOLONKEY = 0x00e1, /* 225 */ + PERIODKEY = 0x00e2, /* 226 */ + COMMAKEY = 0x00e3, /* 227 */ + QUOTEKEY = 0x00e4, /* 228 */ + ACCENTGRAVEKEY = 0x00e5, /* 229 */ + MINUSKEY = 0x00e6, /* 230 */ + SLASHKEY = 0x00e8, /* 232 */ + BACKSLASHKEY = 0x00e9, /* 233 */ + EQUALKEY = 0x00ea, /* 234 */ + LEFTBRACKETKEY = 0x00eb, /* 235 */ + RIGHTBRACKETKEY = 0x00ec, /* 236 */ + + LEFTARROWKEY = 0x0089, /* 137 */ + DOWNARROWKEY = 0x008a, /* 138 */ + RIGHTARROWKEY = 0x008b, /* 139 */ + UPARROWKEY = 0x008c, /* 140 */ + + PAD0 = 0x0096, /* 150 */ + PAD1 = 0x0097, /* 151 */ + PAD2 = 0x0098, /* 152 */ + PAD3 = 0x0099, /* 153 */ + PAD4 = 0x009a, /* 154 */ + PAD5 = 0x009b, /* 155 */ + PAD6 = 0x009c, /* 156 */ + PAD7 = 0x009d, /* 157 */ + PAD8 = 0x009e, /* 158 */ + PAD9 = 0x009f, /* 159 */ + + PADPERIOD = 0x00c7, /* 199 */ + PADASTERKEY = 0x00a0, /* 160 */ + PADSLASHKEY = 0x00a1, /* 161 */ + PADMINUS = 0x00a2, /* 162 */ + PADENTER = 0x00a3, /* 163 */ + PADPLUSKEY = 0x00a4, /* 164 */ + + PAUSEKEY = 0x00a5, /* 165 */ + INSERTKEY = 0x00a6, /* 166 */ + HOMEKEY = 0x00a7, /* 167 */ + PAGEUPKEY = 0x00a8, /* 168 */ + PAGEDOWNKEY = 0x00a9, /* 169 */ + ENDKEY = 0x00aa, /* 170 */ + + UNKNOWNKEY = 0x00ab, /* 171 */ + OSKEY = 0x00ac, /* 172 */ + GRLESSKEY = 0x00ad, /* 173 */ + + /* XXX: are these codes ok? */ + MEDIAPLAY = 0x00ae, /* 174 */ + MEDIASTOP = 0x00af, /* 175 */ + MEDIAFIRST = 0x00b0, /* 176 */ + MEDIALAST = 0x00b1, /* 177 */ + + F1KEY = 0x012c, /* 300 */ + F2KEY = 0x012d, /* 301 */ + F3KEY = 0x012e, /* 302 */ + F4KEY = 0x012f, /* 303 */ + F5KEY = 0x0130, /* 304 */ + F6KEY = 0x0131, /* 305 */ + F7KEY = 0x0132, /* 306 */ + F8KEY = 0x0133, /* 307 */ + F9KEY = 0x0134, /* 308 */ + F10KEY = 0x0135, /* 309 */ + F11KEY = 0x0136, /* 310 */ + F12KEY = 0x0137, /* 311 */ + F13KEY = 0x0138, /* 312 */ + F14KEY = 0x0139, /* 313 */ + F15KEY = 0x013a, /* 314 */ + F16KEY = 0x013b, /* 315 */ + F17KEY = 0x013c, /* 316 */ + F18KEY = 0x013d, /* 317 */ + F19KEY = 0x013e, /* 318 */ + + /* *** End of keyboard codes. *** */ + + /* NDOF (from SpaceNavigator & friends) + * These should be kept in sync with GHOST_NDOFManager.h + * Ordering matters, exact values do not. */ + NDOF_MOTION = 0x0190, + /* used internally, never sent */ NDOF_BUTTON_NONE = NDOF_MOTION, - // these two are available from any 3Dconnexion device + /* these two are available from any 3Dconnexion device */ NDOF_BUTTON_MENU, NDOF_BUTTON_FIT, - // standard views + /* standard views */ NDOF_BUTTON_TOP, NDOF_BUTTON_BOTTOM, NDOF_BUTTON_LEFT, NDOF_BUTTON_RIGHT, NDOF_BUTTON_FRONT, NDOF_BUTTON_BACK, - // more views + /* more views */ NDOF_BUTTON_ISO1, NDOF_BUTTON_ISO2, - // 90 degree rotations + /* 90 degree rotations */ NDOF_BUTTON_ROLL_CW, NDOF_BUTTON_ROLL_CCW, NDOF_BUTTON_SPIN_CW, NDOF_BUTTON_SPIN_CCW, NDOF_BUTTON_TILT_CW, NDOF_BUTTON_TILT_CCW, - // device control + /* device control */ NDOF_BUTTON_ROTATE, NDOF_BUTTON_PANZOOM, NDOF_BUTTON_DOMINANT, NDOF_BUTTON_PLUS, NDOF_BUTTON_MINUS, - // keyboard emulation + /* keyboard emulation */ NDOF_BUTTON_ESC, NDOF_BUTTON_ALT, NDOF_BUTTON_SHIFT, NDOF_BUTTON_CTRL, - // general-purpose buttons + /* general-purpose buttons */ NDOF_BUTTON_1, NDOF_BUTTON_2, NDOF_BUTTON_3, @@ -132,180 +270,81 @@ enum { NDOF_BUTTON_8, NDOF_BUTTON_9, NDOF_BUTTON_10, - // more general-purpose buttons + /* more general-purpose buttons */ NDOF_BUTTON_A, NDOF_BUTTON_B, NDOF_BUTTON_C, - // the end - NDOF_LAST + /* the end */ + NDOF_LAST, + + /* ********** End of Input devices. ********** */ + + /* ********** Start of Blender internal events. ********** */ + + /* XXX Those are mixed inside keyboard 'area'! */ + /* System: 0x010x */ + INPUTCHANGE = 0x0103, /* input connected or disconnected */ + WINDEACTIVATE = 0x0104, /* window is deactivated, focus lost */ + /* Timer: 0x011x */ + TIMER = 0x0110, /* timer event, passed on to all queues */ + TIMER0 = 0x0111, /* timer event, slot for internal use */ + TIMER1 = 0x0112, /* timer event, slot for internal use */ + TIMER2 = 0x0113, /* timer event, slot for internal use */ + TIMERJOBS = 0x0114, /* timer event, jobs system */ + TIMERAUTOSAVE = 0x0115, /* timer event, autosave */ + TIMERREPORT = 0x0116, /* timer event, reports */ + TIMERREGION = 0x0117, /* timer event, region slide in/out */ + TIMERF = 0x011F, /* last timer */ + + /* Tweak, gestures: 0x500x, 0x501x */ + EVT_ACTIONZONE_AREA = 0x5000, + EVT_ACTIONZONE_REGION = 0x5001, + /* tweak events, for L M R mousebuttons */ + EVT_TWEAK_L = 0x5002, + EVT_TWEAK_M = 0x5003, + EVT_TWEAK_R = 0x5004, + /* tweak events for action or select mousebutton */ + EVT_TWEAK_A = 0x5005, + EVT_TWEAK_S = 0x5006, + EVT_GESTURE = 0x5010, + + /* Misc Blender internals: 0x502x */ + EVT_FILESELECT = 0x5020, + EVT_BUT_OPEN = 0x5021, + EVT_MODAL_MAP = 0x5022, + EVT_DROP = 0x5023, + EVT_BUT_CANCEL = 0x5024, + + /* ********** End of Blender internal events. ********** */ }; -/* SYSTEM : 0x01xx */ -#define INPUTCHANGE 0x0103 /* input connected or disconnected */ -#define WINDEACTIVATE 0x0104 /* window is deactivated, focus lost */ - -#define TIMER 0x0110 /* timer event, passed on to all queues */ -#define TIMER0 0x0111 /* timer event, slot for internal use */ -#define TIMER1 0x0112 /* timer event, slot for internal use */ -#define TIMER2 0x0113 /* timer event, slot for internal use */ -#define TIMERJOBS 0x0114 /* timer event, jobs system */ -#define TIMERAUTOSAVE 0x0115 /* timer event, autosave */ -#define TIMERREPORT 0x0116 /* timer event, reports */ -#define TIMERREGION 0x0117 /* timer event, region slide in/out */ -#define TIMERF 0x011F /* last timer */ +/* *********** wmEvent.type helpers. ********** */ /* test whether the event is timer event */ #define ISTIMER(event_type) (event_type >= TIMER && event_type <= TIMERF) -/* standard keyboard */ -#define AKEY 'a' -#define BKEY 'b' -#define CKEY 'c' -#define DKEY 'd' -#define EKEY 'e' -#define FKEY 'f' -#define GKEY 'g' -#define HKEY 'h' -#define IKEY 'i' -#define JKEY 'j' -#define KKEY 'k' -#define LKEY 'l' -#define MKEY 'm' -#define NKEY 'n' -#define OKEY 'o' -#define PKEY 'p' -#define QKEY 'q' -#define RKEY 'r' -#define SKEY 's' -#define TKEY 't' -#define UKEY 'u' -#define VKEY 'v' -#define WKEY 'w' -#define XKEY 'x' -#define YKEY 'y' -#define ZKEY 'z' - -#define ZEROKEY '0' -#define ONEKEY '1' -#define TWOKEY '2' -#define THREEKEY '3' -#define FOURKEY '4' -#define FIVEKEY '5' -#define SIXKEY '6' -#define SEVENKEY '7' -#define EIGHTKEY '8' -#define NINEKEY '9' - -#define CAPSLOCKKEY 211 - -#define LEFTCTRLKEY 212 -#define LEFTALTKEY 213 -#define RIGHTALTKEY 214 -#define RIGHTCTRLKEY 215 -#define RIGHTSHIFTKEY 216 -#define LEFTSHIFTKEY 217 - -#define ESCKEY 218 -#define TABKEY 219 -#define RETKEY 220 -#define SPACEKEY 221 -#define LINEFEEDKEY 222 -#define BACKSPACEKEY 223 -#define DELKEY 224 -#define SEMICOLONKEY 225 -#define PERIODKEY 226 -#define COMMAKEY 227 -#define QUOTEKEY 228 -#define ACCENTGRAVEKEY 229 -#define MINUSKEY 230 -#define SLASHKEY 232 -#define BACKSLASHKEY 233 -#define EQUALKEY 234 -#define LEFTBRACKETKEY 235 -#define RIGHTBRACKETKEY 236 - -#define LEFTARROWKEY 137 -#define DOWNARROWKEY 138 -#define RIGHTARROWKEY 139 -#define UPARROWKEY 140 - -#define PAD0 150 -#define PAD1 151 -#define PAD2 152 -#define PAD3 153 -#define PAD4 154 -#define PAD5 155 -#define PAD6 156 -#define PAD7 157 -#define PAD8 158 -#define PAD9 159 - - -#define PADPERIOD 199 -#define PADSLASHKEY 161 -#define PADASTERKEY 160 - -#define PADMINUS 162 -#define PADENTER 163 -#define PADPLUSKEY 164 - -#define F1KEY 300 -#define F2KEY 301 -#define F3KEY 302 -#define F4KEY 303 -#define F5KEY 304 -#define F6KEY 305 -#define F7KEY 306 -#define F8KEY 307 -#define F9KEY 308 -#define F10KEY 309 -#define F11KEY 310 -#define F12KEY 311 -#define F13KEY 312 -#define F14KEY 313 -#define F15KEY 314 -#define F16KEY 315 -#define F17KEY 316 -#define F18KEY 317 -#define F19KEY 318 - -#define PAUSEKEY 165 -#define INSERTKEY 166 -#define HOMEKEY 167 -#define PAGEUPKEY 168 -#define PAGEDOWNKEY 169 -#define ENDKEY 170 - -#define UNKNOWNKEY 171 -#define OSKEY 172 -#define GRLESSKEY 173 - -// XXX: are these codes ok? -#define MEDIAPLAY 174 -#define MEDIASTOP 175 -#define MEDIAFIRST 176 -#define MEDIALAST 177 - /* for event checks */ - /* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */ - /* UNUSED - see wm_eventmatch - BUG [#30479] */ -// #define ISTEXTINPUT(event_type) (event_type >= ' ' && event_type <= 255) +/* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */ +/* UNUSED - see wm_eventmatch - BUG [#30479] */ +/* #define ISTEXTINPUT(event_type) (event_type >= ' ' && event_type <= 255) */ /* note, an alternative could be to check 'event->utf8_buf' */ - /* test whether the event is a key on the keyboard */ -#define ISKEYBOARD(event_type) (event_type >= ' ' && event_type <= 320) +/* test whether the event is a key on the keyboard */ +#define ISKEYBOARD(event_type) \ + ((event_type >= 0x0020 && event_type <= 0x00ff) || \ + (event_type >= 0x012c && event_type <= 0x013f)) - /* test whether the event is a modifier key */ +/* test whether the event is a modifier key */ #define ISKEYMODIFIER(event_type) ((event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) || event_type == OSKEY) - /* test whether the event is a mouse button */ +/* test whether the event is a mouse button */ #define ISMOUSE(event_type) (event_type >= LEFTMOUSE && event_type <= BUTTON7MOUSE) - /* test whether the event is tweak event */ +/* test whether the event is tweak event */ #define ISTWEAK(event_type) (event_type >= EVT_TWEAK_L && event_type <= EVT_GESTURE) - /* test whether the event is a NDOF event */ +/* test whether the event is a NDOF event */ #define ISNDOF(event_type) (event_type >= NDOF_MOTION && event_type < NDOF_LAST) /* test whether event type is acceptable as hotkey, excluding modifiers */ @@ -315,76 +354,61 @@ enum { (event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) == false && \ (event_type >= UNKNOWNKEY && event_type <= GRLESSKEY) == false) -/* **************** BLENDER GESTURE EVENTS (0x5000) **************** */ - -#define EVT_ACTIONZONE_AREA 20480 -#define EVT_ACTIONZONE_REGION 20481 - - /* tweak events, for L M R mousebuttons */ -#define EVT_TWEAK_L 20482 -#define EVT_TWEAK_M 20483 -#define EVT_TWEAK_R 20484 - /* tweak events for action or select mousebutton */ -#define EVT_TWEAK_A 20485 -#define EVT_TWEAK_S 20486 - -#define EVT_GESTURE 20496 - -/* value of tweaks and line gestures, note, KM_ANY (-1) works for this case too */ -#define EVT_GESTURE_N 1 -#define EVT_GESTURE_NE 2 -#define EVT_GESTURE_E 3 -#define EVT_GESTURE_SE 4 -#define EVT_GESTURE_S 5 -#define EVT_GESTURE_SW 6 -#define EVT_GESTURE_W 7 -#define EVT_GESTURE_NW 8 -/* value of corner gestures */ -#define EVT_GESTURE_N_E 9 -#define EVT_GESTURE_N_W 10 -#define EVT_GESTURE_E_N 11 -#define EVT_GESTURE_E_S 12 -#define EVT_GESTURE_S_E 13 -#define EVT_GESTURE_S_W 14 -#define EVT_GESTURE_W_S 15 -#define EVT_GESTURE_W_N 16 - -/* **************** OTHER BLENDER EVENTS ********************* */ - -/* event->type */ -#define EVT_FILESELECT 0x5020 - -/* event->val */ -#define EVT_FILESELECT_OPEN 1 -#define EVT_FILESELECT_FULL_OPEN 2 -#define EVT_FILESELECT_EXEC 3 -#define EVT_FILESELECT_CANCEL 4 -#define EVT_FILESELECT_EXTERNAL_CANCEL 5 - -/* event->type */ -#define EVT_BUT_OPEN 0x5021 -#define EVT_MODAL_MAP 0x5022 -#define EVT_DROP 0x5023 -#define EVT_BUT_CANCEL 0x5024 - -/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ -#define GESTURE_MODAL_CANCEL 1 -#define GESTURE_MODAL_CONFIRM 2 - -#define GESTURE_MODAL_SELECT 3 -#define GESTURE_MODAL_DESELECT 4 - -#define GESTURE_MODAL_NOP 5 /* circle select when no mouse button is pressed */ - -#define GESTURE_MODAL_CIRCLE_ADD 6 /* circle sel: larger brush */ -#define GESTURE_MODAL_CIRCLE_SUB 7 /* circle sel: smaller brush */ - -#define GESTURE_MODAL_BEGIN 8 /* border select/straight line, activate, use release to detect which button */ - -#define GESTURE_MODAL_IN 9 -#define GESTURE_MODAL_OUT 10 - -#define GESTURE_MODAL_CIRCLE_SIZE 11 /* circle sel: size brush (for trackpad event) */ + +/* ********** wmEvent.val ********** */ + +/* Gestures */ +enum { + /* value of tweaks and line gestures, note, KM_ANY (-1) works for this case too */ + EVT_GESTURE_N = 1, + EVT_GESTURE_NE = 2, + EVT_GESTURE_E = 3, + EVT_GESTURE_SE = 4, + EVT_GESTURE_S = 5, + EVT_GESTURE_SW = 6, + EVT_GESTURE_W = 7, + EVT_GESTURE_NW = 8, + /* value of corner gestures */ + EVT_GESTURE_N_E = 9, + EVT_GESTURE_N_W = 10, + EVT_GESTURE_E_N = 11, + EVT_GESTURE_E_S = 12, + EVT_GESTURE_S_E = 13, + EVT_GESTURE_S_W = 14, + EVT_GESTURE_W_S = 15, + EVT_GESTURE_W_N = 16, +}; + +/* File select */ +enum { + EVT_FILESELECT_OPEN = 1, + EVT_FILESELECT_FULL_OPEN = 2, + EVT_FILESELECT_EXEC = 3, + EVT_FILESELECT_CANCEL = 4, + EVT_FILESELECT_EXTERNAL_CANCEL = 5, +}; + +/* Gesture */ +/* NOTE: these values are saved in keymap files, do not change them but just add new ones */ +enum { + GESTURE_MODAL_CANCEL = 1, + GESTURE_MODAL_CONFIRM = 2, + + GESTURE_MODAL_SELECT = 3, + GESTURE_MODAL_DESELECT = 4, + + GESTURE_MODAL_NOP = 5, /* circle select when no mouse button is pressed */ + + GESTURE_MODAL_CIRCLE_ADD = 6, /* circle sel: larger brush */ + GESTURE_MODAL_CIRCLE_SUB = 7, /* circle sel: smaller brush */ + + GESTURE_MODAL_BEGIN = 8, /* border select/straight line, activate, use release to detect which button */ + + GESTURE_MODAL_IN = 9, + GESTURE_MODAL_OUT = 10, + + GESTURE_MODAL_CIRCLE_SIZE = 11, /* circle sel: size brush (for trackpad event) */ +}; #endif /* __WM_EVENT_TYPES_H__ */ diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index 7ce3fa82f8b..ce20371d91b 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -228,3 +228,9 @@ if(WITH_PLAYER) endif() setup_liblinks(blenderplayer) + +# We put CLEW and CUEW here because OPENSUBDIV_LIBRARIES dpeends on them.. +if(WITH_CYCLES OR WITH_COMPOSITOR OR WITH_OPENSUBDIV) + target_link_libraries(blenderplayer "extern_clew") + target_link_libraries(blenderplayer "extern_cuew") +endif() diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 72f411b4231..97e7d99c802 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -301,6 +301,8 @@ void ED_armature_transform(struct bArmature *arm, float mat[4][4]) RET_NONE struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op) RET_NULL struct wmTimer *WM_event_add_timer(struct wmWindowManager *wm, struct wmWindow *win, int event_type, double timestep) RET_NULL void WM_event_remove_timer(struct wmWindowManager *wm, struct wmWindow *win, struct wmTimer *timer) RET_NONE +float WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]) RET_ZERO +bool WM_event_is_tablet(const struct wmEvent *event) RET_ZERO void ED_armature_edit_bone_remove(struct bArmature *arm, struct EditBone *exBone) RET_NONE void object_test_constraints(struct Object *owner) RET_NONE void ED_armature_ebone_to_mat4(struct EditBone *ebone, float mat[4][4]) RET_NONE @@ -385,7 +387,6 @@ void ED_area_tag_redraw(struct ScrArea *sa) RET_NONE void ED_area_tag_refresh(struct ScrArea *sa) RET_NONE void ED_area_newspace(struct bContext *C, struct ScrArea *sa, int type) RET_NONE void ED_region_tag_redraw(struct ARegion *ar) RET_NONE -void ED_curve_transform(struct Curve *cv, float mat[4][4]) RET_NONE void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op) RET_NONE void WM_cursor_wait(bool val) RET_NONE void ED_node_texture_default(const struct bContext *C, struct Tex *tex) RET_NONE @@ -411,7 +412,7 @@ void ED_view3D_background_image_remove(struct View3D *v3d, struct BGpic *bgpic) void ED_view3D_background_image_clear(struct View3D *v3d) RET_NONE void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4]) RET_NONE float ED_view3d_grid_scale(struct Scene *scene, struct View3D *v3d, const char **grid_unit) RET_ZERO -void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa) RET_NONE +void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa) RET_NONE void ED_node_shader_default(const struct bContext *C, struct ID *id) RET_NONE void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh) RET_NONE struct bScreen *ED_screen_animation_playing(const struct wmWindowManager *wm) RET_NULL @@ -437,7 +438,6 @@ void uiLayoutSetScaleX(struct uiLayout *layout, float scale) RET_NONE void uiLayoutSetScaleY(struct uiLayout *layout, float scale) RET_NONE void uiTemplateIconView(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname) RET_NONE void ED_base_object_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Base *base) RET_NONE -void ED_mesh_transform(struct Mesh *me, float mat[4][4]) RET_NONE void ED_mesh_update(struct Mesh *mesh, struct bContext *C, int calc_edges, int calc_tessface) RET_NONE void ED_mesh_vertices_add(struct Mesh *mesh, struct ReportList *reports, int count) RET_NONE void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count) RET_NONE @@ -473,8 +473,6 @@ bool ED_texture_context_check_lamp(const struct bContext *C) RET_ZERO bool ED_texture_context_check_particles(const struct bContext *C) RET_ZERO bool ED_texture_context_check_others(const struct bContext *C) RET_ZERO -void ED_mball_transform(struct MetaBall *mb, float mat[4][4]) RET_NONE - bool snapObjectsRayEx(struct Scene *scene, struct Base *base_act, struct View3D *v3d, struct ARegion *ar, struct Object *obedit, short snap_mode, struct Object **r_ob, float r_obmat[4][4], const float ray_start[3], const float ray_normal[3], float *r_ray_dist, @@ -482,7 +480,6 @@ bool snapObjectsRayEx(struct Scene *scene, struct Base *base_act, struct View3D void make_editLatt(struct Object *obedit) RET_NONE void load_editLatt(struct Object *obedit) RET_NONE -void ED_lattice_transform(struct Lattice *lt, float mat[4][4]) RET_NONE void load_editNurb(struct Object *obedit) RET_NONE void make_editNurb(struct Object *obedit) RET_NONE @@ -561,6 +558,7 @@ void uiTemplateColorspaceSettings(struct uiLayout *layout, struct PointerRNA *pt void uiTemplateColormanagedViewSettings(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname) RET_NONE void uiTemplateComponentMenu(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name) RET_NONE void uiTemplateNodeSocket(struct uiLayout *layout, struct bContext *C, float *color) RET_NONE +void uiTemplatePalette(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color) RET_NONE /* rna render */ struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername) RET_NULL @@ -619,6 +617,13 @@ struct wmKeyMap *WM_modalkeymap_add(struct wmKeyConfig *keyconf, const char *idn struct uiPopupMenu *uiPupMenuBegin(struct bContext *C, const char *title, int icon) RET_NULL void uiPupMenuEnd(struct bContext *C, struct uiPopupMenu *head) RET_NONE struct uiLayout *uiPupMenuLayout(struct uiPopupMenu *head) RET_NULL +struct uiLayout *uiPieMenuLayout(struct uiPieMenu *pie) RET_NULL +void uiPieMenuInvoke(struct bContext *C, const char *idname, const struct wmEvent *event) RET_NONE +struct uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const struct wmEvent *event) RET_NULL +void uiPieMenuEnd(struct bContext *C, uiPieMenu *pie) RET_NONE +struct uiLayout *uiLayoutRadial(struct uiLayout *layout) RET_NULL +void uiPieOperatorEnumInvoke(struct bContext *C, const char *title, const char *opname, + const char *propname, const struct wmEvent *event) RET_NONE /* RNA COLLADA dependency */ int collada_export(struct Scene *sce, diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 7df91df23c8..bd9dce01ed8 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -278,7 +278,7 @@ elseif(APPLE) if(WITH_PYTHON_MODULE) set(TARGETDIR_VER ${TARGETDIR}/${BLENDER_VERSION}) else() - set(TARGETDIR_VER ${TARGETDIR}/blender.app/Contents/MacOS/${BLENDER_VERSION}) + set(TARGETDIR_VER ${TARGETDIR}/blender.app/Contents/Resources/${BLENDER_VERSION}) endif() endif() @@ -395,19 +395,26 @@ endif() if(UNIX AND NOT APPLE) - install( - CODE - " - execute_process(COMMAND - ${CMAKE_SOURCE_DIR}/doc/manpage/blender.1.py - ${TARGETDIR}/blender - ${TARGETDIR}/blender.1) - " - ) + if(NOT WITH_PYTHON_MODULE) + install( + CODE + " + execute_process(COMMAND + ${CMAKE_SOURCE_DIR}/doc/manpage/blender.1.py + ${TARGETDIR}/blender + ${TARGETDIR}/blender.1) + " + ) + endif() # there are a few differences between portable and system install if(WITH_INSTALL_PORTABLE) install( + FILES ${TARGETDIR}/blender.1 + DESTINATION ${TARGETDIR} + ) + + install( FILES ${CMAKE_SOURCE_DIR}/release/freedesktop/blender.desktop ${CMAKE_SOURCE_DIR}/release/freedesktop/icons/scalable/apps/blender.svg @@ -438,6 +445,11 @@ if(UNIX AND NOT APPLE) PROGRAMS ${TARGETDIR}/blender DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ) + # manpage only with 'blender' binary + install( + FILES ${TARGETDIR}/blender.1 + DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1 + ) endif() @@ -473,10 +485,6 @@ if(UNIX AND NOT APPLE) DESTINATION ${CMAKE_INSTALL_PREFIX}/bin ) install( - FILES ${TARGETDIR}/blender.1 - DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1 - ) - install( FILES ${BLENDER_TEXT_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/blender ) @@ -515,16 +523,22 @@ if(UNIX AND NOT APPLE) PATTERN "idlelib" EXCLUDE # ./idlelib PATTERN "test" EXCLUDE # ./test PATTERN "turtledemo" EXCLUDE # ./turtledemo - PATTERN "turtle.py" EXCLUDE # ./turtle.py + PATTERN "turtle.py" EXCLUDE # ./turtle.py ) # # doesnt work, todo # install(CODE "execute_process(COMMAND find ${TARGETDIR}/${BLENDER_VERSION}/python/lib/ -name '*.so' -exec strip -s {} '\;')") - + if(WITH_PYTHON_INSTALL_NUMPY) + # Install to the same directory as the source, so debian-like + # distros are happy with their policy. + set(_suffix "site-packages") + if(${PYTHON_NUMPY_PATH} MATCHES "dist-packages") + set(_suffix "dist-packages") + endif() install( DIRECTORY ${PYTHON_NUMPY_PATH}/numpy - DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/site-packages + DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix} PATTERN ".svn" EXCLUDE PATTERN "__pycache__" EXCLUDE # * any cache * PATTERN "*.pyc" EXCLUDE # * any cache * @@ -538,19 +552,47 @@ if(UNIX AND NOT APPLE) PATTERN "*.h" EXCLUDE # some includes are not in include dirs PATTERN "*.a" EXCLUDE # ./core/lib/libnpymath.a - for linking, we dont need. ) + unset(_suffix) endif() # Copy requests, we need to generalize site-packages if(WITH_PYTHON_INSTALL_REQUESTS) + set(_suffix "site-packages") + if(${PYTHON_REQUESTS_PATH} MATCHES "dist-packages") + set(_suffix "dist-packages") + endif() install( - DIRECTORY ${PYTHON_LIBPATH}/python${PYTHON_VERSION}/site-packages/requests - DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/site-packages + DIRECTORY ${PYTHON_REQUESTS_PATH}/requests + DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix} PATTERN ".svn" EXCLUDE PATTERN "__pycache__" EXCLUDE # * any cache * PATTERN "*.pyc" EXCLUDE # * any cache * PATTERN "*.pyo" EXCLUDE # * any cache * PATTERN "cacert.pem" EXCLUDE # for now we don't deal with security ) + # On some platforms requests does have extra dependencies. + set(_requests_deps "chardet" "urllib3") + foreach(_requests_dep ${_requests_deps}) + if(EXISTS ${PYTHON_REQUESTS_PATH}/${_requests_dep}) + install( + DIRECTORY ${PYTHON_REQUESTS_PATH}/${_requests_dep} + DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix} + PATTERN ".svn" EXCLUDE + PATTERN "__pycache__" EXCLUDE # * any cache * + PATTERN "*.pyc" EXCLUDE # * any cache * + PATTERN "*.pyo" EXCLUDE # * any cache * + ) + endif() + endforeach() + if(EXISTS ${PYTHON_REQUESTS_PATH}/six.py) + install( + FILES ${PYTHON_REQUESTS_PATH}/six.py + DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix} + ) + endif() + unset(_requests_dep) + unset(_requests_deps) + unset(_suffix) endif() unset(_target_LIB) @@ -567,13 +609,13 @@ elseif(WIN32) string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION}) install( - FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.dll + FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.dll ${LIBDIR}/python/lib/sqlite3.dll DESTINATION ${TARGETDIR} CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel ) install( - FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}_d.dll + FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}_d.dll ${LIBDIR}/python/lib/sqlite3_d.dll DESTINATION ${TARGETDIR} CONFIGURATIONS Debug ) @@ -719,12 +761,10 @@ elseif(WIN32) endif() if(WITH_SDL) - if(NOT CMAKE_CL_64) - install( - FILES ${LIBDIR}/sdl/lib/SDL.dll - DESTINATION ${TARGETDIR} - ) - endif() + install( + FILES ${LIBDIR}/sdl/lib/SDL.dll + DESTINATION ${TARGETDIR} + ) endif() if(NOT CMAKE_CL_64) @@ -810,6 +850,13 @@ elseif(APPLE) ) endif() + if(WITH_LLVM AND NOT LLVM_STATIC) + install( + FILES ${LIBDIR}/llvm/lib/libLLVM-3.4.dylib + DESTINATION ${TARGETDIR}/blender.app/Contents/MacOS + ) + endif() + # python if(WITH_PYTHON AND NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK) # the python zip is first extract as part of the build process, @@ -909,3 +956,18 @@ setup_blender_sorted_libs() target_link_libraries(blender ${BLENDER_SORTED_LIBS}) setup_liblinks(blender) + +# ----------------------------------------------------------------------------- +# Setup launcher + +if(WIN32 AND NOT WITH_PYTHON_MODULE) + set(LAUNCHER_SRC + creator_launch_win.c + ../icons/winblender.rc + ) + add_executable(blender-launcher ${LAUNCHER_SRC}) + target_link_libraries(blender-launcher bf_intern_utfconv ${PLATFORM_LINKLIBS}) + + set_target_properties(blender PROPERTIES OUTPUT_NAME blender-app) + set_target_properties(blender-launcher PROPERTIES OUTPUT_NAME blender) +endif() diff --git a/source/creator/creator.c b/source/creator/creator.c index 25455c99a71..10f82b90516 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -41,6 +41,9 @@ #endif #ifdef WIN32 +# if defined(_MSC_VER) && _MSC_VER >= 1800 && defined(_M_X64) +# include <math.h> /* needed for _set_FMA3_enable */ +# endif # include <windows.h> # include "utfconv.h" #endif @@ -1501,7 +1504,13 @@ int main( bArgs *ba; #endif -#ifdef WIN32 /* Win32 Unicode Args */ +#ifdef WIN32 + /* FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it. */ +# if defined(_MSC_VER) && _MSC_VER >= 1800 && defined(_M_X64) + _set_FMA3_enable(0); +# endif + + /* Win32 Unicode Args */ /* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized * (it depends on the args passed in, which is what we're getting here!) */ diff --git a/source/creator/creator_launch_win.c b/source/creator/creator_launch_win.c new file mode 100644 index 00000000000..a7e04b2dafc --- /dev/null +++ b/source/creator/creator_launch_win.c @@ -0,0 +1,85 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* Binary name to launch. */ +#define BLENDER_BINARY L"blender-app.exe" + +#define WIN32_LEAN_AND_MEAN +#include <stdio.h> +#include <stdlib.h> + +#include <windows.h> +#include <Shellapi.h> + +#include "utfconv.h" + +#include "BLI_utildefines.h" +#include "BLI_winstuff.h" + +static void local_hacks_do(void) +{ + _putenv_s("OMP_WAIT_POLICY", "PASSIVE"); +} + +int main(int argc, const char **UNUSED(argv_c)) +{ + PROCESS_INFORMATION processInformation = {0}; + STARTUPINFOW startupInfo = {0}; + BOOL result; + wchar_t command[65536]; + int i, len = sizeof(command) / sizeof(wchar_t); + wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc); + int argci = 0; + + local_hacks_do(); + + wcsncpy(command, BLENDER_BINARY, len - 1); + len -= wcslen(BLENDER_BINARY); + for (i = 1; i < argc; ++i) { + wcsncat(command, L" \"", len - 2); + wcsncat(command, argv_16[i], len - 3); + len -= wcslen(argv_16[i]) + 1; + wcsncat(command, L"\"", len - 1); + } + + LocalFree(argv_16); + + startupInfo.cb = sizeof(startupInfo); + result = CreateProcessW(NULL, command, NULL, NULL, TRUE, + 0, NULL, NULL, + &startupInfo, &processInformation); + + if (!result) { + fprintf(stderr, "%S\n", L"Error launching " BLENDER_BINARY); + return EXIT_FAILURE; + } + + WaitForSingleObject(processInformation.hProcess, INFINITE); + + CloseHandle(processInformation.hProcess); + CloseHandle(processInformation.hThread); + + return EXIT_SUCCESS; +} diff --git a/source/creator/osx_locals.map b/source/creator/osx_locals.map index c3dd8b62792..a1d7e7fed57 100644 --- a/source/creator/osx_locals.map +++ b/source/creator/osx_locals.map @@ -1,3 +1,5 @@ ## The symbols will be treated as if they were marked as __private_extern__ ## (aka visibility=hidden) and will not be global in the output file *boost* +*__ZNSt6vector* + diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index e11bc84a0da..8d73e591113 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -101,7 +101,7 @@ static void game_copy_pose(bPose **dst, bPose *src, int copy_constraint) out->chanhash = NULL; out->agroups.first= out->agroups.last= NULL; out->ikdata = NULL; - out->ikparam = MEM_dupallocN(out->ikparam); + out->ikparam = MEM_dupallocN(src->ikparam); out->flag |= POSE_GAME_ENGINE; BLI_duplicatelist(&out->chanbase, &src->chanbase); @@ -231,6 +231,8 @@ BL_ArmatureObject::BL_ArmatureObject( m_objArma = BKE_object_copy(armature); m_objArma->data = BKE_armature_copy((bArmature *)armature->data); m_pose = m_objArma->pose; + // need this to get iTaSC working ok in the BGE + m_pose->flag |= POSE_GAME_ENGINE; memcpy(m_obmat, m_objArma->obmat, sizeof(m_obmat)); } diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index e511f01e9c6..87b64582e11 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -876,7 +876,7 @@ static bool ConvertMaterial( material->alphablend = GEMAT_ALPHA; // always zsort alpha + add - if ((ELEM3(material->alphablend, GEMAT_ALPHA, GEMAT_ALPHA_SORT, GEMAT_ADD) || texalpha) && (material->alphablend != GEMAT_CLIP )) { + if ((ELEM(material->alphablend, GEMAT_ALPHA, GEMAT_ALPHA_SORT, GEMAT_ADD) || texalpha) && (material->alphablend != GEMAT_CLIP )) { material->ras_mode |= ALPHA; material->ras_mode |= (mat && (mat->game.alpha_blend & GEMAT_ALPHA_SORT))? ZSORT: 0; } diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.h b/source/gameengine/Converter/BL_ShapeActionActuator.h index f72275b79cf..e96d0e0ebb4 100644 --- a/source/gameengine/Converter/BL_ShapeActionActuator.h +++ b/source/gameengine/Converter/BL_ShapeActionActuator.h @@ -59,7 +59,7 @@ public: virtual void ProcessReplica(); void SetBlendTime (float newtime); - void BlendShape(struct Key* key, float weigth); + void BlendShape(struct Key* key, float weight); bAction* GetAction() { return m_action; } void SetAction(bAction* act) { m_action= act; } diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index 45fc11b97d2..f6ed3366625 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -538,8 +538,8 @@ void BL_ConvertActuators(const char* maggiename, originalval, editobact->time, editobact->flag, - blenderobject->trackflag, - blenderobject->upflag); + editobact->trackflag, + editobact->upflag); baseact = tmptrackact; break; } diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp index 93a5ee11366..0d706fcd924 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.cpp +++ b/source/gameengine/Converter/KX_ConvertSensors.cpp @@ -329,12 +329,19 @@ void BL_ConvertSensors(struct Object* blenderobject, gameobj); } else { /* give us a focus-aware sensor */ + bool bFindMaterial = (bmouse->mode & SENS_COLLISION_MATERIAL); + bool bXRay = (bmouse->flag & SENS_RAY_XRAY); + STR_String checkname = (bFindMaterial? bmouse->matname : bmouse->propname); + gamesensor = new KX_MouseFocusSensor(eventmgr, startx, starty, keytype, trackfocus, (bmouse->flag & SENS_MOUSE_FOCUS_PULSE) ? true:false, + checkname, + bFindMaterial, + bXRay, kxscene, kxengine, gameobj); diff --git a/source/gameengine/Expressions/Expression.cpp b/source/gameengine/Expressions/Expression.cpp index c1146aaa65c..2428df977d3 100644 --- a/source/gameengine/Expressions/Expression.cpp +++ b/source/gameengine/Expressions/Expression.cpp @@ -21,13 +21,13 @@ ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// -#ifdef _DEBUG +#ifdef DEBUG //int gRefCountExpr; #endif CExpression::CExpression()// : m_cached_calculate(NULL) { m_refcount = 1; -#ifdef _DEBUG +#ifdef DEBUG //gRefCountExpr++; #endif } diff --git a/source/gameengine/Expressions/Expression.h b/source/gameengine/Expressions/Expression.h index d1b7eda43f0..9a4f1f93284 100644 --- a/source/gameengine/Expressions/Expression.h +++ b/source/gameengine/Expressions/Expression.h @@ -116,7 +116,7 @@ public: virtual CExpression * AddRef() { // please leave multiline, for debugger !!! -#ifdef _DEBUG +#ifdef DEBUG //gRefCountExpr++; assertd(m_refcount < 255); #endif @@ -124,7 +124,7 @@ public: return this; }; virtual CExpression* Release(CExpression* complicatedtrick=NULL) { -#ifdef _DEBUG +#ifdef DEBUG //gRefCountExpr--; #endif if (--m_refcount < 1) diff --git a/source/gameengine/Expressions/IntValue.cpp b/source/gameengine/Expressions/IntValue.cpp index a2d055974c3..82d2e94dbb0 100644 --- a/source/gameengine/Expressions/IntValue.cpp +++ b/source/gameengine/Expressions/IntValue.cpp @@ -35,7 +35,7 @@ effect: constructs a new CIntValue */ { -#ifdef _DEBUG_ +#ifdef DEBUG_ m_textval = "Int illegal constructor"; #endif m_pstrRep=NULL; diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp index 1ced71e66a4..bdef2dbd5b0 100644 --- a/source/gameengine/Expressions/Value.cpp +++ b/source/gameengine/Expressions/Value.cpp @@ -86,7 +86,7 @@ struct SmartCValueRef std::vector<SmartCValueRef> gRefList; #endif -#ifdef _DEBUG +#ifdef DEBUG //int gRefCountValue; #endif @@ -101,7 +101,7 @@ effect: constucts a CValue */ { //debug(gRefCountValue++) // debugging -#ifdef _DEBUG +#ifdef DEBUG //gRefCountValue++; #ifdef CVALUE_DEBUG gRefList.push_back(SmartCValueRef(this)); @@ -460,7 +460,7 @@ void CValue::DisableRefCount() m_refcount--; //debug(gRefCountValue--); -#ifdef _DEBUG +#ifdef DEBUG //gRefCountValue--; #endif m_ValFlags.RefCountDisabled=true; @@ -472,7 +472,7 @@ void CValue::ProcessReplica() /* was AddDataToReplica in 2.48 */ { m_refcount = 1; -#ifdef _DEBUG +#ifdef DEBUG //gRefCountValue++; #endif PyObjectPlus::ProcessReplica(); diff --git a/source/gameengine/Expressions/Value.h b/source/gameengine/Expressions/Value.h index 7f6ce9aa703..c7e9a40a059 100644 --- a/source/gameengine/Expressions/Value.h +++ b/source/gameengine/Expressions/Value.h @@ -90,7 +90,7 @@ enum VALUE_DATA_TYPE { -#ifdef _DEBUG +#ifdef DEBUG //extern int gRefCountValue; // debugonly variable to check if all CValue Refences are Dereferenced at programexit #endif @@ -251,7 +251,7 @@ public: // Increase global reference count, used to see at the end of the program // if all CValue-derived classes have been dereferenced to 0 //debug(gRefCountValue++); -#ifdef _DEBUG +#ifdef DEBUG //gRefCountValue++; #endif m_refcount++; @@ -264,7 +264,7 @@ public: // Decrease global reference count, used to see at the end of the program // if all CValue-derived classes have been dereferenced to 0 //debug(gRefCountValue--); -#ifdef _DEBUG +#ifdef DEBUG //gRefCountValue--; #endif // Decrease local reference count, if it reaches 0 the object should be freed diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h b/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h index 37c867ef7d6..566e5567507 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h +++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h @@ -36,7 +36,7 @@ #undef main #endif -#ifndef _DEBUG +#ifndef DEBUG # define JOYSTICK_ECHO(x) #else # include <iostream> diff --git a/source/gameengine/GameLogic/SCA_IScene.cpp b/source/gameengine/GameLogic/SCA_IScene.cpp index c98c86639d3..3ca4b6607b3 100644 --- a/source/gameengine/GameLogic/SCA_IScene.cpp +++ b/source/gameengine/GameLogic/SCA_IScene.cpp @@ -70,6 +70,32 @@ std::vector<SCA_DebugProp*>& SCA_IScene::GetDebugProperties() } +bool SCA_IScene::PropertyInDebugList( class CValue *gameobj, const STR_String &name ) +{ + for (std::vector<SCA_DebugProp*>::iterator it = m_debugList.begin(); + !(it==m_debugList.end());++it) { + STR_String debugname = (*it)->m_name; + CValue *debugobj = (*it)->m_obj; + + if (debugobj == gameobj && debugname == name) + return true; + } + return false; +} + + +bool SCA_IScene::ObjectInDebugList( class CValue *gameobj ) +{ + for (std::vector<SCA_DebugProp*>::iterator it = m_debugList.begin(); + !(it==m_debugList.end());++it) { + CValue* debugobj = (*it)->m_obj; + + if (debugobj == gameobj) + return true; + } + return false; +} + void SCA_IScene::AddDebugProperty(class CValue* debugprop, const STR_String &name) @@ -84,6 +110,24 @@ void SCA_IScene::AddDebugProperty(class CValue* debugprop, } +void SCA_IScene::RemoveDebugProperty(class CValue *gameobj, + const STR_String &name) +{ + vector<SCA_DebugProp*>::iterator it = m_debugList.begin(); + while(it != m_debugList.end()) { + STR_String debugname = (*it)->m_name; + CValue *debugobj = (*it)->m_obj; + + if (debugobj == gameobj && debugname == name) { + delete (*it); + m_debugList.erase(it); + break; + } + ++it; + } +} + + void SCA_IScene::RemoveObjectDebugProperties(class CValue* gameobj) { vector<SCA_DebugProp*>::iterator it = m_debugList.begin(); diff --git a/source/gameengine/GameLogic/SCA_IScene.h b/source/gameengine/GameLogic/SCA_IScene.h index e2e1edd4354..b76b5636b13 100644 --- a/source/gameengine/GameLogic/SCA_IScene.h +++ b/source/gameengine/GameLogic/SCA_IScene.h @@ -67,9 +67,11 @@ public: virtual void ReplaceMesh(class CValue* gameobj, void* meshobj, bool use_gfx, bool use_phys)=0; std::vector<SCA_DebugProp*>& GetDebugProperties(); + bool PropertyInDebugList(class CValue *gameobj, const STR_String &name); + bool ObjectInDebugList(class CValue *gameobj); void RemoveAllDebugProperties(); - void AddDebugProperty(class CValue* debugprop, - const STR_String &name); + void AddDebugProperty(class CValue* debugprop, const STR_String &name); + void RemoveDebugProperty(class CValue *gameobj, const STR_String &name); void RemoveObjectDebugProperties(class CValue* gameobj); virtual void Update2DFilter(std::vector<STR_String>& propNames, void* gameObj, diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp index 0eab6187d07..ea1b2a2bce3 100644 --- a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp +++ b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp @@ -69,13 +69,24 @@ bool SCA_PropertyActuator::Update() bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); - + CValue* propowner = GetParent(); if (bNegativeEvent) - return false; // do nothing on negative events + { + if (m_type==KX_ACT_PROP_LEVEL) + { + CValue* newval = new CBoolValue(false); + CValue* oldprop = propowner->GetProperty(m_propname); + if (oldprop) + { + oldprop->SetValue(newval); + } + newval->Release(); + } + return false; + } - CValue* propowner = GetParent(); CParser parser; parser.SetContext( propowner->AddRef()); @@ -97,6 +108,19 @@ bool SCA_PropertyActuator::Update() } newval->Release(); } + else if (m_type==KX_ACT_PROP_LEVEL) + { + CValue* newval = new CBoolValue(true); + CValue* oldprop = propowner->GetProperty(m_propname); + if (oldprop) + { + oldprop->SetValue(newval); + } else + { + propowner->SetProperty(m_propname,newval); + } + newval->Release(); + } else if ((userexpr = parser.ProcessText(m_exprtxt))) { switch (m_type) { diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.h b/source/gameengine/GameLogic/SCA_PropertyActuator.h index 83a6d05df1b..228ecf94bc4 100644 --- a/source/gameengine/GameLogic/SCA_PropertyActuator.h +++ b/source/gameengine/GameLogic/SCA_PropertyActuator.h @@ -44,6 +44,7 @@ class SCA_PropertyActuator : public SCA_IActuator KX_ACT_PROP_ADD, KX_ACT_PROP_COPY, KX_ACT_PROP_TOGGLE, + KX_ACT_PROP_LEVEL, KX_ACT_PROP_MAX }; diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp index 0d0b99edee1..9f0b582045f 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -616,7 +616,7 @@ void KX_BlenderMaterial::ActivateMeshSlot(const RAS_MeshSlot & ms, RAS_IRasteriz /* we do blend modes here, because they can change per object * with the same material due to obcolor/obalpha */ alphablend = mBlenderShader->GetAlphaBlend(); - if (ELEM3(alphablend, GEMAT_SOLID, GEMAT_ALPHA, GEMAT_ALPHA_SORT) && mMaterial->alphablend != GEMAT_SOLID) + if (ELEM(alphablend, GEMAT_SOLID, GEMAT_ALPHA, GEMAT_ALPHA_SORT) && mMaterial->alphablend != GEMAT_SOLID) alphablend = mMaterial->alphablend; rasty->SetAlphaBlend(alphablend); diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp index 793324fab75..29d92762285 100644 --- a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp @@ -114,6 +114,7 @@ PyMethodDef KX_ConstraintWrapper::Methods[] = { PyAttributeDef KX_ConstraintWrapper::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("constraint_id", KX_ConstraintWrapper, pyattr_get_constraintId), + KX_PYATTRIBUTE_RO_FUNCTION("constraint_type", KX_ConstraintWrapper, pyattr_get_constraintType), { NULL } //Sentinel }; @@ -123,4 +124,10 @@ PyObject *KX_ConstraintWrapper::pyattr_get_constraintId(void *self_v, const KX_P return self->PyGetConstraintId(); } +PyObject *KX_ConstraintWrapper::pyattr_get_constraintType(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_ConstraintWrapper* self = static_cast<KX_ConstraintWrapper*>(self_v); + return PyLong_FromLong(self->m_constraintType); +} + #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.h b/source/gameengine/Ketsji/KX_ConstraintWrapper.h index eafc45b5a70..b7124c76439 100644 --- a/source/gameengine/Ketsji/KX_ConstraintWrapper.h +++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.h @@ -49,6 +49,7 @@ public: KX_PYMETHOD(KX_ConstraintWrapper,GetParam); static PyObject *pyattr_get_constraintId(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_constraintType(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); #endif private: diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp index f58fee88d48..a77269c116d 100644 --- a/source/gameengine/Ketsji/KX_Dome.cpp +++ b/source/gameengine/Ketsji/KX_Dome.cpp @@ -2044,6 +2044,7 @@ void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i) cam->NodeUpdateGS(0.f); scene->CalculateVisibleMeshes(m_rasterizer,cam); + scene->UpdateAnimations(m_engine->GetFrameTime()); scene->RenderBuckets(camtrans, m_rasterizer); } diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index de528aeac63..c681e0842c4 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -51,6 +51,7 @@ typedef unsigned long uint_ptr; #include "KX_Light.h" // only for their ::Type #include "KX_FontObject.h" // only for their ::Type #include "RAS_MeshObject.h" +#include "KX_NavMeshObject.h" #include "KX_MeshProxy.h" #include "KX_PolyProxy.h" #include <stdio.h> // printf @@ -68,6 +69,7 @@ typedef unsigned long uint_ptr; #include "SCA_IController.h" #include "NG_NetworkScene.h" //Needed for sendMessage() #include "KX_ObstacleSimulation.h" +#include "KX_Scene.h" #include "BKE_object.h" @@ -928,6 +930,27 @@ KX_GameObject::SetVisible( } } +bool KX_GameObject::GetCulled() +{ + // If we're set to not cull, double-check with + // the mesh slots first. This is kind of nasty, but + // it allows us to get proper culling information. + if (!m_bCulled) + { + SG_QList::iterator<RAS_MeshSlot> mit(m_meshSlots); + for (mit.begin(); !mit.end(); ++mit) + { + if ((*mit)->m_bCulled) + { + m_bCulled = true; + break; + } + } + } + + return m_bCulled; +} + static void setOccluder_recursive(SG_Node* node, bool v) { NodeList& children = node->GetSGChildren(); @@ -958,6 +981,44 @@ KX_GameObject::SetOccluder( } } +static void setDebug_recursive(SG_Node *node, bool debug) +{ + NodeList& children = node->GetSGChildren(); + KX_Scene *scene = KX_GetActiveScene(); + + for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) { + SG_Node *childnode = (*childit); + KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject()); + if (clientgameobj != NULL) { + if (debug) { + if (!scene->ObjectInDebugList(clientgameobj)) + scene->AddObjectDebugProperties(clientgameobj); + } + else + scene->RemoveObjectDebugProperties(clientgameobj); + } + + /* if the childobj is NULL then this may be an inverse parent link + * so a non recursive search should still look down this node. */ + setDebug_recursive(childnode, debug); + } +} + +void KX_GameObject::SetUseDebugProperties( bool debug, bool recursive ) +{ + KX_Scene *scene = KX_GetActiveScene(); + + if (debug) { + if (!scene->ObjectInDebugList(this)) + scene->AddObjectDebugProperties(this); + } + else + scene->RemoveObjectDebugProperties(this); + + if (recursive) + setDebug_recursive(GetSGNode(), debug); +} + void KX_GameObject::SetLayer( int l @@ -1807,6 +1868,7 @@ PyMethodDef KX_GameObject::Methods[] = { KX_PYMETHODTABLE_O(KX_GameObject, getDistanceTo), KX_PYMETHODTABLE_O(KX_GameObject, getVectTo), KX_PYMETHODTABLE(KX_GameObject, sendMessage), + KX_PYMETHODTABLE(KX_GameObject, addDebugProperty), KX_PYMETHODTABLE_KEYWORDS(KX_GameObject, playAction), KX_PYMETHODTABLE(KX_GameObject, stopAction), @@ -1859,6 +1921,8 @@ PyAttributeDef KX_GameObject::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("childrenRecursive", KX_GameObject, pyattr_get_children_recursive), KX_PYATTRIBUTE_RO_FUNCTION("attrDict", KX_GameObject, pyattr_get_attrDict), KX_PYATTRIBUTE_RW_FUNCTION("color", KX_GameObject, pyattr_get_obcolor, pyattr_set_obcolor), + KX_PYATTRIBUTE_RW_FUNCTION("debug", KX_GameObject, pyattr_get_debug, pyattr_set_debug), + KX_PYATTRIBUTE_RW_FUNCTION("debugRecursive", KX_GameObject, pyattr_get_debugRecursive, pyattr_set_debugRecursive), /* experimental, don't rely on these yet */ KX_PYATTRIBUTE_RO_FUNCTION("sensors", KX_GameObject, pyattr_get_sensors), @@ -2775,6 +2839,52 @@ PyObject *KX_GameObject::pyattr_get_attrDict(void *self_v, const KX_PYATTRIBUTE_ return self->m_attr_dict; } +PyObject *KX_GameObject::pyattr_get_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene *scene = KX_GetActiveScene(); + KX_GameObject *self = static_cast<KX_GameObject*>(self_v); + + return PyBool_FromLong(scene->ObjectInDebugList(self)); +} + +int KX_GameObject::pyattr_set_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject *self = static_cast<KX_GameObject*>(self_v); + int param = PyObject_IsTrue(value); + + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "gameOb.debug = bool: KX_GameObject, expected True or False"); + return PY_SET_ATTR_FAIL; + } + + self->SetUseDebugProperties(param, false); + + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_GameObject::pyattr_get_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene *scene = KX_GetActiveScene(); + KX_GameObject *self = static_cast<KX_GameObject*>(self_v); + + return PyBool_FromLong(scene->ObjectInDebugList(self)); +} + +int KX_GameObject::pyattr_set_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject *self = static_cast<KX_GameObject*>(self_v); + int param = PyObject_IsTrue(value); + + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "gameOb.debugRecursive = bool: KX_GameObject, expected True or False"); + return PY_SET_ATTR_FAIL; + } + + self->SetUseDebugProperties(param, true); + + return PY_SET_ATTR_SUCCESS; +} + PyObject *KX_GameObject::PyApplyForce(PyObject *args) { int local = 0; @@ -3596,6 +3706,29 @@ KX_PYMETHODDEF_DOC(KX_GameObject, isPlayingAction, } +KX_PYMETHODDEF_DOC(KX_GameObject, addDebugProperty, +"addDebugProperty(name, visible=1)\n" +"Added or remove a debug property to the debug list.\n") +{ + KX_Scene *scene = KX_GetActiveScene(); + char *name; + int visible = 1; + + if (!PyArg_ParseTuple(args,"s|i:debugProperty", &name , &visible)) + return NULL; + + if (visible) { + if (!scene->PropertyInDebugList(this, name)) + scene->AddDebugProperty(this, name); + } + else { + scene->RemoveDebugProperty(this, name); + } + + Py_RETURN_NONE; +} + + /* dict style access */ @@ -3663,7 +3796,8 @@ bool ConvertPythonToGameObject(PyObject *value, KX_GameObject **object, bool py_ if ( PyObject_TypeCheck(value, &KX_GameObject::Type) || PyObject_TypeCheck(value, &KX_LightObject::Type) || PyObject_TypeCheck(value, &KX_Camera::Type) || - PyObject_TypeCheck(value, &KX_FontObject::Type)) + PyObject_TypeCheck(value, &KX_FontObject::Type) || + PyObject_TypeCheck(value, &KX_NavMeshObject::Type)) { *object = static_cast<KX_GameObject*>BGE_PROXY_REF(value); diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 7450be4fdef..d4fa4851696 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -852,10 +852,10 @@ public: /** * Was this object culled? */ - inline bool + bool GetCulled( void - ) { return m_bCulled; } + ); /** * Set culled flag of this object @@ -934,6 +934,11 @@ public: m_pObstacleSimulation = NULL; } + /** + * add debug object to the debuglist. + */ + void SetUseDebugProperties(bool debug, bool recursive); + KX_ClientObjectInfo* getClientInfo() { return m_pClient_info; } CListValue* GetChildren(); @@ -993,6 +998,7 @@ public: KX_PYMETHOD_DOC_O(KX_GameObject,getVectTo); KX_PYMETHOD_DOC_VARARGS(KX_GameObject, sendMessage); KX_PYMETHOD_VARARGS(KX_GameObject, ReinstancePhysicsMesh); + KX_PYMETHOD_DOC(KX_GameObject, addDebugProperty); KX_PYMETHOD_DOC(KX_GameObject, playAction); KX_PYMETHOD_DOC(KX_GameObject, stopAction); @@ -1060,7 +1066,11 @@ public: 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); - + static PyObject* pyattr_get_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + /* Experimental! */ static PyObject* pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject* pyattr_get_controllers(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 7d7e15a5141..14772cda113 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -140,7 +140,6 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_frameTime(0.f), m_clockTime(0.f), m_previousClockTime(0.f), - m_previousAnimTime(0.f), m_exitcode(KX_EXIT_REQUEST_NO_REQUEST), @@ -164,6 +163,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_showProperties(false), m_showBackground(false), m_show_debug_properties(false), + m_autoAddDebugProperties(true), m_animation_record(false), @@ -686,16 +686,6 @@ bool KX_KetsjiEngine::NextFrame() SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE); scene->UpdateParents(m_frameTime); - // update levels of detail - scene->UpdateObjectLods(); - - if (!GetRestrictAnimationFPS()) - { - m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); - scene->UpdateAnimations(m_frameTime); - } - m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); SG_SetActiveStage(SG_STAGE_PHYSICS2); scene->GetPhysicsEnvironment()->BeginFrame(); @@ -797,27 +787,6 @@ bool KX_KetsjiEngine::NextFrame() m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true); } } - - - // Handle the animations independently of the logic time step - if (GetRestrictAnimationFPS()) - { - double clocktime = m_kxsystem->GetTimeInSeconds(); - m_logger->StartLog(tc_animations, clocktime, true); - SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); - - double anim_timestep = 1.0/KX_GetActiveScene()->GetAnimationFPS(); - if (clocktime - m_previousAnimTime > anim_timestep) - { - // Sanity/debug print to make sure we're actually going at the fps we want (should be close to anim_timestep) - // printf("Anim fps: %f\n", 1.0/(m_clockTime - m_previousAnimTime)); - m_previousAnimTime = clocktime; - for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit) - { - (*sceneit)->UpdateAnimations(clocktime); - } - } - } // Start logging time spend outside main loop m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true); @@ -1186,8 +1155,15 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) raslight->BindShadowBuffer(m_canvas, cam, camtrans); /* update scene */ + m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); scene->CalculateVisibleMeshes(m_rasterizer, cam, raslight->GetShadowLayer()); + m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); + scene->UpdateAnimations(GetFrameTime()); + + m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); + + /* render */ m_rasterizer->ClearDepthBuffer(); m_rasterizer->ClearColorBuffer(); @@ -1319,6 +1295,11 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) scene->CalculateVisibleMeshes(m_rasterizer,cam); + m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); + SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); + + scene->UpdateAnimations(GetFrameTime()); + m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); SG_SetActiveStage(SG_STAGE_RENDER); @@ -1751,9 +1732,20 @@ void KX_KetsjiEngine::AddScheduledScenes() -void KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene) +bool KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene) { - m_replace_scenes.push_back(std::make_pair(oldscene,newscene)); + // Don't allow replacement if the new scene doesn't exists. + // Allows smarter game design (used to have no check here). + // Note that it creates a small backward compatbility issue + // for a game that did a replace followed by a lib load with the + // new scene in the lib => it won't work anymore, the lib + // must be loaded before doing the replace. + if (m_sceneconverter->GetBlenderSceneForName(newscene) != NULL) + { + m_replace_scenes.push_back(std::make_pair(oldscene,newscene)); + return true; + } + return false; } // replace scene is not the same as removing and adding because the @@ -1777,13 +1769,19 @@ void KX_KetsjiEngine::ReplaceScheduledScenes() KX_SceneList::iterator sceneit; for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++) { - KX_Scene* scene = *sceneit; + KX_Scene* scene = *sceneit; if (scene->GetName() == oldscenename) { - m_sceneconverter->RemoveScene(scene); - KX_Scene* tmpscene = CreateScene(newscenename); - m_scenes[i]=tmpscene; - PostProcessScene(tmpscene); + // avoid crash if the new scene doesn't exist, just do nothing + Scene *blScene = m_sceneconverter->GetBlenderSceneForName(newscenename); + if (blScene) { + m_sceneconverter->RemoveScene(scene); + KX_Scene* tmpscene = CreateScene(blScene); + m_scenes[i]=tmpscene; + PostProcessScene(tmpscene); + } else { + printf("warning: scene %s could not be found, not replaced!\n",newscenename.ReadPtr()); + } } i++; } @@ -1917,6 +1915,46 @@ short KX_KetsjiEngine::GetExitKey() return m_exitkey; } +void KX_KetsjiEngine::SetShowFramerate(bool frameRate) +{ + m_show_framerate = frameRate; +} + +bool KX_KetsjiEngine::GetShowFramerate() +{ + return m_show_framerate; +} + +void KX_KetsjiEngine::SetShowProfile(bool profile) +{ + m_show_profile = profile; +} + +bool KX_KetsjiEngine::GetShowProfile() +{ + return m_show_profile; +} + +void KX_KetsjiEngine::SetShowProperties(bool properties) +{ + m_show_debug_properties = properties; +} + +bool KX_KetsjiEngine::GetShowProperties() +{ + return m_show_debug_properties; +} + +void KX_KetsjiEngine::SetAutoAddDebugProperties(bool add) +{ + m_autoAddDebugProperties = add; +} + +bool KX_KetsjiEngine::GetAutoAddDebugProperties() +{ + return m_autoAddDebugProperties; +} + void KX_KetsjiEngine::SetTimingDisplay(bool frameRate, bool profile, bool properties) { m_show_framerate = frameRate; diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index 9e5d1893320..2b80e3bd69a 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -111,7 +111,6 @@ private: double m_frameTime;//discrete timestamp of the 'game logic frame' double m_clockTime;//current time double m_previousClockTime;//previous clock time - double m_previousAnimTime; //the last time animations were updated double m_remainingTime; static int m_maxLogicFrame; /* maximum number of consecutive logic frame */ @@ -175,8 +174,10 @@ private: bool m_showProperties; /** Show background behind text for readability? */ bool m_showBackground; - + /** Show debug properties on the game display*/ bool m_show_debug_properties; + /** Automatic add debug properties to the debug list*/ + bool m_autoAddDebugProperties; /** record physics into keyframes */ bool m_animation_record; @@ -222,6 +223,7 @@ public: PyObject* GetPyProfileDict(); #endif void SetSceneConverter(KX_ISceneConverter* sceneconverter); + KX_ISceneConverter* GetSceneConverter() { return m_sceneconverter; } void SetAnimRecordMode(bool animation_record, int startFrame); RAS_IRasterizer* GetRasterizer() { return m_rasterizer; } @@ -256,7 +258,7 @@ public: void ConvertAndAddScene(const STR_String& scenename,bool overlay); void RemoveScene(const STR_String& scenename); - void ReplaceScene(const STR_String& oldscene,const STR_String& newscene); + bool ReplaceScene(const STR_String& oldscene,const STR_String& newscene); void SuspendScene(const STR_String& scenename); void ResumeScene(const STR_String& scenename); @@ -354,6 +356,46 @@ public: static short GetExitKey(); /** + * \Sets the display for frame rate on or off. + */ + void SetShowFramerate(bool frameRate); + + /** + * \Gets the display for frame rate on or off. + */ + bool GetShowFramerate(); + + /** + * \Sets the display for individual components on or off. + */ + void SetShowProfile(bool profile); + + /** + * \Gets the display for individual components on or off. + */ + bool GetShowProfile(); + + /** + * \Sets the display of scene object debug properties on or off. + */ + void SetShowProperties(bool properties); + + /** + * \Gets the display of scene object debug properties on or off. + */ + bool GetShowProperties(); + + /** + * \Sets if the auto adding of scene object debug properties on or off. + */ + bool GetAutoAddDebugProperties(); + + /** + * \Sets the auto adding of scene object debug properties on or off. + */ + void SetAutoAddDebugProperties(bool add); + + /** * Activates or deactivates timing information display. * \param frameRate Display for frame rate on or off. * \param profile Display for individual components on or off. diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp index 37c36da0db3..33cfec57fc0 100644 --- a/source/gameengine/Ketsji/KX_Light.cpp +++ b/source/gameengine/Ketsji/KX_Light.cpp @@ -231,7 +231,7 @@ int KX_LightObject::pyattr_set_distance(void *self_v, const KX_PYATTRIBUTE_DEF * else if (val > 5000.f) val = 5000.f; - self->m_lightobj->m_energy = val; + self->m_lightobj->m_distance = val; return PY_SET_ATTR_SUCCESS; } @@ -242,7 +242,7 @@ int KX_LightObject::pyattr_set_distance(void *self_v, const KX_PYATTRIBUTE_DEF * PyObject *KX_LightObject::pyattr_get_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_LightObject* self = static_cast<KX_LightObject*>(self_v); - return Py_BuildValue("[fff]", self->m_lightobj->m_color[0], self->m_lightobj->m_color[1], self->m_lightobj->m_color[1]); + return Py_BuildValue("[fff]", self->m_lightobj->m_color[0], self->m_lightobj->m_color[1], self->m_lightobj->m_color[2]); } int KX_LightObject::pyattr_set_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) diff --git a/source/gameengine/Ketsji/KX_MouseActuator.cpp b/source/gameengine/Ketsji/KX_MouseActuator.cpp index 3d74bd7c98a..aae5d18189a 100644 --- a/source/gameengine/Ketsji/KX_MouseActuator.cpp +++ b/source/gameengine/Ketsji/KX_MouseActuator.cpp @@ -208,6 +208,9 @@ bool KX_MouseActuator::Update() parent->ApplyRotation(rotation, m_local_x); } } + else { + setposition[0] = 0.5; + } //Calculating Y axis. if (m_use_axis_y) { @@ -266,6 +269,9 @@ bool KX_MouseActuator::Update() parent->ApplyRotation(rotation, m_local_y); } } + else { + setposition[1] = 0.5; + } setMousePosition(setposition[0], setposition[1]); diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp index 2dbafdad3d9..a9f6bb0d2ff 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp @@ -60,15 +60,21 @@ KX_MouseFocusSensor::KX_MouseFocusSensor(SCA_MouseManager* eventmgr, int startx, int starty, - short int mousemode, - int focusmode, - bool bTouchPulse, - KX_Scene* kxscene, - KX_KetsjiEngine *kxengine, - SCA_IObject* gameobj) + short int mousemode, + int focusmode, + bool bTouchPulse, + const STR_String& propname, + bool bFindMaterial, + bool bXRay, + KX_Scene* kxscene, + KX_KetsjiEngine *kxengine, + SCA_IObject* gameobj) : SCA_MouseSensor(eventmgr, startx, starty, mousemode, gameobj), m_focusmode(focusmode), m_bTouchPulse(bTouchPulse), + m_bXRay(bXRay), + m_bFindMaterial(bFindMaterial), + m_propertyname(propname), m_kxscene(kxscene), m_kxengine(kxengine) { @@ -146,20 +152,73 @@ bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo *client_info, KX_RayCast *r * self-hits are excluded by setting the correct ignore-object.) * Hitspots now become valid. */ KX_GameObject* thisObj = (KX_GameObject*) GetParent(); + + bool bFound = false; + if ((m_focusmode == 2) || hitKXObj == thisObj) { - m_hitObject = hitKXObj; - m_hitPosition = result->m_hitPoint; - m_hitNormal = result->m_hitNormal; - m_hitUV = result->m_hitUV; - return true; + if (m_propertyname.Length() == 0) + { + bFound = true; + } + else + { + if (m_bFindMaterial) + { + if (client_info->m_auxilary_info) + { + bFound = (m_propertyname== ((char*)client_info->m_auxilary_info)); + } + } + else + { + bFound = hitKXObj->GetProperty(m_propertyname) != NULL; + } + } + + if (bFound) + { + m_hitObject = hitKXObj; + m_hitPosition = result->m_hitPoint; + m_hitNormal = result->m_hitNormal; + m_hitUV = result->m_hitUV; + return true; + } } return true; // object must be visible to trigger //return false; // occluded objects can trigger } - +/* this function is used to pre-filter the object before casting the ray on them. + * This is useful for "X-Ray" option when we want to see "through" unwanted object. + */ +bool KX_MouseFocusSensor::NeedRayCast(KX_ClientObjectInfo* client) +{ + if (client->m_type > KX_ClientObjectInfo::ACTOR) + { + // Unknown type of object, skip it. + // Should not occur as the sensor objects are filtered in RayTest() + printf("Invalid client type %d found ray casting\n", client->m_type); + return false; + } + if (m_bXRay && m_propertyname.Length() != 0) + { + if (m_bFindMaterial) + { + // not quite correct: an object may have multiple material + // should check all the material and not only the first one + if (!client->m_auxilary_info || (m_propertyname != ((char*)client->m_auxilary_info))) + return false; + } + else + { + if (client->m_gameobject->GetProperty(m_propertyname) == NULL) + return false; + } + } + return true; +} bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam) { @@ -384,7 +443,10 @@ PyAttributeDef KX_MouseFocusSensor::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("hitPosition", KX_MouseFocusSensor, pyattr_get_hit_position), KX_PYATTRIBUTE_RO_FUNCTION("hitNormal", KX_MouseFocusSensor, pyattr_get_hit_normal), KX_PYATTRIBUTE_RO_FUNCTION("hitUV", KX_MouseFocusSensor, pyattr_get_hit_uv), - KX_PYATTRIBUTE_BOOL_RW("usePulseFocus", KX_MouseFocusSensor,m_bTouchPulse), + KX_PYATTRIBUTE_BOOL_RW("usePulseFocus", KX_MouseFocusSensor, m_bTouchPulse), + KX_PYATTRIBUTE_BOOL_RW("useXRay", KX_MouseFocusSensor, m_bXRay), + KX_PYATTRIBUTE_BOOL_RW("useMaterial", KX_MouseFocusSensor, m_bFindMaterial), + KX_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, KX_MouseFocusSensor, m_propertyname), { NULL } //Sentinel }; diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h index 1f7809831e7..0c7c8ab676a 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h @@ -57,6 +57,9 @@ class KX_MouseFocusSensor : public SCA_MouseSensor short int mousemode, int focusmode, bool bTouchPulse, + const STR_String& propname, + bool bFindMaterial, + bool bXRay, KX_Scene* kxscene, KX_KetsjiEngine* kxengine, SCA_IObject* gameobj); @@ -88,7 +91,7 @@ class KX_MouseFocusSensor : public SCA_MouseSensor }; bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data); - bool NeedRayCast(KX_ClientObjectInfo* client) { return true; } + bool NeedRayCast(KX_ClientObjectInfo* client); const MT_Point3& RaySource() const; const MT_Point3& RayTarget() const; @@ -134,6 +137,21 @@ class KX_MouseFocusSensor : public SCA_MouseSensor bool m_bTouchPulse; /** + * Flags get through other objects + */ + bool m_bXRay; + + /** + * Flags material + */ + bool m_bFindMaterial; + + /** + * Property or material name + */ + STR_String m_propertyname; + + /** * Flags whether the previous test evaluated positive. */ bool m_positive_event; diff --git a/source/gameengine/Ketsji/KX_NavMeshObject.cpp b/source/gameengine/Ketsji/KX_NavMeshObject.cpp index 998b856497e..8360681759a 100644 --- a/source/gameengine/Ketsji/KX_NavMeshObject.cpp +++ b/source/gameengine/Ketsji/KX_NavMeshObject.cpp @@ -111,7 +111,7 @@ bool KX_NavMeshObject::BuildVertIndArrays(float *&vertices, int& nverts, float *&dvertices, int &ndvertsuniq, unsigned short *&dtris, int& ndtris, int &vertsPerPoly) { - DerivedMesh* dm = mesh_create_derived_no_virtual(KX_GetActiveScene()->GetBlenderScene(), GetBlenderObject(), + DerivedMesh* dm = mesh_create_derived_no_virtual(GetScene()->GetBlenderScene(), GetBlenderObject(), NULL, CD_MASK_MESH); CustomData *pdata = dm->getPolyDataLayout(dm); int* recastData = (int*) CustomData_get_layer(pdata, CD_RECAST); diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp index e9843b0af5b..ebf1b9ec577 100644 --- a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp +++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp @@ -740,6 +740,7 @@ PyObject *initPythonConstraintBinding() KX_MACRO_addTypesToDict(d, ANGULAR_CONSTRAINT, PHY_ANGULAR_CONSTRAINT); KX_MACRO_addTypesToDict(d, CONETWIST_CONSTRAINT, PHY_CONE_TWIST_CONSTRAINT); KX_MACRO_addTypesToDict(d, VEHICLE_CONSTRAINT, PHY_VEHICLE_CONSTRAINT); + KX_MACRO_addTypesToDict(d, GENERIC_6DOF_CONSTRAINT, PHY_GENERIC_6DOF_CONSTRAINT); // Check for errors if (PyErr_Occurred()) { diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index ca6658773e9..fefc64b4bad 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -88,6 +88,7 @@ extern "C" { #include "KX_SteeringActuator.h" #include "KX_NavMeshObject.h" #include "KX_MouseActuator.h" +#include "KX_TrackToActuator.h" #include "SCA_IInputDevice.h" #include "SCA_PropertySensor.h" @@ -200,7 +201,16 @@ static PyObject *gp_OrigPythonSysModules= NULL; //#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, PyLong_FromLong(SCA_IInputDevice::KX_##name)) //#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, item=PyLong_FromLong(name)); Py_DECREF(item) /* For the defines for types from logic bricks, we do stuff explicitly... */ -#define KX_MACRO_addTypesToDict(dict, name, name2) PyDict_SetItemString(dict, #name, item=PyLong_FromLong(name2)); Py_DECREF(item) +#define KX_MACRO_addTypesToDict(dict, name, value) KX_MACRO_addTypesToDict_fn(dict, #name, value) +static void KX_MACRO_addTypesToDict_fn(PyObject *dict, const char *name, long value) +{ + PyObject *item; + + item = PyLong_FromLong(value); + PyDict_SetItemString(dict, name, item); + Py_DECREF(item); +} + // temporarily python stuff, will be put in another place later ! @@ -247,7 +257,7 @@ static PyObject *gPyExpandPath(PyObject *, PyObject *args) BLI_strncpy(expanded, filename, FILE_MAX); BLI_path_abs(expanded, gp_GamePythonPath); - return PyUnicode_DecodeFSDefault(expanded); + return PyC_UnicodeFromByte(expanded); } static char gPyStartGame_doc[] = @@ -536,7 +546,7 @@ static PyObject *gPyGetBlendFileList(PyObject *, PyObject *args) while ((dirp = readdir(dp)) != NULL) { if (BLI_testextensie(dirp->d_name, ".blend")) { - value= PyUnicode_DecodeFSDefault(dirp->d_name); + value = PyC_UnicodeFromByte(dirp->d_name); PyList_Append(list, value); Py_DECREF(value); } @@ -1391,6 +1401,71 @@ static PyObject *gPyGetVsync(PyObject *) return PyLong_FromLong(interval); } +static PyObject *gPyShowFramerate(PyObject *, PyObject *args) +{ + int visible; + if (!PyArg_ParseTuple(args,"i:showFramerate",&visible)) + return NULL; + + if (visible && gp_KetsjiEngine) + gp_KetsjiEngine->SetShowFramerate(true); + else + gp_KetsjiEngine->SetShowFramerate(false); + + Py_RETURN_NONE; +} + +static PyObject *gPyShowProfile(PyObject *, PyObject *args) +{ + int visible; + if (!PyArg_ParseTuple(args,"i:showProfile",&visible)) + return NULL; + + if (visible && gp_KetsjiEngine) + gp_KetsjiEngine->SetShowProfile(true); + else + gp_KetsjiEngine->SetShowProfile(false); + + Py_RETURN_NONE; +} + +static PyObject *gPyShowProperties(PyObject *, PyObject *args) +{ + int visible; + if (!PyArg_ParseTuple(args,"i:showProperties",&visible)) + return NULL; + + if (visible && gp_KetsjiEngine) + gp_KetsjiEngine->SetShowProperties(true); + else + gp_KetsjiEngine->SetShowProperties(false); + + Py_RETURN_NONE; +} + +static PyObject *gPyAutoDebugList(PyObject *, PyObject *args) +{ + int add; + if (!PyArg_ParseTuple(args,"i:autoAddProperties",&add)) + return NULL; + + if (add && gp_KetsjiEngine) + gp_KetsjiEngine->SetAutoAddDebugProperties(true); + else + gp_KetsjiEngine->SetAutoAddDebugProperties(false); + + Py_RETURN_NONE; +} + +static PyObject *gPyClearDebugList(PyObject *) +{ + if (gp_KetsjiScene) + gp_KetsjiScene->RemoveAllDebugProperties(); + + Py_RETURN_NONE; +} + + static struct PyMethodDef rasterizer_methods[] = { {"getWindowWidth",(PyCFunction) gPyGetWindowWidth, METH_VARARGS, "getWindowWidth doc"}, @@ -1438,6 +1513,11 @@ static struct PyMethodDef rasterizer_methods[] = { {"getMipmapping", (PyCFunction) gPyGetMipmapping, METH_NOARGS, ""}, {"setVsync", (PyCFunction) gPySetVsync, METH_VARARGS, ""}, {"getVsync", (PyCFunction) gPyGetVsync, METH_NOARGS, ""}, + {"showFramerate",(PyCFunction) gPyShowFramerate, METH_VARARGS, "show or hide the framerate"}, + {"showProfile",(PyCFunction) gPyShowProfile, METH_VARARGS, "show or hide the profile"}, + {"showProperties",(PyCFunction) gPyShowProperties, METH_VARARGS, "show or hide the debug properties"}, + {"autoDebugList",(PyCFunction) gPyAutoDebugList, METH_VARARGS, "enable or disable auto adding debug properties to the debug list"}, + {"clearDebugList",(PyCFunction) gPyClearDebugList, METH_NOARGS, "clears the debug property list"}, { NULL, (PyCFunction) NULL, 0, NULL } }; @@ -1686,6 +1766,17 @@ PyObject *initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack 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); + /* TrackTo Actuator */ + KX_MACRO_addTypesToDict(d, KX_TRACK_UPAXIS_POS_X, KX_TrackToActuator::KX_TRACK_UPAXIS_POS_X); + KX_MACRO_addTypesToDict(d, KX_TRACK_UPAXIS_POS_Y, KX_TrackToActuator::KX_TRACK_UPAXIS_POS_Y); + KX_MACRO_addTypesToDict(d, KX_TRACK_UPAXIS_POS_Z, KX_TrackToActuator::KX_TRACK_UPAXIS_POS_Z); + KX_MACRO_addTypesToDict(d, KX_TRACK_TRAXIS_POS_X, KX_TrackToActuator::KX_TRACK_TRAXIS_POS_X); + KX_MACRO_addTypesToDict(d, KX_TRACK_TRAXIS_POS_Y, KX_TrackToActuator::KX_TRACK_TRAXIS_POS_Y); + KX_MACRO_addTypesToDict(d, KX_TRACK_TRAXIS_POS_Z, KX_TrackToActuator::KX_TRACK_TRAXIS_POS_Z); + KX_MACRO_addTypesToDict(d, KX_TRACK_TRAXIS_NEG_X, KX_TrackToActuator::KX_TRACK_TRAXIS_NEG_X); + KX_MACRO_addTypesToDict(d, KX_TRACK_TRAXIS_NEG_Y, KX_TrackToActuator::KX_TRACK_TRAXIS_NEG_Y); + KX_MACRO_addTypesToDict(d, KX_TRACK_TRAXIS_NEG_Z, KX_TrackToActuator::KX_TRACK_TRAXIS_NEG_Z); + /* Dynamic actuator */ KX_MACRO_addTypesToDict(d, KX_DYN_RESTORE_DYNAMICS, KX_SCA_DynamicActuator::KX_DYN_RESTORE_DYNAMICS); KX_MACRO_addTypesToDict(d, KX_DYN_DISABLE_DYNAMICS, KX_SCA_DynamicActuator::KX_DYN_DISABLE_DYNAMICS); @@ -1885,7 +1976,7 @@ static void initPySysObjects__append(PyObject *sys_path, const char *filename) BLI_split_dir_part(filename, expanded, sizeof(expanded)); /* get the dir part of filename only */ BLI_path_abs(expanded, gp_GamePythonPath); /* filename from lib->filename is (always?) absolute, so this may not be needed but it wont hurt */ BLI_cleanup_file(gp_GamePythonPath, expanded); /* Don't use BLI_cleanup_dir because it adds a slash - BREAKS WIN32 ONLY */ - item= PyUnicode_DecodeFSDefault(expanded); + item = PyC_UnicodeFromByte(expanded); // printf("SysPath - '%s', '%s', '%s'\n", expanded, filename, gp_GamePythonPath); @@ -2190,7 +2281,6 @@ PyObject *initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas) PyObject *m; PyObject *d; - PyObject *item; /* Use existing module where possible * be careful not to init any runtime vars after this */ @@ -2320,7 +2410,6 @@ PyObject *initGameKeys() { PyObject *m; PyObject *d; - PyObject *item; /* Use existing module where possible */ m = PyImport_ImportModule( "GameKeys" ); diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 3d71327828e..625bbee2c8e 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -595,7 +595,9 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal void KX_Scene::ReplicateLogic(KX_GameObject* newobj) { /* add properties to debug list, for added objects and DupliGroups */ - AddObjectDebugProperties(newobj); + if (KX_GetActiveEngine()->GetAutoAddDebugProperties()) { + AddObjectDebugProperties(newobj); + } // also relink the controller to sensors/actuators SCA_ControllerList& controllers = newobj->GetControllers(); //SCA_SensorList& sensors = newobj->GetSensors(); @@ -1005,7 +1007,7 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj) int ret; KX_GameObject* newobj = (KX_GameObject*) gameobj; - /* remove property to debug list */ + /* remove property from debug list */ RemoveObjectDebugProperties(newobj); /* Invalidate the python reference, since the object may exist in script lists @@ -1529,6 +1531,9 @@ void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam, int MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam, layer); } } + + // Now that we know visible meshes, update LoDs + UpdateObjectLods(); } // logic stuff @@ -1634,6 +1639,20 @@ static void update_anim_thread_func(TaskPool *pool, void *taskdata, int UNUSED(t void KX_Scene::UpdateAnimations(double curtime) { + KX_KetsjiEngine *engine = KX_GetActiveEngine(); + + if (engine->GetRestrictAnimationFPS()) + { + // Handle the animations independently of the logic time step + double anim_timestep = 1.0 / GetAnimationFPS(); + if (curtime - m_previousAnimTime < anim_timestep) + return; + + // Sanity/debug print to make sure we're actually going at the fps we want (should be close to anim_timestep) + // printf("Anim fps: %f\n", 1.0/(m_clockTime - m_previousAnimTime)); + m_previousAnimTime = curtime; + } + TaskPool *pool = BLI_task_pool_create(KX_GetActiveEngine()->GetTaskScheduler(), &curtime); for (int i=0; i<m_animatedlist->GetCount(); ++i) { @@ -2005,7 +2024,11 @@ bool KX_Scene::MergeScene(KX_Scene *other) { KX_GameObject* gameobj = (KX_GameObject*)other->GetObjectList()->GetValue(i); MergeScene_GameObject(gameobj, this, other); - AddObjectDebugProperties(gameobj); // add properties to debug list for LibLoad objects + + /* add properties to debug list for LibLoad objects */ + if (KX_GetActiveEngine()->GetAutoAddDebugProperties()) { + AddObjectDebugProperties(gameobj); + } gameobj->UpdateBuckets(false); /* only for active objects */ } @@ -2478,16 +2501,18 @@ KX_PYMETHODDEF_DOC(KX_Scene, restart, KX_PYMETHODDEF_DOC(KX_Scene, replace, "replace(newScene)\n" - "Replaces this scene with another one.\n") + "Replaces this scene with another one.\n" + "Return True if the new scene exists and scheduled for replacement, False otherwise.\n") { char* name; if (!PyArg_ParseTuple(args, "s:replace", &name)) return NULL; - KX_GetActiveEngine()->ReplaceScene(m_sceneName, name); + if (KX_GetActiveEngine()->ReplaceScene(m_sceneName, name)) + Py_RETURN_TRUE; - Py_RETURN_NONE; + Py_RETURN_FALSE; } KX_PYMETHODDEF_DOC(KX_Scene, suspend, diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index 2e1ee9f101d..c5840c28041 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -289,6 +289,8 @@ protected: double m_suspendedtime; double m_suspendeddelta; + double m_previousAnimTime; //the last time animations were updated + struct Scene* m_blenderScene; RAS_2DFilterManager m_filtermanager; diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.cpp b/source/gameengine/Ketsji/KX_SteeringActuator.cpp index 2fa72c04a20..ff192299702 100644 --- a/source/gameengine/Ketsji/KX_SteeringActuator.cpp +++ b/source/gameengine/Ketsji/KX_SteeringActuator.cpp @@ -602,7 +602,7 @@ int KX_SteeringActuator::pyattr_set_navmesh(void *self, const struct KX_PYATTRIB if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_SteeringActuator")) return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error - if (!PyObject_TypeCheck(value, &KX_NavMeshObject::Type)) + if (dynamic_cast<KX_NavMeshObject *>(gameobj) == NULL) { PyErr_Format(PyExc_TypeError, "KX_NavMeshObject is expected"); return PY_SET_ATTR_FAIL; diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp index 90b7850946b..75baf5fac1d 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp +++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp @@ -31,8 +31,7 @@ * Replace the mesh for this actuator's parent */ -/* todo: not all trackflags / upflags are implemented/tested ! - * m_trackflag is used to determine the forward tracking direction +/* m_trackflag is used to determine the forward tracking direction * m_upflag for the up direction * normal situation is +y for forward, +z for up */ @@ -177,7 +176,77 @@ static MT_Matrix3x3 matrix3x3_interpol(MT_Matrix3x3 oldmat, MT_Matrix3x3 mat, in return EulToMat3(eul); } +static float basis_cross(int n, int m) +{ + switch (n - m) { + case 1: + case -2: + return 1.0f; + + case -1: + case 2: + return -1.0f; + + default: + return 0.0f; + } +} +/* vectomat function obtained from constrain.c and modified to work with MOTO library */ +static MT_Matrix3x3 vectomat(MT_Vector3 vec, short axis, short upflag, short threedimup) +{ + MT_Matrix3x3 mat; + MT_Vector3 y(MT_Scalar(0.0), MT_Scalar(1.0), MT_Scalar(0.0)); + MT_Vector3 z(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(1.0)); /* world Z axis is the global up axis */ + MT_Vector3 proj; + MT_Vector3 right; + MT_Scalar mul; + int right_index; + + /* Normalized Vec vector*/ + vec = vec.safe_normalized_vec(z); + + /* if 2D doesn't move the up vector */ + if (!threedimup){ + vec.setValue(MT_Scalar(vec[0]), MT_Scalar(vec[1]), MT_Scalar(0.0)); + vec = (vec - z.dot(vec)*z).safe_normalized_vec(z); + } + + if (axis > 2) + axis -= 3; + else + vec = -vec; + + /* project the up vector onto the plane specified by vec */ + /* first z onto vec... */ + mul = z.dot(vec) / vec.dot(vec); + proj = vec * mul; + /* then onto the plane */ + proj = z - proj; + /* proj specifies the transformation of the up axis */ + proj = proj.safe_normalized_vec(y); + + /* Normalized cross product of vec and proj specifies transformation of the right axis */ + right = proj.cross(vec); + right.normalize(); + + if (axis != upflag) { + right_index = 3 - axis - upflag; + + /* account for up direction, track direction */ + right = right * basis_cross(axis, upflag); + mat.setRow(right_index, right); + mat.setRow(upflag, proj); + mat.setRow(axis, vec); + mat = mat.inverse(); + } + /* identity matrix - don't do anything if the two axes are the same */ + else { + mat.setIdentity(); + } + + return mat; +} KX_TrackToActuator::~KX_TrackToActuator() { @@ -247,153 +316,24 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) else if (m_object) { KX_GameObject* curobj = (KX_GameObject*) GetParent(); - MT_Vector3 dir = ((KX_GameObject*)m_object)->NodeGetWorldPosition() - curobj->NodeGetWorldPosition(); - if (dir.length2()) - dir.normalize(); - MT_Vector3 up(0,0,1); - - -#ifdef DSADSA - switch (m_upflag) - { - case 0: - { - up.setValue(1.0,0,0); - break; - } - case 1: - { - up.setValue(0,1.0,0); - break; - } - case 2: - default: - { - up.setValue(0,0,1.0); - } - } -#endif - if (m_allow3D) - { - up = (up - up.dot(dir) * dir).safe_normalized(); - - } - else - { - dir = (dir - up.dot(dir)*up).safe_normalized(); - } - - MT_Vector3 left; + MT_Vector3 dir = curobj->NodeGetWorldPosition() - ((KX_GameObject*)m_object)->NodeGetWorldPosition(); MT_Matrix3x3 mat; - - switch (m_trackflag) - { - case 0: // TRACK X - { - // (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up - left = dir.safe_normalized(); - dir = up.cross(left).safe_normalized(); - mat.setValue ( - left[0], dir[0],up[0], - left[1], dir[1],up[1], - left[2], dir[2],up[2] - ); - - break; - }; - case 1: // TRACK Y - { - // (0.0 , 1.0 , 0.0 ) y direction is forward, z (0.0 , 0.0 , 1.0 ) up - left = (dir.cross(up)).safe_normalized(); - mat.setValue ( - left[0], dir[0],up[0], - left[1], dir[1],up[1], - left[2], dir[2],up[2] - ); - - break; - } - - case 2: // track Z - { - left = up.safe_normalized(); - up = dir.safe_normalized(); - dir = left; - left = (dir.cross(up)).safe_normalized(); - mat.setValue ( - left[0], dir[0],up[0], - left[1], dir[1],up[1], - left[2], dir[2],up[2] - ); - break; - } - - case 3: // TRACK -X - { - // (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up - left = -dir.safe_normalized(); - dir = up.cross(left).safe_normalized(); - mat.setValue ( - left[0], dir[0],up[0], - left[1], dir[1],up[1], - left[2], dir[2],up[2] - ); - - break; - }; - case 4: // TRACK -Y - { - // (0.0 , -1.0 , 0.0 ) -y direction is forward, z (0.0 , 0.0 , 1.0 ) up - left = (-dir.cross(up)).safe_normalized(); - mat.setValue ( - left[0], -dir[0],up[0], - left[1], -dir[1],up[1], - left[2], -dir[2],up[2] - ); - break; - } - case 5: // track -Z - { - left = up.safe_normalized(); - up = -dir.safe_normalized(); - dir = left; - left = (dir.cross(up)).safe_normalized(); - mat.setValue ( - left[0], dir[0],up[0], - left[1], dir[1],up[1], - left[2], dir[2],up[2] - ); - - break; - } - - default: - { - // (1.0 , 0.0 , 0.0 ) -x direction is forward, z (0.0 , 0.0 , 1.0 ) up - left = -dir.safe_normalized(); - dir = up.cross(left).safe_normalized(); - mat.setValue ( - left[0], dir[0],up[0], - left[1], dir[1],up[1], - left[2], dir[2],up[2] - ); - } - } - MT_Matrix3x3 oldmat; - oldmat= curobj->NodeGetWorldOrientation(); + + mat = vectomat(dir, m_trackflag, m_upflag, m_allow3D); + oldmat = curobj->NodeGetWorldOrientation(); /* erwin should rewrite this! */ - mat= matrix3x3_interpol(oldmat, mat, m_time); + mat = matrix3x3_interpol(oldmat, mat, m_time); - - if (m_parentobj) { // check if the model is parented and calculate the child transform + /* check if the model is parented and calculate the child transform */ + if (m_parentobj) { MT_Point3 localpos; localpos = curobj->GetSGNode()->GetLocalPosition(); // Get the inverse of the parent matrix MT_Matrix3x3 parentmatinv; - parentmatinv = m_parentobj->NodeGetWorldOrientation ().inverse (); + parentmatinv = m_parentobj->NodeGetWorldOrientation().inverse(); // transform the local coordinate system into the parents system mat = parentmatinv * mat; // append the initial parent local rotation matrix @@ -404,8 +344,7 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) curobj->NodeSetLocalPosition(localpos); //curobj->UpdateTransform(); } - else - { + else { curobj->NodeSetLocalOrientation(mat); } @@ -451,6 +390,8 @@ PyMethodDef KX_TrackToActuator::Methods[] = { PyAttributeDef KX_TrackToActuator::Attributes[] = { KX_PYATTRIBUTE_INT_RW("time",0,1000,true,KX_TrackToActuator,m_time), KX_PYATTRIBUTE_BOOL_RW("use3D",KX_TrackToActuator,m_allow3D), + KX_PYATTRIBUTE_INT_RW("upAxis", 0, 2, true, KX_TrackToActuator,m_upflag), + KX_PYATTRIBUTE_INT_RW("trackAxis", 0, 5, true, KX_TrackToActuator,m_trackflag), KX_PYATTRIBUTE_RW_FUNCTION("object", KX_TrackToActuator, pyattr_get_object, pyattr_set_object), { NULL } //Sentinel diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.h b/source/gameengine/Ketsji/KX_TrackToActuator.h index 4df240a0063..124014eede2 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.h +++ b/source/gameengine/Ketsji/KX_TrackToActuator.h @@ -68,6 +68,21 @@ class KX_TrackToActuator : public SCA_IActuator virtual void Relink(CTR_Map<CTR_HashedPtr, void*> *obj_map); virtual bool Update(double curtime, bool frame); + //Python Interface + enum UpAxis { + KX_TRACK_UPAXIS_POS_X = 0, + KX_TRACK_UPAXIS_POS_Y, + KX_TRACK_UPAXIS_POS_Z + }; + enum TrackAxis { + KX_TRACK_TRAXIS_POS_X = 0, + KX_TRACK_TRAXIS_POS_Y, + KX_TRACK_TRAXIS_POS_Z, + KX_TRACK_TRAXIS_NEG_X, + KX_TRACK_TRAXIS_NEG_Y, + KX_TRACK_TRAXIS_NEG_Z + }; + #ifdef WITH_PYTHON /* Python part */ diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt index e295b701b36..e52dc1ba052 100644 --- a/source/gameengine/Physics/Bullet/CMakeLists.txt +++ b/source/gameengine/Physics/Bullet/CMakeLists.txt @@ -29,6 +29,7 @@ remove_strict_flags() set(INC . ../common + ../../Converter ../../Expressions ../../GameLogic ../../Ketsji diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index 69e190c79db..e17d4402556 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -42,6 +42,7 @@ subject to the following restrictions: #include "PHY_Pro.h" #include "KX_GameObject.h" #include "KX_PythonInit.h" // for KX_RasterizerDrawDebugLine +#include "KX_BlenderSceneConverter.h" #include "RAS_MeshObject.h" #include "RAS_Polygon.h" #include "RAS_TexVert.h" @@ -83,7 +84,7 @@ void DrawRasterizerLine(const float* from,const float* to,int color); // This was copied from the old KX_ConvertPhysicsObjects #ifdef WIN32 -#if defined(_MSC_VER) && (_MSC_VER >= 1310) +#ifdef _MSC_VER //only use SIMD Hull code under Win32 //#define TEST_HULL 1 #ifdef TEST_HULL @@ -877,6 +878,14 @@ void CcdPhysicsEnvironment::ProcessFhSprings(double curTime,float interval) } } +int CcdPhysicsEnvironment::GetDebugMode() const +{ + if (m_debugDrawer) { + return m_debugDrawer->getDebugMode(); + } + return 0; +} + void CcdPhysicsEnvironment::SetDebugMode(int debugMode) { if (m_debugDrawer) { @@ -2085,7 +2094,7 @@ void CcdPhysicsEnvironment::SetConstraintParam(int constraintId,int param,float case 12: case 13: case 14: case 15: case 16: case 17: { - //param 13-17 are for motorized springs on each of the degrees of freedom + //param 12-17 are for motorized springs on each of the degrees of freedom btGeneric6DofSpringConstraint* genCons = (btGeneric6DofSpringConstraint*)typedConstraint; int springIndex = param-12; if (value0!=0.f) @@ -3036,9 +3045,17 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject CcdConstructionInfo ci; class CcdShapeConstructionInfo *shapeInfo = new CcdShapeConstructionInfo(); - KX_GameObject *parent = gameobj->GetParent(); - if (parent) + // get Root Parent of blenderobject + Object *blenderparent = blenderobject->parent; + while (blenderparent && blenderparent->parent) { + blenderparent = blenderparent->parent; + } + + KX_GameObject *parent = NULL; + if (blenderparent) { + KX_BlenderSceneConverter *converter = (KX_BlenderSceneConverter*)KX_GetActiveEngine()->GetSceneConverter(); + parent = converter->FindGameObject(blenderparent); isbulletdyna = false; isbulletsoftbody = false; shapeprops->m_mass = 0.f; diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h index a94e205b160..ff8a3f4f9f9 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h @@ -139,6 +139,7 @@ protected: virtual float GetFixedTimeStep() { return 0.f; } virtual void SetDebugMode(int debugMode); + virtual int GetDebugMode()const; virtual void SetGravity(float x,float y,float z); virtual void GetGravity(MT_Vector3& grav); diff --git a/source/gameengine/Physics/Bullet/SConscript b/source/gameengine/Physics/Bullet/SConscript index 2700997ccd4..2a8249b9558 100644 --- a/source/gameengine/Physics/Bullet/SConscript +++ b/source/gameengine/Physics/Bullet/SConscript @@ -39,6 +39,7 @@ incs = [ '#source/blender/blenkernel', '#source/blender/blenlib', '#source/blender/makesdna', + '#source/gameengine/Converter', '#source/gameengine/Expressions', '#source/gameengine/GameLogic', '#source/gameengine/Ketsji', diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp index 1bb5431c749..979128370ee 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp @@ -78,8 +78,10 @@ float DummyPhysicsEnvironment::GetFixedTimeStep() return 0.f; } - - +int DummyPhysicsEnvironment::GetDebugMode() const +{ + return 0; +} void DummyPhysicsEnvironment::SetGravity(float x,float y,float z) { diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h index a645af1e471..cfc8841cac2 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h @@ -56,6 +56,8 @@ public: virtual void SetFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep); virtual float GetFixedTimeStep(); + virtual int GetDebugMode() const; + virtual void SetGravity(float x,float y,float z); virtual void GetGravity(class MT_Vector3& grav); diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h index 81a45f93993..dd762b02b4e 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h @@ -126,6 +126,8 @@ class PHY_IPhysicsEnvironment //returns 0.f if no fixed timestep is used virtual float GetFixedTimeStep()=0; + ///getDebugMode return the actual debug visualization state + virtual int GetDebugMode()const=0; ///setDebugMode is used to support several ways of debug lines, contact point visualization virtual void SetDebugMode(int debugMode) {} ///setNumIterations set the number of iterations for iterative solvers diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp index 61c658b22fd..e0613350b77 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp @@ -247,7 +247,7 @@ void RAS_StorageIM::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi) //ms.m_pDerivedMesh->drawMappedFacesTex(ms.m_pDerivedMesh, CheckTexfaceDM, mcol); current_blmat_nr = current_polymat->GetMaterialIndex(); current_image = current_polymat->GetBlenderImage(); - ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL); + ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL, DM_DRAW_USE_ACTIVE_UV); } return; } diff --git a/source/gameengine/VideoTexture/ImageBuff.cpp b/source/gameengine/VideoTexture/ImageBuff.cpp index 6cc8d287e66..705d9136cbe 100644 --- a/source/gameengine/VideoTexture/ImageBuff.cpp +++ b/source/gameengine/VideoTexture/ImageBuff.cpp @@ -163,7 +163,7 @@ void ImageBuff::plot(unsigned char *img, short width, short height, short x, sho // assign temporarily our buffer to the ImBuf buffer, we use the same format tmpbuf->rect = (unsigned int*)img; m_imbuf->rect = m_image; - IMB_rectblend(m_imbuf, m_imbuf, tmpbuf, NULL, NULL, 0, x, y, x, y, 0, 0, width, height, (IMB_BlendMode)mode); + IMB_rectblend(m_imbuf, m_imbuf, tmpbuf, NULL, NULL, NULL, 0, x, y, x, y, 0, 0, width, height, (IMB_BlendMode)mode, false); // remove so that MB_freeImBuf will free our buffer m_imbuf->rect = NULL; tmpbuf->rect = NULL; @@ -186,7 +186,7 @@ void ImageBuff::plot(ImageBuff *img, short x, short y, short mode) // assign temporarily our buffer to the ImBuf buffer, we use the same format img->m_imbuf->rect = img->m_image; m_imbuf->rect = m_image; - IMB_rectblend(m_imbuf, m_imbuf, img->m_imbuf, NULL, NULL, 0, x, y, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode); + IMB_rectblend(m_imbuf, m_imbuf, img->m_imbuf, NULL, NULL, NULL, 0, x, y, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode, false); // remove so that MB_freeImBuf will free our buffer m_imbuf->rect = NULL; img->m_imbuf->rect = NULL; diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp index 57b2e85845c..617e7fd1d8e 100644 --- a/source/gameengine/VideoTexture/ImageRender.cpp +++ b/source/gameengine/VideoTexture/ImageRender.cpp @@ -274,6 +274,8 @@ void ImageRender::Render() m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera); + m_scene->UpdateAnimations(m_engine->GetFrameTime()); + m_scene->RenderBuckets(camtrans, m_rasterizer); m_scene->RenderFonts(); diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp index 179f1ced03b..edf3c58bcbe 100644 --- a/source/gameengine/VideoTexture/VideoFFmpeg.cpp +++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp @@ -545,6 +545,7 @@ void VideoFFmpeg::openFile (char *filename) // but it is really not desirable to seek on http file, so force streaming. // It would be good to find this information from the context but there are no simple indication !strncmp(filename, "http://", 7) || + !strncmp(filename, "rtsp://", 7) || (m_formatCtx->pb && !m_formatCtx->pb->seekable) ) { @@ -680,6 +681,12 @@ bool VideoFFmpeg::play (void) { // set video position setPositions(); + + if (m_isStreaming) + { + av_read_play(m_formatCtx); + } + // return success return true; } @@ -696,6 +703,10 @@ bool VideoFFmpeg::pause (void) { if (VideoBase::pause()) { + if (m_isStreaming) + { + av_read_pause(m_formatCtx); + } return true; } } |