diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2015-02-10 19:09:00 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2015-02-10 19:09:00 +0300 |
commit | e89fd502d7b1ee5a4c17286a78ae0116f03510b7 (patch) | |
tree | 5c68b5cb560b3cc5ba62046167d364b2183abb11 /source/blender/editors | |
parent | 6cd3ebfc9fa4838a74192f2e5cc82b5d5d2e6fe7 (diff) | |
parent | 227a94077f508a47fe7595b9091ab86aecde4ad5 (diff) |
Merge branch 'master' into alembic_pointcache
Conflicts:
CMakeLists.txt
build_files/build_environment/install_deps.sh
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/SConscript
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/pointcache.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/space_outliner/outliner_draw.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesrna/SConscript
source/blender/makesrna/intern/CMakeLists.txt
source/blender/makesrna/intern/SConscript
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_object_force.c
source/blender/modifiers/MOD_modifiertypes.h
source/blender/modifiers/intern/MOD_util.c
source/blender/render/intern/source/voxeldata.c
Diffstat (limited to 'source/blender/editors')
155 files changed, 4568 insertions, 1919 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index d76eba93640..37c40052275 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -61,6 +61,7 @@ #include "RNA_access.h" +#include "BKE_animsys.h" #include "BKE_curve.h" #include "BKE_key.h" #include "BKE_nla.h" @@ -3519,6 +3520,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float /* step 5) draw name ............................................... */ /* TODO: when renaming, we might not want to draw this, especially if name happens to be longer than channel */ if (acf->name) { + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */ /* set text color */ @@ -3532,7 +3534,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float acf->name(ale, name); offset += 3; - UI_draw_string(offset, ytext, name); + UI_fontstyle_draw_simple(fstyle, offset, ytext, name); /* draw red underline if channel is disabled */ if ((ale->type == ANIMTYPE_FCURVE) && (ale->flag & FCURVE_DISABLED)) { @@ -3688,6 +3690,7 @@ static void achannel_nlatrack_solo_widget_cb(bContext *C, void *adt_poin, void * static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poin) { ID *id = (ID *)id_poin; + AnimData *adt = BKE_animdata_from_id(id); FCurve *fcu = (FCurve *)fcu_poin; ReportList *reports = CTX_wm_reports(C); @@ -3698,9 +3701,8 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi bool done = false; float cfra; - /* get current frame */ - // NOTE: this will do for now... - cfra = (float)CFRA; + /* get current frame and apply NLA-mapping to it (if applicable) */ + cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); /* get flags for keyframing */ flag = ANIM_get_keyframing_flags(scene, 1); @@ -3737,9 +3739,8 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi bool done = false; float cfra; - /* get current frame */ - // NOTE: this will do for now... - cfra = (float)CFRA; + /* get current frame and apply NLA-mapping to it (if applicable) */ + cfra = BKE_nla_tweakedit_remap(key->adt, (float)CFRA, NLATIME_CONVERT_UNMAP); /* get flags for keyframing */ flag = ANIM_get_keyframing_flags(scene, 1); diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 2d7656642d3..0e052279796 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -59,6 +59,7 @@ /* Draw current frame number in a little green box beside the current frame indicator */ static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const bool time) { + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; float xscale, yscale, x, y; char numstr[32] = " t"; /* t is the character to start replacing from */ int slen; @@ -78,7 +79,8 @@ static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const else { BLI_timecode_string_from_time_simple(&numstr[4], sizeof(numstr) - 4, 1, cfra); } - slen = UI_fontstyle_string_width(numstr) - 1; + + slen = UI_fontstyle_string_width(fstyle, numstr) - 1; /* get starting coordinates for drawing */ x = cfra * xscale; @@ -90,7 +92,7 @@ static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const /* draw current frame number - black text */ UI_ThemeColor(TH_TEXT); - UI_draw_string(x - 0.25f * U.widget_unit, y + 0.15f * U.widget_unit, numstr); + UI_fontstyle_draw_simple(fstyle, x - 0.25f * U.widget_unit, y + 0.15f * U.widget_unit, numstr); /* restore view transform */ glScalef(xscale, 1.0, 1.0); diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index b6c7a4aa5a0..140b7e0b117 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -317,7 +317,7 @@ void debug_markers_print_list(ListBase *markers) /* function to draw markers */ static void draw_marker( - View2D *v2d, TimeMarker *marker, int cfra, int flag, + View2D *v2d, const uiFontStyle *fstyle, TimeMarker *marker, int cfra, int flag, /* avoid re-calculating each time */ const float ypixels, const float xscale, const float yscale) { @@ -399,13 +399,14 @@ static void draw_marker( } #endif - UI_draw_string(x, y, marker->name); + UI_fontstyle_draw_simple(fstyle, x, y, marker->name); } } /* Draw Scene-Markers in time window */ void ED_markers_draw(const bContext *C, int flag) { + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; ListBase *markers = ED_context_get_markers(C); View2D *v2d; TimeMarker *marker; @@ -455,7 +456,7 @@ void ED_markers_draw(const bContext *C, int flag) if ((marker->frame >= v2d_clip_range_x[0]) && (marker->frame <= v2d_clip_range_x[1])) { - draw_marker(v2d, marker, scene->r.cfra, flag, + draw_marker(v2d, fstyle, marker, scene->r.cfra, flag, ypixels, xscale, yscale); } } @@ -1056,7 +1057,7 @@ static void select_timeline_marker_frame(ListBase *markers, int frame, bool exte } BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) { - /* this way a not-extend select will allways give 1 selected marker */ + /* this way a not-extend select will always give 1 selected marker */ if (marker->frame == frame) { marker->flag ^= SELECT; break; diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c index 8ede1a0ad76..bcdad1c93ad 100644 --- a/source/blender/editors/animation/fmodifier_ui.c +++ b/source/blender/editors/animation/fmodifier_ui.c @@ -130,6 +130,7 @@ static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, s switch (data->mode) { case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */ { + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; float *cp = NULL; char xval[32]; unsigned int i; @@ -147,11 +148,12 @@ static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, s /* calculate maximum width of label for "x^n" labels */ if (data->arraysize > 2) { BLI_snprintf(xval, sizeof(xval), "x^%u", data->arraysize); - maxXWidth = UI_fontstyle_string_width(xval) + 0.5 * UI_UNIT_X; /* XXX: UI_fontstyle_string_width is not accurate */ + /* XXX: UI_fontstyle_string_width is not accurate */ + maxXWidth = UI_fontstyle_string_width(fstyle, xval) + 0.5 * UI_UNIT_X; } else { /* basic size (just "x") */ - maxXWidth = UI_fontstyle_string_width("x") + 0.5 * UI_UNIT_X; + maxXWidth = UI_fontstyle_string_width(fstyle, "x") + 0.5 * UI_UNIT_X; } /* draw controls for each coefficient and a + sign at end of row */ diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 439b3b94974..ee1bfdff0bd 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -785,7 +785,8 @@ static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt) static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { if (bezt->f2 & SELECT) { - mirror_bezier_yaxis_ex(bezt, 0.0f); + /* Yes, names are inverted, we are mirroring accross y axis, hence along x axis... */ + mirror_bezier_xaxis_ex(bezt, 0.0f); } return 0; @@ -794,7 +795,8 @@ static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt) static short mirror_bezier_xaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { if (bezt->f2 & SELECT) { - mirror_bezier_xaxis_ex(bezt, 0.0f); + /* Yes, names are inverted, we are mirroring accross x axis, hence along y axis... */ + mirror_bezier_yaxis_ex(bezt, 0.0f); } return 0; @@ -814,7 +816,7 @@ static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt) { /* value to mirror over is stored in the custom data -> first float value slot */ if (bezt->f2 & SELECT) { - mirror_bezier_xaxis_ex(bezt, ked->f1); + mirror_bezier_yaxis_ex(bezt, ked->f1); } return 0; diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 7ac11c1cd06..932a00d1687 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -641,7 +641,7 @@ static void flip_names(tAnimCopybufItem *aci, char **name) str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path"); BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1); - str_iter += prefix_l ; + str_iter += prefix_l; BLI_strncpy(str_iter, bname_new, length + 1); str_iter += length; BLI_strncpy(str_iter, str_end, postfix_l + 1); @@ -663,14 +663,14 @@ static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_ if ((from_single) || (aci->array_index == fcu->array_index)) { char *name = NULL; flip_names(aci, &name); - if (strcmp(name, fcu->rna_path) == 0) { + if (STREQ(name, fcu->rna_path)) { MEM_freeN(name); break; } MEM_freeN(name); } } - else if (to_simple || (strcmp(aci->rna_path, fcu->rna_path) == 0)) { + else if (to_simple || STREQ(aci->rna_path, fcu->rna_path)) { if ((from_single) || (aci->array_index == fcu->array_index)) { break; } @@ -711,7 +711,7 @@ static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short f int len_path = strlen(fcu->rna_path); if (len_id <= len_path) { /* note, paths which end with "] will fail with this test - Animated ID Props */ - if (strcmp(identifier, fcu->rna_path + (len_path - len_id)) == 0) { + if (STREQ(identifier, fcu->rna_path + (len_path - len_id))) { if ((from_single) || (aci->array_index == fcu->array_index)) break; } diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index a5c0eee8d3b..4b9a629183e 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -556,7 +556,7 @@ KeyingSet *ANIM_builtin_keyingset_get_named(KeyingSet *prevKS, const char name[] /* loop over KeyingSets checking names */ for (ks = first; ks; ks = ks->next) { - if (strcmp(name, ks->idname) == 0) + if (STREQ(name, ks->idname)) return ks; } @@ -603,7 +603,7 @@ void ANIM_keyingset_info_unregister(Main *bmain, KeyingSetInfo *ksi) ksn = ks->next; /* remove if matching typeinfo name */ - if (strcmp(ks->typeinfo, ksi->idname) == 0) { + if (STREQ(ks->typeinfo, ksi->idname)) { Scene *scene; BKE_keyingset_free(ks); BLI_remlink(&builtin_keyingsets, ks); @@ -914,6 +914,37 @@ short ANIM_validate_keyingset(bContext *C, ListBase *dsources, KeyingSet *ks) return 0; } +/* Determine which keying flags apply based on the override flags */ +static short keyingset_apply_keying_flags(const short base_flags, const short overrides, const short own_flags) +{ + short result = 0; + + /* The logic for whether a keying flag applies is as follows: + * - If the flag in question is set in "overrides", that means that the + * status of that flag in "own_flags" is used + * - If however the flag isn't set, then its value in "base_flags" is used + * instead (i.e. no override) + */ +#define APPLY_KEYINGFLAG_OVERRIDE(kflag) \ + if (overrides & kflag) { \ + result |= (own_flags & kflag); \ + } \ + else { \ + result |= (base_flags & kflag); \ + } + + /* Apply the flags one by one... + * (See rna_def_common_keying_flags() for the supported flags) + */ + APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_NEEDED) + APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_MATRIX) + APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_XYZ2RGB) + +#undef APPLY_KEYINGFLAG_OVERRIDE + + return result; +} + /* Given a KeyingSet and context info (if required), modify keyframes for the channels specified * by the KeyingSet. This takes into account many of the different combinations of using KeyingSets. * Returns the number of channels that keyframes were added to @@ -923,7 +954,8 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe Scene *scene = CTX_data_scene(C); ReportList *reports = CTX_wm_reports(C); KS_Path *ksp; - int kflag = 0, success = 0; + const short base_kflags = ANIM_get_keyframing_flags(scene, 1); + short kflag = 0, success = 0; const char *groupname = NULL; /* sanity checks */ @@ -932,11 +964,8 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe /* get flags to use */ if (mode == MODIFYKEY_MODE_INSERT) { - /* use KeyingSet's flags as base */ - kflag = ks->keyingflag; - - /* supplement with info from the context */ - kflag |= ANIM_get_keyframing_flags(scene, 1); + /* use context settings as base */ + kflag = keyingset_apply_keying_flags(base_kflags, ks->keyingoverride, ks->keyingflag); } else if (mode == MODIFYKEY_MODE_DELETE) kflag = 0; @@ -962,8 +991,8 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe continue; } - /* since keying settings can be defined on the paths too, extend the path before using it */ - kflag2 = (kflag | ksp->keyingflag); + /* since keying settings can be defined on the paths too, apply the settings for this path first */ + kflag2 = keyingset_apply_keying_flags(kflag, ksp->keyingoverride, ksp->keyingflag); /* get pointer to name of group to add channels to */ if (ksp->groupmode == KSP_GROUP_NONE) diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index eba1bc4d78d..22aaeccc4a8 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -270,7 +270,7 @@ static EditBone *get_named_editbone(ListBase *edbo, const char *name) if (name) { for (eBone = edbo->first; eBone; eBone = eBone->next) { - if (!strcmp(name, eBone->name)) + if (STREQ(name, eBone->name)) return eBone; } } diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 7f7843a6d1d..88c52989c07 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -38,6 +38,8 @@ #include "MEM_guardedalloc.h" +#include "BLF_translation.h" + #include "BLI_blenlib.h" #include "BLI_math.h" @@ -236,28 +238,49 @@ float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const bool return roll; } - +/* note, ranges arithmatic is used below */ typedef enum eCalcRollTypes { - CALC_ROLL_X = 0, - CALC_ROLL_Y = 1, - CALC_ROLL_Z = 2, - - CALC_ROLL_TAN_X = 3, - CALC_ROLL_TAN_Z = 4, - - CALC_ROLL_ACTIVE = 5, - CALC_ROLL_VIEW = 6, - CALC_ROLL_CURSOR = 7, + /* pos */ + CALC_ROLL_POS_X = 0, + CALC_ROLL_POS_Y, + CALC_ROLL_POS_Z, + + CALC_ROLL_TAN_POS_X, + CALC_ROLL_TAN_POS_Z, + + /* neg */ + CALC_ROLL_NEG_X, + CALC_ROLL_NEG_Y, + CALC_ROLL_NEG_Z, + + CALC_ROLL_TAN_NEG_X, + CALC_ROLL_TAN_NEG_Z, + + /* no sign */ + CALC_ROLL_ACTIVE, + CALC_ROLL_VIEW, + CALC_ROLL_CURSOR, } eCalcRollTypes; static EnumPropertyItem prop_calc_roll_types[] = { - {CALC_ROLL_TAN_X, "X", 0, "Local X Tangent", ""}, - {CALC_ROLL_TAN_Z, "Z", 0, "Local Z Tangent", ""}, + {0, "", 0, N_("Positive"), ""}, + {CALC_ROLL_TAN_POS_X, "POS_X", 0, "Local +X Tangent", ""}, + {CALC_ROLL_TAN_POS_Z, "POS_Z", 0, "Local +Z Tangent", ""}, + + {CALC_ROLL_POS_X, "GLOBAL_POS_X", 0, "Global +X Axis", ""}, + {CALC_ROLL_POS_Y, "GLOBAL_POS_Y", 0, "Global +Y Axis", ""}, + {CALC_ROLL_POS_Z, "GLOBAL_POS_Z", 0, "Global +Z Axis", ""}, - {CALC_ROLL_X, "GLOBAL_X", 0, "Global X Axis", ""}, - {CALC_ROLL_Y, "GLOBAL_Y", 0, "Global Y Axis", ""}, - {CALC_ROLL_Z, "GLOBAL_Z", 0, "Global Z Axis", ""}, + {0, "", 0, N_("Negative"), ""}, + {CALC_ROLL_TAN_NEG_X, "NEG_X", 0, "Local -X Tangent", ""}, + {CALC_ROLL_TAN_NEG_Z, "NEG_Z", 0, "Local -Z Tangent", ""}, + + {CALC_ROLL_NEG_X, "GLOBAL_NEG_X", 0, "Global -X Axis", ""}, + {CALC_ROLL_NEG_Y, "GLOBAL_NEG_Y", 0, "Global -Y Axis", ""}, + {CALC_ROLL_NEG_Z, "GLOBAL_NEG_Z", 0, "Global -Z Axis", ""}, + + {0, "", 0, N_("Other"), ""}, {CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""}, {CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""}, {CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""}, @@ -268,15 +291,22 @@ static EnumPropertyItem prop_calc_roll_types[] = { static int armature_calc_roll_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_edit_object(C); - const short type = RNA_enum_get(op->ptr, "type"); + eCalcRollTypes type = RNA_enum_get(op->ptr, "type"); const bool axis_only = RNA_boolean_get(op->ptr, "axis_only"); - const bool axis_flip = RNA_boolean_get(op->ptr, "axis_flip"); + /* axis_flip when matching the active bone never makes sense */ + bool axis_flip = ((type >= CALC_ROLL_ACTIVE) ? RNA_boolean_get(op->ptr, "axis_flip") : + (type >= CALC_ROLL_TAN_NEG_X) ? true : false); float imat[3][3]; bArmature *arm = ob->data; EditBone *ebone; + if ((type >= CALC_ROLL_NEG_X) && (type <= CALC_ROLL_TAN_NEG_Z)) { + type -= (CALC_ROLL_ACTIVE - CALC_ROLL_NEG_X); + axis_flip = true; + } + copy_m3_m4(imat, ob->obmat); invert_m3(imat); @@ -302,7 +332,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op) } } } - else if (ELEM(type, CALC_ROLL_TAN_X, CALC_ROLL_TAN_Z)) { + else if (ELEM(type, CALC_ROLL_TAN_POS_X, CALC_ROLL_TAN_POS_Z)) { for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (ebone->parent) { bool is_edit = (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)); @@ -323,7 +353,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op) sub_v3_v3v3(dir_b, ebone_other->head, ebone_other->tail); normalize_v3(dir_b); - if (type == CALC_ROLL_TAN_Z) { + if (type == CALC_ROLL_TAN_POS_Z) { cross_v3_v3v3(vec, dir_a, dir_b); } else { @@ -374,7 +404,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op) copy_v3_v3(vec, mat[2]); } else { /* Axis */ - assert(type >= 0 && type <= 5); + assert(type <= 5); if (type < 3) vec[type] = 1.0f; else vec[type - 2] = -1.0f; mul_m3_v3(imat, vec); @@ -423,7 +453,7 @@ void ARMATURE_OT_calculate_roll(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, CALC_ROLL_TAN_X, "Type", ""); + ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, CALC_ROLL_TAN_POS_X, "Type", ""); RNA_def_boolean(ot->srna, "axis_flip", 0, "Flip Axis", "Negate the alignment axis"); RNA_def_boolean(ot->srna, "axis_only", 0, "Shortest Rotation", "Ignore the axis direction, use the shortest rotation to align"); } diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 9afc45955bd..a8b5f888597 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -141,7 +141,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n char oldname[MAXBONENAME]; /* names better differ! */ - if (strncmp(oldnamep, newnamep, MAXBONENAME)) { + if (!STREQLEN(oldnamep, newnamep, MAXBONENAME)) { /* we alter newname string... so make copy */ BLI_strncpy(newname, newnamep, MAXBONENAME); @@ -219,7 +219,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n if (ob->parent && (ob->parent->data == arm)) { if (ob->partype == PARBONE) { /* bone name in object */ - if (!strcmp(ob->parsubstr, oldname)) + if (STREQ(ob->parsubstr, oldname)) BLI_strncpy(ob->parsubstr, newname, MAXBONENAME); } } @@ -267,6 +267,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n /* Fix all animdata that may refer to this bone - we can't just do the ones attached to objects, since * other ID-blocks may have drivers referring to this bone [#29822] */ + // XXX: the ID here is for armatures, but most bone drivers are actually on the object instead... { BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname); @@ -284,7 +285,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n if (sl->spacetype == SPACE_VIEW3D) { View3D *v3d = (View3D *)sl; if (v3d->ob_centre && v3d->ob_centre->data == arm) { - if (!strcmp(v3d->ob_centre_bone, oldname)) { + if (STREQ(v3d->ob_centre_bone, oldname)) { BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME); } } diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 3e226c39c8c..53989dd783c 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -29,20 +29,26 @@ * \ingroup edarmature */ +#include "MEM_guardedalloc.h" + +#include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" #include "BLI_math.h" #include "BLF_translation.h" #include "BKE_action.h" +#include "BKE_animsys.h" #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_depsgraph.h" +#include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_report.h" @@ -98,33 +104,122 @@ static void joined_armature_fix_links_constraints( /* action constraint? (pose constraints only) */ if (con->type == CONSTRAINT_TYPE_ACTION) { - bActionConstraint *data = con->data; // XXX old animation system - bAction *act; - bActionChannel *achan; + bActionConstraint *data = con->data; if (data->act) { - act = data->act; + BKE_action_fix_paths_rename(&tarArm->id, data->act, "pose.bones[", + pchan->name, curbone->name, 0, 0, false); + } + } + + } +} + +/* userdata for joined_armature_fix_animdata_cb() */ +typedef struct tJoinArmature_AdtFixData { + Object *srcArm; + Object *tarArm; + + GHash *names_map; +} tJoinArmature_AdtFixData; - for (achan = act->chanbase.first; achan; achan = achan->next) { - if (STREQ(achan->name, pchan->name)) { - BLI_strncpy(achan->name, curbone->name, sizeof(achan->name)); +/* Callback to pass to void BKE_animdata_main_cb() for fixing driver ID's to point to the new ID */ +/* FIXME: For now, we only care about drivers here. When editing rigs, it's very rare to have animation + * on the rigs being edited already, so it should be safe to skip these. + */ +static void joined_armature_fix_animdata_cb(ID *id, AnimData *adt, void *user_data) +{ + tJoinArmature_AdtFixData *afd = (tJoinArmature_AdtFixData *)user_data; + ID *src_id = &afd->srcArm->id; + ID *dst_id = &afd->tarArm->id; + + GHashIterator gh_iter; + FCurve *fcu; + + /* Fix paths - If this is the target object, it will have some "dirty" paths */ + if (id == src_id) { + /* Fix drivers */ + for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + /* skip driver if it doesn't affect the bones */ + if (strstr(fcu->rna_path, "pose.bones[") == NULL) { + continue; + } + + // FIXME: this is too crude... it just does everything! + GHASH_ITER(gh_iter, afd->names_map) { + const char *old_name = BLI_ghashIterator_getKey(&gh_iter); + const char *new_name = BLI_ghashIterator_getValue(&gh_iter); + + /* only remap if changed; this still means there will be some waste if there aren't many drivers/keys */ + if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) { + fcu->rna_path = BKE_animsys_fix_rna_path_rename(id, fcu->rna_path, "pose.bones", + old_name, new_name, 0, 0, false); + + /* we don't want to apply a second remapping on this driver now, + * so stop trying names, but keep fixing drivers + */ + break; + } + } + } + } + + + /* Driver targets */ + for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + ChannelDriver *driver = fcu->driver; + DriverVar *dvar; + + /* Fix driver references to invalid ID's */ + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + /* only change the used targets, since the others will need fixing manually anyway */ + DRIVER_TARGETS_USED_LOOPER(dvar) + { + /* change the ID's used... */ + if (dtar->id == src_id) { + dtar->id = dst_id; + + /* also check on the subtarget... + * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own + * little twists so that we know that it isn't going to clobber the wrong data + */ + if ((dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) || (dtar->pchan_name[0])) { + GHASH_ITER(gh_iter, afd->names_map) { + const char *old_name = BLI_ghashIterator_getKey(&gh_iter); + const char *new_name = BLI_ghashIterator_getValue(&gh_iter); + + /* only remap if changed */ + if (!STREQ(old_name, new_name)) { + if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) { + /* Fix up path */ + dtar->rna_path = BKE_animsys_fix_rna_path_rename(id, dtar->rna_path, "pose.bones", + old_name, new_name, 0, 0, false); + break; /* no need to try any more names for bone path */ + } + else if (STREQ(dtar->pchan_name, old_name)) { + /* Change target bone name */ + BLI_strncpy(dtar->pchan_name, new_name, sizeof(dtar->pchan_name)); + break; /* no need to try any more names for bone subtarget */ + } + } + } } } } + DRIVER_TARGETS_LOOPER_END } - } } /* Helper function for armature joining - link fixing */ -static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone) +static void joined_armature_fix_links(Main *bmain, Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone) { Object *ob; bPose *pose; bPoseChannel *pchant; /* let's go through all objects in database */ - for (ob = G.main->object.first; ob; ob = ob->id.next) { + for (ob = bmain->object.first; ob; ob = ob->id.next) { /* do some object-type specific things */ if (ob->type == OB_ARMATURE) { pose = ob->pose; @@ -198,8 +293,17 @@ int join_armature_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases) { if ((base->object->type == OB_ARMATURE) && (base->object != ob)) { + tJoinArmature_AdtFixData afd = {NULL}; bArmature *curarm = base->object->data; + /* we assume that each armature datablock is only used in a single place */ + BLI_assert(ob->data != base->object->data); + + /* init callback data for fixing up AnimData links later */ + afd.srcArm = base->object; + afd.tarArm = ob; + afd.names_map = BLI_ghash_str_new("join_armature_adt_fix"); + /* Make a list of editbones in current armature */ ED_armature_to_edit(base->object->data); @@ -219,6 +323,7 @@ int join_armature_exec(bContext *C, wmOperator *op) /* Get new name */ unique_editbone_name(arm->edbo, curbone->name, NULL); + BLI_ghash_insert(afd.names_map, BLI_strdup(pchan->name), curbone->name); /* Transform the bone */ { @@ -249,7 +354,7 @@ int join_armature_exec(bContext *C, wmOperator *op) } /* Fix Constraints and Other Links to this Bone and Armature */ - joined_armature_fix_links(ob, base->object, pchan, curbone); + joined_armature_fix_links(bmain, ob, base->object, pchan, curbone); /* Rename pchan */ BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name)); @@ -264,6 +369,37 @@ int join_armature_exec(bContext *C, wmOperator *op) BKE_pose_channels_hash_free(pose); } + /* Fix all the drivers (and animation data) */ + BKE_animdata_main_cb(bmain, joined_armature_fix_animdata_cb, &afd); + BLI_ghash_free(afd.names_map, MEM_freeN, NULL); + + /* Only copy over animdata now, after all the remapping has been done, + * so that we don't have to worry about ambiguities re which armature + * a bone came from! + */ + if (base->object->adt) { + if (ob->adt == NULL) { + /* no animdata, so just use a copy of the whole thing */ + ob->adt = BKE_copy_animdata(base->object->adt, false); + } + else { + /* merge in data - we'll fix the drivers manually */ + BKE_animdata_merge_copy(&ob->id, &base->object->id, ADT_MERGECOPY_KEEP_DST, false); + } + } + + if (curarm->adt) { + if (arm->adt == NULL) { + /* no animdata, so just use a copy of the whole thing */ + arm->adt = BKE_copy_animdata(curarm->adt, false); + } + else { + /* merge in data - we'll fix the drivers manually */ + BKE_animdata_merge_copy(&arm->id, &curarm->id, ADT_MERGECOPY_KEEP_DST, false); + } + } + + /* Free the old object data */ ED_base_object_free_and_unlink(bmain, scene, base); } } diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index c6ef76c570c..307e6c076f2 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -254,7 +254,7 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv static int armature_select_linked_poll(bContext *C) { - return (ED_operator_view3d_active(C) && ED_operator_editarmature(C) ); + return (ED_operator_view3d_active(C) && ED_operator_editarmature(C)); } void ARMATURE_OT_select_linked(wmOperatorType *ot) diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c index aace8c5434c..5376fc8c79b 100644 --- a/source/blender/editors/armature/editarmature_retarget.c +++ b/source/blender/editors/armature/editarmature_retarget.c @@ -718,7 +718,7 @@ static void RIG_reconnectControlBones(RigGraph *rg) cti->get_constraint_targets(con, &targets); for (target_index = 0, ct = targets.first; ct; target_index++, ct = ct->next) { - if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) { + if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) { /* SET bone link to bone corresponding to pchan */ EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name); @@ -841,7 +841,7 @@ static void RIG_reconnectControlBones(RigGraph *rg) cti->get_constraint_targets(con, &targets); for (ct = targets.first; ct; ct = ct->next) { - if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) { + if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) { /* SET bone link to ctrl corresponding to pchan */ RigControl *link = BLI_ghash_lookup(rg->controls_map, pchan->name); @@ -1160,7 +1160,7 @@ static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bo last_bone = bone; - if (strcmp(bone->name, "head") == 0) { + if (STREQ(bone->name, "head")) { contain_head = 1; } } diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index 3dbf7b4b65a..6c2d4256a0f 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -333,11 +333,11 @@ static void sk_autoname(bContext *C, ReebArc *arc) if (side[0] == '\0') { valid = 1; } - else if (strcmp(side, "R") == 0 || strcmp(side, "L") == 0) { + else if (STREQ(side, "R") || STREQ(side, "L")) { valid = 1; caps = 1; } - else if (strcmp(side, "r") == 0 || strcmp(side, "l") == 0) { + else if (STREQ(side, "r") || STREQ(side, "l")) { valid = 1; caps = 0; } diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 2e6eace88aa..d571fb374d9 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -1050,7 +1050,7 @@ static void poselib_preview_get_next(tPoseLib_PreviewData *pld, int step) LinkData *ld, *ldn, *ldc; /* free and rebuild if needed (i.e. if search-str changed) */ - if (strcmp(pld->searchstr, pld->searchold)) { + if (!STREQ(pld->searchstr, pld->searchold)) { /* free list of temporary search matches */ BLI_freelistN(&pld->searchp); diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c index 1297755b7d0..2ba1eedd33b 100644 --- a/source/blender/editors/armature/pose_utils.c +++ b/source/blender/editors/armature/pose_utils.c @@ -259,7 +259,7 @@ LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, con FCurve *fcu = (FCurve *)ld->data; /* check if paths match */ - if (strcmp(path, fcu->rna_path) == 0) + if (STREQ(path, fcu->rna_path)) return ld; } diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 99c64be5797..4aeeaa87269 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -643,25 +643,20 @@ static void keyData_switchDirectionNurb(Curve *cu, Nurb *nu) static GHash *dupli_keyIndexHash(GHash *keyindex) { GHash *gh; - GHashIterator *hashIter; + GHashIterator gh_iter; gh = BLI_ghash_ptr_new_ex("dupli_keyIndex gh", BLI_ghash_size(keyindex)); - for (hashIter = BLI_ghashIterator_new(keyindex); - BLI_ghashIterator_done(hashIter) == false; - BLI_ghashIterator_step(hashIter)) - { - void *cv = BLI_ghashIterator_getKey(hashIter); - CVKeyIndex *index = BLI_ghashIterator_getValue(hashIter); - CVKeyIndex *newIndex = MEM_callocN(sizeof(CVKeyIndex), "dupli_keyIndexHash index"); + GHASH_ITER (gh_iter, keyindex) { + void *cv = BLI_ghashIterator_getKey(&gh_iter); + CVKeyIndex *index = BLI_ghashIterator_getValue(&gh_iter); + CVKeyIndex *newIndex = MEM_mallocN(sizeof(CVKeyIndex), "dupli_keyIndexHash index"); memcpy(newIndex, index, sizeof(CVKeyIndex)); BLI_ghash_insert(gh, cv, newIndex); } - BLI_ghashIterator_free(hashIter); - return gh; } @@ -999,7 +994,7 @@ static void fcurve_path_rename(AnimData *adt, const char *orig_rna_path, char *r for (fcu = orig_curves->first; fcu; fcu = nextfcu) { nextfcu = fcu->next; - if (!strncmp(fcu->rna_path, orig_rna_path, len)) { + if (STREQLEN(fcu->rna_path, orig_rna_path, len)) { char *spath, *suffix = fcu->rna_path + len; nfcu = copy_fcurve(fcu); spath = nfcu->rna_path; @@ -1102,10 +1097,10 @@ static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves) for (fcu = orig_curves->first; fcu; fcu = next) { next = fcu->next; - if (!strncmp(fcu->rna_path, "splines", 7)) { + if (STREQLEN(fcu->rna_path, "splines", 7)) { const char *ch = strchr(fcu->rna_path, '.'); - if (ch && (!strncmp(ch, ".bezier_points", 14) || !strncmp(ch, ".points", 7))) + if (ch && (STREQLEN(ch, ".bezier_points", 14) || STREQLEN(ch, ".points", 7))) fcurve_remove(adt, orig_curves, fcu); } } @@ -1129,7 +1124,7 @@ static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves) for (fcu = orig_curves->first; fcu; fcu = next) { next = fcu->next; - if (!strncmp(fcu->rna_path, "splines", 7)) fcurve_remove(adt, orig_curves, fcu); + if (STREQLEN(fcu->rna_path, "splines", 7)) fcurve_remove(adt, orig_curves, fcu); else BLI_addtail(&curves, fcu); } @@ -2007,7 +2002,7 @@ static void ed_curve_delete_selected(Object *obedit) } /* only for OB_SURF */ -bool ed_editnurb_extrude_flag(EditNurb *editnurb, short flag) +bool ed_editnurb_extrude_flag(EditNurb *editnurb, const short flag) { Nurb *nu; BPoint *bp, *bpn, *newbp; @@ -2368,7 +2363,6 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, } else { /* knots done after duplicate as pntsu may change */ - nu->knotsu = nu->knotsv = NULL; BKE_nurb_order_clamp_u(nu); BKE_nurb_knot_calc_u(nu); @@ -4889,285 +4883,405 @@ void CURVE_OT_spin(wmOperatorType *ot) RNA_def_float_vector(ot->srna, "axis", 3, NULL, -FLT_MAX, FLT_MAX, "Axis", "Axis in global view space", -1.0f, 1.0f); } -/***************** add vertex operator **********************/ +/***************** extrude vertex operator **********************/ -static int addvert_Nurb(bContext *C, short mode, float location[3]) +static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb) { - Object *obedit = CTX_data_edit_object(C); - Curve *cu = (Curve *)obedit->data; - EditNurb *editnurb = cu->editnurb; - Nurb *nu, *newnu = NULL; - BezTriple *bezt, *newbezt = NULL; - BPoint *bp, *newbp = NULL; - float imat[4][4], temp[3]; - bool ok = false; - BezTriple *bezt_recalc[3] = {NULL}; + Nurb *nu = NULL; + Nurb *nu_last = NULL; - invert_m4_m4(imat, obedit->obmat); + bool changed = false; - findselectedNurbvert(&editnurb->nurbs, &nu, &bezt, &bp); - - if ((nu == NULL) || (nu->type == CU_BEZIER && bezt == NULL) || (nu->type != CU_BEZIER && bp == NULL)) { - if (mode != 'e') { - if (cu->actnu != CU_ACT_NONE) - nu = BLI_findlink(&editnurb->nurbs, cu->actnu); - - if (!nu || nu->type == CU_BEZIER) { - newbezt = (BezTriple *)MEM_callocN(sizeof(BezTriple), "addvert_Nurb"); - newbezt->radius = 1; - newbezt->alfa = 0; - BEZ_SEL(newbezt); - newbezt->h2 = newbezt->h1 = HD_AUTO; - - newnu = (Nurb *)MEM_callocN(sizeof(Nurb), "addvert_Nurb newnu"); - if (!nu) { - /* no selected segment -- create new one which is BEZIER type - * type couldn't be determined from Curve bt could be changed - * in the future, so shouldn't make much headache */ - newnu->type = CU_BEZIER; - newnu->resolu = cu->resolu; - newnu->flag |= CU_SMOOTH; - } - else { - memcpy(newnu, nu, sizeof(Nurb)); - } + Nurb *cu_actnu; + union { + BezTriple *bezt; + BPoint *bp; + void *p; + } cu_actvert; - BLI_addtail(&editnurb->nurbs, newnu); - newnu->bezt = newbezt; - newnu->pntsu = 1; + BKE_curve_nurb_vert_active_get(cu, &cu_actnu, &cu_actvert.p); + BKE_curve_nurb_vert_active_set(cu, NULL, NULL); - temp[0] = 1; - temp[1] = 0; - temp[2] = 0; + /* first pass (endpoints) */ + for (nu = editnurb->nurbs.first; nu; nu = nu->next) { - copy_v3_v3(newbezt->vec[1], location); - sub_v3_v3v3(newbezt->vec[0], newbezt->vec[1], temp); - add_v3_v3v3(newbezt->vec[2], newbezt->vec[1], temp); + if ((nu->flagu & CU_NURB_CYCLIC) && (nu->pntsu > 1)) { + continue; + } - mul_m4_v3(imat, newbezt->vec[0]); - mul_m4_v3(imat, newbezt->vec[1]); - mul_m4_v3(imat, newbezt->vec[2]); + if (nu->type == CU_BEZIER) { - ok = 1; - nu = newnu; - } - else if (nu->pntsv == 1) { - newbp = (BPoint *)MEM_callocN(sizeof(BPoint), "addvert_Nurb5"); - newbp->radius = 1; - newbp->alfa = 0; - newbp->f1 |= SELECT; + /* Check to see if the first bezier point is selected */ + if (nu->pntsu > 0 && nu->bezt != NULL) { + BezTriple *nu_bezt_old = nu->bezt; + BezTriple *bezt = nu->bezt; + + if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) { + BezTriple *bezt_new; + BEZ_DESEL(bezt); - newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "addvert_Nurb newnu"); - memcpy(newnu, nu, sizeof(Nurb)); - BLI_addtail(&editnurb->nurbs, newnu); - newnu->bp = newbp; - newnu->orderu = 2; - newnu->pntsu = 1; + bezt_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BezTriple), __func__); + ED_curve_beztcpy(editnurb, bezt_new + 1, bezt, nu->pntsu); + *bezt_new = *bezt; - mul_v3_m4v3(newbp->vec, imat, location); - newbp->vec[3] = 1.0; - newnu->knotsu = newnu->knotsv = NULL; - BKE_nurb_knot_calc_u(newnu); + MEM_freeN(nu->bezt); + nu->bezt = bezt_new; - ok = 1; - nu = newnu; + nu->pntsu += 1; + + if (ARRAY_HAS_ITEM(cu_actvert.bezt, nu_bezt_old, nu->pntsu - 1)) { + cu_actvert.bezt = (cu_actvert.bezt == bezt) ? + bezt_new : &nu->bezt[(cu_actvert.bezt - nu_bezt_old) + 1]; + BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bezt); + } + + BEZ_SEL(bezt_new); + changed = true; + } } + /* Check to see if the last bezier point is selected */ + if (nu->pntsu > 1) { + BezTriple *nu_bezt_old = nu->bezt; + BezTriple *bezt = &nu->bezt[nu->pntsu - 1]; + + if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) { + BezTriple *bezt_new; + BEZ_DESEL(bezt); + + bezt_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BezTriple), __func__); + ED_curve_beztcpy(editnurb, bezt_new, nu->bezt, nu->pntsu); + bezt_new[nu->pntsu] = *bezt; + + MEM_freeN(nu->bezt); + nu->bezt = bezt_new; + + bezt_new += nu->pntsu; + nu->pntsu += 1; + + if (ARRAY_HAS_ITEM(cu_actvert.bezt, nu_bezt_old, nu->pntsu - 1)) { + cu_actvert.bezt = (cu_actvert.bezt == bezt) ? + bezt_new : &nu->bezt[cu_actvert.bezt - nu_bezt_old]; + BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bezt); + } + + BEZ_SEL(bezt_new); + changed = true; + } + } } + else { - if (!ok) - return OPERATOR_CANCELLED; - } + /* Check to see if the first bpoint is selected */ + if (nu->pntsu > 0 && nu->bp != NULL) { + BPoint *nu_bp_old = nu->bp; + BPoint *bp = nu->bp; - if (!ok && nu->type == CU_BEZIER) { - /* which bezpoint? */ - if (bezt == &nu->bezt[nu->pntsu - 1]) { /* last */ - BEZ_DESEL(bezt); - newbezt = (BezTriple *)MEM_callocN((nu->pntsu + 1) * sizeof(BezTriple), "addvert_Nurb"); - ED_curve_beztcpy(editnurb, newbezt, nu->bezt, nu->pntsu); - newbezt[nu->pntsu] = *bezt; - copy_v3_v3(temp, bezt->vec[1]); - MEM_freeN(nu->bezt); - nu->bezt = newbezt; - newbezt += nu->pntsu; - BEZ_SEL(newbezt); - newbezt->h1 = newbezt->h2; - bezt = &nu->bezt[nu->pntsu - 1]; - ok = 1; + if (bp->f1 & SELECT) { + BPoint *bp_new; + bp->f1 &= ~SELECT; - if (nu->pntsu > 1) { - bezt_recalc[1] = newbezt; - bezt_recalc[0] = newbezt - 1; - } - } - else if (bezt == nu->bezt) { /* first */ - BEZ_DESEL(bezt); - newbezt = (BezTriple *)MEM_callocN((nu->pntsu + 1) * sizeof(BezTriple), "addvert_Nurb"); - ED_curve_beztcpy(editnurb, newbezt + 1, bezt, nu->pntsu); - *newbezt = *bezt; - BEZ_SEL(newbezt); - newbezt->h2 = newbezt->h1; - copy_v3_v3(temp, bezt->vec[1]); - MEM_freeN(nu->bezt); - nu->bezt = newbezt; - bezt = newbezt + 1; - ok = 1; + bp_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BPoint), __func__); + ED_curve_bpcpy(editnurb, bp_new + 1, bp, nu->pntsu); + *bp_new = *bp; + + MEM_freeN(nu->bp); + nu->bp = bp_new; + nu->pntsu += 1; + BKE_nurb_knot_calc_u(nu); + + if (ARRAY_HAS_ITEM(cu_actvert.bp, nu_bp_old, nu->pntsu - 1)) { + cu_actvert.bp = (cu_actvert.bp == bp) ? + bp_new : &nu->bp[(cu_actvert.bp - nu_bp_old) + 1]; + BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bp); + } + + bp_new->f1 |= SELECT; + changed = true; + } + } + + /* Check to see if the last bpoint is selected */ if (nu->pntsu > 1) { - bezt_recalc[1] = newbezt; - bezt_recalc[2] = newbezt + 1; + BPoint *nu_bp_old = nu->bp; + BPoint *bp = &nu->bp[nu->pntsu - 1]; + + if (bp->f1 & SELECT) { + BPoint *bp_new; + bp->f1 &= ~SELECT; + + bp_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BPoint), __func__); + ED_curve_bpcpy(editnurb, bp_new, nu->bp, nu->pntsu); + bp_new[nu->pntsu] = *bp; + + MEM_freeN(nu->bp); + nu->bp = bp_new; + + bp_new += nu->pntsu; + nu->pntsu += 1; + + if (ARRAY_HAS_ITEM(cu_actvert.bp, nu_bp_old, nu->pntsu - 1)) { + cu_actvert.bp = (cu_actvert.bp == bp) ? + bp_new : &nu->bp[cu_actvert.bp - nu_bp_old]; + BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bp); + } + + BKE_nurb_knot_calc_u(nu); + + bp_new->f1 |= SELECT; + changed = true; + } } } - else if (mode != 'e') { - BEZ_DESEL(bezt); - newbezt = (BezTriple *)MEM_callocN(sizeof(BezTriple), "addvert_Nurb"); - *newbezt = *bezt; - BEZ_SEL(newbezt); - newbezt->h2 = newbezt->h1; - copy_v3_v3(temp, bezt->vec[1]); + } - newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "addvert_Nurb newnu"); - memcpy(newnu, nu, sizeof(Nurb)); - BLI_addtail(&editnurb->nurbs, newnu); - newnu->bezt = newbezt; - newnu->pntsu = 1; + /* second pass (interior points) */ + nu_last = editnurb->nurbs.last; + for (nu = editnurb->nurbs.first; (nu != nu_last->next); nu = nu->next) { + int i, i_end; - nu = newnu; - bezt = newbezt; - ok = 1; + if ((nu->flagu & CU_NURB_CYCLIC) && (nu->pntsu > 1)) { + /* all points are interior */ + i = 0; + i_end = nu->pntsu; } else { - bezt = NULL; + /* skip endpoints */ + i = 1; + i_end = nu->pntsu - 1; } - if (bezt) { - if (!newnu) nu->pntsu++; + if (nu->type == CU_BEZIER) { + BezTriple *bezt; - if (mode == 'e') { - copy_v3_v3(newbezt->vec[0], bezt->vec[0]); - copy_v3_v3(newbezt->vec[1], bezt->vec[1]); - copy_v3_v3(newbezt->vec[2], bezt->vec[2]); - } - else { - mul_v3_m4v3(newbezt->vec[1], imat, location); - sub_v3_v3v3(temp, newbezt->vec[1], temp); + for (bezt = &nu->bezt[i]; i < i_end; i++, bezt++) { + if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) { + Nurb *nurb_new; + BezTriple *bezt_new; + + BEZ_DESEL(bezt); + nurb_new = BKE_nurb_copy(nu, 1, 1); + nurb_new->flagu &= ~CU_NURB_CYCLIC; + BLI_addtail(&editnurb->nurbs, nurb_new); + bezt_new = nurb_new->bezt; + ED_curve_beztcpy(editnurb, bezt_new, bezt, 1); + BEZ_SEL(bezt_new); + + if (cu_actvert.bezt == bezt || cu_actnu == NULL) { + BKE_curve_nurb_vert_active_set(cu, nurb_new, bezt_new); + } - if (bezt_recalc[1]) { - const char h1 = bezt_recalc[1]->h1, h2 = bezt_recalc[1]->h2; - bezt_recalc[1]->h1 = bezt_recalc[1]->h2 = HD_AUTO; - BKE_nurb_handle_calc(bezt_recalc[1], bezt_recalc[0], bezt_recalc[2], 0); - bezt_recalc[1]->h1 = h1; - bezt_recalc[1]->h2 = h2; - } - else { - add_v3_v3v3(newbezt->vec[0], bezt->vec[0], temp); - add_v3_v3v3(newbezt->vec[2], bezt->vec[2], temp); + changed = true; } - + } + } + else { + BPoint *bp; + + for (bp = &nu->bp[i]; i < i_end; i++, bp++) { + if (bp->f1 & SELECT) { + Nurb *nurb_new; + BPoint *bp_new; + + bp->f1 &= ~SELECT; + nurb_new = BKE_nurb_copy(nu, 1, 1); + nurb_new->flagu &= ~CU_NURB_CYCLIC; + BLI_addtail(&editnurb->nurbs, nurb_new); + bp_new = nurb_new->bp; + ED_curve_bpcpy(editnurb, bp_new, bp, 1); + bp_new->f1 |= SELECT; + + if (cu_actvert.bp == bp || cu_actnu == NULL) { + BKE_curve_nurb_vert_active_set(cu, nurb_new, bp_new); + } - if (newnu) BKE_nurb_handles_calc(newnu); - else BKE_nurb_handles_calc(nu); + changed = true; + } } } } - else if (!ok && nu->pntsv == 1) { - /* which b-point? */ - if (bp == &nu->bp[nu->pntsu - 1]) { /* last */ - bp->f1 = 0; - newbp = (BPoint *)MEM_callocN((nu->pntsu + 1) * sizeof(BPoint), "addvert_Nurb4"); - ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu); - newbp[nu->pntsu] = *bp; - MEM_freeN(nu->bp); - nu->bp = newbp; - newbp += nu->pntsu; - newbp->f1 |= SELECT; - bp = newbp - 1; - ok = 1; - } - else if (bp == nu->bp) { /* first */ - bp->f1 = 0; - newbp = (BPoint *)MEM_callocN((nu->pntsu + 1) * sizeof(BPoint), "addvert_Nurb3"); - ED_curve_bpcpy(editnurb, newbp + 1, bp, nu->pntsu); - *newbp = *bp; - newbp->f1 |= SELECT; - MEM_freeN(nu->bp); - nu->bp = newbp; - bp = newbp + 1; - ok = 1; - } - else if (mode != 'e') { - bp->f1 = 0; - newbp = (BPoint *)MEM_callocN(sizeof(BPoint), "addvert_Nurb5"); - *newbp = *bp; - newbp->f1 |= SELECT; - newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "addvert_Nurb newnu"); - memcpy(newnu, nu, sizeof(Nurb)); - BLI_addtail(&editnurb->nurbs, newnu); - newnu->bp = newbp; - newnu->orderu = 2; - newnu->pntsu = 1; - newnu->knotsu = newnu->knotsv = NULL; + if (changed == false) { + BKE_curve_nurb_vert_active_set(cu, cu_actnu, cu_actvert.p); + } - nu = newnu; - bp = newbp; - ok = 1; + return changed; +} + +/***************** add vertex operator **********************/ + +static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float location[3]) +{ + Nurb *nu; + + float minmax[2][3]; + float temp[3]; + bool nu_has_select = false; + + bool changed = false; + + INIT_MINMAX(minmax[0], minmax[1]); + + for (nu = editnurb->nurbs.first; nu; nu = nu->next) { + int i; + if (nu->type == CU_BEZIER) { + BezTriple *bezt; + + for (i = 0, bezt = nu->bezt; i < nu->pntsu; i++, bezt++) { + if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) { + minmax_v3v3_v3(UNPACK2(minmax), bezt->vec[1]); + nu_has_select = true; + } + } } else { - bp = NULL; + BPoint *bp; + + for (i = 0, bp = nu->bp; i < nu->pntsu; i++, bp++) { + if (bp->f1 & SELECT) { + minmax_v3v3_v3(UNPACK2(minmax), bp->vec); + nu_has_select = true; + } + } } + } + + if (nu_has_select && ed_editcurve_extrude(cu, editnurb)) { + float ofs[3], center[3]; + int i; + + mid_v3_v3v3(center, minmax[0], minmax[1]); + sub_v3_v3v3(ofs, location, center); - if (bp) { - if (mode == 'e') { - copy_v3_v3(newbp->vec, bp->vec); + if ((cu->flag & CU_3D) == 0) { + ofs[2] = 0.0f; + } + + for (nu = editnurb->nurbs.first; nu; nu = nu->next) { + if (nu->type == CU_BEZIER) { + BezTriple *bezt; + for (i = 0, bezt = nu->bezt; i < nu->pntsu; i++, bezt++) { + if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) { + add_v3_v3(bezt->vec[0], ofs); + add_v3_v3(bezt->vec[1], ofs); + add_v3_v3(bezt->vec[2], ofs); + + if (((nu->flagu & CU_NURB_CYCLIC) == 0) && + (i == 0 || i == nu->pntsu - 1)) + { + BKE_nurb_handle_calc_simple_auto(nu, bezt); + } + } + } } else { - mul_v3_m4v3(newbp->vec, imat, location); - newbp->vec[3] = 1.0; + BPoint *bp; - if (!newnu && nu->orderu < 4 && nu->orderu <= nu->pntsu) - nu->orderu++; + for (i = 0, bp = nu->bp; i < nu->pntsu; i++, bp++) { + if (bp->f1 & SELECT) { + add_v3_v3(bp->vec, ofs); + } + } } + } + changed = true; + } + else { + /* nothing selected: create a new curve */ + nu = BKE_curve_nurb_active_get(cu); - if (!newnu) { - nu->pntsu++; - BKE_nurb_knot_calc_u(nu); + if (!nu || nu->type == CU_BEZIER) { + Nurb *nurb_new; + BezTriple *bezt_new; + + if (nu) { + nurb_new = BKE_nurb_copy(nu, 1, 1); } else { - BKE_nurb_knot_calc_u(newnu); + nurb_new = MEM_callocN(sizeof(Nurb), "BLI_editcurve_addvert new_bezt_nurb 2"); + nurb_new->type = CU_BEZIER; + nurb_new->resolu = cu->resolu; + nurb_new->orderu = 4; + nurb_new->flag |= CU_SMOOTH; + BKE_nurb_bezierPoints_add(nurb_new, 1); } - } - } + BLI_addtail(&editnurb->nurbs, nurb_new); - if (ok) { - if (nu->bezt) { - BKE_curve_nurb_vert_active_set(cu, nu, newbezt); + bezt_new = nurb_new->bezt; + + BEZ_SEL(bezt_new); + + bezt_new->h1 = HD_AUTO; + bezt_new->h2 = HD_AUTO; + + temp[0] = 1.0f; + temp[1] = 0.0f; + temp[2] = 0.0f; + + copy_v3_v3(bezt_new->vec[1], location); + sub_v3_v3v3(bezt_new->vec[0], bezt_new->vec[1], temp); + add_v3_v3v3(bezt_new->vec[2], bezt_new->vec[1], temp); + + changed = true; } else { - BKE_curve_nurb_vert_active_set(cu, nu, newbp); - } + Nurb *nurb_new; + BPoint *bp_new; - BKE_nurb_test2D(nu); + { + nurb_new = MEM_callocN(sizeof(Nurb), __func__); + nurb_new->type = CU_POLY; + nurb_new->resolu = cu->resolu; + nurb_new->flag |= CU_SMOOTH; + nurb_new->orderu = 4; + BKE_nurb_points_add(nurb_new, 1); + } + BLI_addtail(&editnurb->nurbs, nurb_new); - if (ED_curve_updateAnimPaths(obedit->data)) - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + bp_new = nurb_new->bp; - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); + bp_new->f1 |= SELECT; - return OPERATOR_FINISHED; + copy_v3_v3(bp_new->vec, location); + bp_new->vec[3] = 1.0f; + + BKE_nurb_knot_calc_u(nurb_new); + + changed = true; + } } - return OPERATOR_CANCELLED; + return changed; } static int add_vertex_exec(bContext *C, wmOperator *op) { + Object *obedit = CTX_data_edit_object(C); + Curve *cu = obedit->data; + EditNurb *editnurb = cu->editnurb; float location[3]; + float imat[4][4]; RNA_float_get_array(op->ptr, "location", location); - return addvert_Nurb(C, 0, location); + + invert_m4_m4(imat, obedit->obmat); + mul_m4_v3(imat, location); + + if (ed_editcurve_addvert(cu, editnurb, location)) { + if (ED_curve_updateAnimPaths(obedit->data)) { + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + } + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DAG_id_tag_update(obedit->data, 0); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -5236,29 +5350,39 @@ void CURVE_OT_vertex_add(wmOperatorType *ot) /***************** extrude operator **********************/ -static int extrude_exec(bContext *C, wmOperator *UNUSED(op)) +static int curve_extrude_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); Curve *cu = obedit->data; EditNurb *editnurb = cu->editnurb; - Nurb *nu; + bool changed = false; + bool as_curve = false; /* first test: curve? */ - for (nu = editnurb->nurbs.first; nu; nu = nu->next) - if (nu->pntsv == 1 && isNurbsel_count(cu, nu) == 1) - break; + if (obedit->type != OB_CURVE) { + Nurb *nu; + for (nu = editnurb->nurbs.first; nu; nu = nu->next) { + if (nu->pntsv == 1 && isNurbsel_count(cu, nu) == 1) { + as_curve = true; + break; + } + } + } - if (obedit->type == OB_CURVE || nu) { - addvert_Nurb(C, 'e', NULL); + if (obedit->type == OB_CURVE || as_curve) { + changed = ed_editcurve_extrude(cu, editnurb); } else { - if (ed_editnurb_extrude_flag(editnurb, SELECT)) { - if (ED_curve_updateAnimPaths(obedit->data)) - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); + changed = ed_editnurb_extrude_flag(editnurb, SELECT); + } - WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); - DAG_id_tag_update(obedit->data, 0); + if (changed) { + if (ED_curve_updateAnimPaths(obedit->data)) { + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit); } + + WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data); + DAG_id_tag_update(obedit->data, 0); } return OPERATOR_FINISHED; @@ -5272,7 +5396,7 @@ void CURVE_OT_extrude(wmOperatorType *ot) ot->idname = "CURVE_OT_extrude"; /* api callbacks */ - ot->exec = extrude_exec; + ot->exec = curve_extrude_exec; ot->poll = ED_operator_editsurfcurve; /* flags */ @@ -6543,7 +6667,6 @@ static int curve_delete_segments(Object *obedit, const bool split) } } - nu->knotsu = nu->knotsv = NULL; BKE_nurb_order_clamp_u(nu); BKE_nurb_knot_calc_u(nu); @@ -6640,7 +6763,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op) Object *obedit = CTX_data_edit_object(C); ListBase *editnurb = object_editcurve_get(obedit); Nurb *nu; - int clear = (strcmp(op->idname, "CURVE_OT_shade_flat") == 0); + int clear = (STREQ(op->idname, "CURVE_OT_shade_flat")); if (obedit->type != OB_CURVE) return OPERATOR_CANCELLED; diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c index c9a961d1a4d..7c53896b969 100644 --- a/source/blender/editors/curve/editcurve_add.c +++ b/source/blender/editors/curve/editcurve_add.c @@ -529,11 +529,9 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf) if (newob && enter_editmode) ED_undo_push(C, "Enter Editmode"); - ED_object_new_primitive_matrix(C, obedit, loc, rot, mat, false); + ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); dia = RNA_float_get(op->ptr, "radius"); - mat[0][0] *= dia; - mat[1][1] *= dia; - mat[2][2] *= dia; + mul_mat3_m4_fl(mat, dia); nu = add_nurbs_primitive(C, obedit, mat, type, newob); editnurb = object_editcurve_get(obedit); diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index 97adaea41a8..a2ba6216f9c 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -390,7 +390,7 @@ void paste_gpdata(Scene *scene) /* find suitable layer from buffer to use to paste from */ for (gpls = gpcopybuf.first; gpls; gpls = gpls->next) { /* check if layer name matches */ - if ((no_name) || (strcmp(gpls->info, gpld->info) == 0)) + if ((no_name) || STREQ(gpls->info, gpld->info)) break; } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 3dae25263e8..a830253f634 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -100,7 +100,8 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr switch (sa->spacetype) { case SPACE_VIEW3D: /* 3D-View */ - case SPACE_TIME: /* Timeline - XXX: this is a hack to get it to show GP keyframes for 3D view */ + case SPACE_TIME: /* Timeline - XXX: this is a hack to get it to show GP keyframes for 3D view */ + case SPACE_ACTION: /* DepeSheet - XXX: this is a hack to get the keyframe jump operator to take GP Keyframes into account */ { BLI_assert(scene && ELEM(scene->toolsettings->gpencil_src, GP_TOOL_SOURCE_SCENE, GP_TOOL_SOURCE_OBJECT)); @@ -620,6 +621,10 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op) /* make copies of selected strokes, and deselect these once we're done */ for (gps = gpf->strokes.first; gps; gps = gps->next) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + if (gps->flag & GP_STROKE_SELECT) { if (gps->totpoints == 1) { /* Special Case: If there's just a single point in this stroke... */ @@ -728,6 +733,10 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) /* make copies of selected strokes, and deselect these once we're done */ for (gps = gpf->strokes.first; gps; gps = gps->next) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + if (gps->flag & GP_STROKE_SELECT) { if (gps->totpoints == 1) { /* Special Case: If there's just a single point in this stroke... */ @@ -936,6 +945,11 @@ static int gp_delete_selected_strokes(bContext *C) for (gps = gpf->strokes.first; gps; gps = gpsn) { gpsn = gps->next; + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + + /* free stroke if selected */ if (gps->flag & GP_STROKE_SELECT) { /* free stroke memory arrays, then stroke itself */ if (gps->points) MEM_freeN(gps->points); @@ -975,6 +989,10 @@ static int gp_dissolve_selected_points(bContext *C) for (gps = gpf->strokes.first; gps; gps = gpsn) { gpsn = gps->next; + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + if (gps->flag & GP_STROKE_SELECT) { bGPDspoint *pt; int i; @@ -1050,6 +1068,11 @@ static int gp_delete_selected_points(bContext *C) for (gps = gpf->strokes.first; gps; gps = gpsn) { gpsn = gps->next; + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + + if (gps->flag & GP_STROKE_SELECT) { bGPDspoint *pt; int i; @@ -2480,50 +2503,50 @@ static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data"); /* Always show those props */ - if (strcmp(prop_id, "type") == 0 || - strcmp(prop_id, "use_normalize_weights") == 0 || - strcmp(prop_id, "radius_multiplier") == 0 || - strcmp(prop_id, "use_link_strokes") == 0) + if (STREQ(prop_id, "type") || + STREQ(prop_id, "use_normalize_weights") || + STREQ(prop_id, "radius_multiplier") || + STREQ(prop_id, "use_link_strokes")) { return true; } /* Never show this prop */ - if (strcmp(prop_id, "use_timing_data") == 0) + if (STREQ(prop_id, "use_timing_data")) return false; if (link_strokes) { /* Only show when link_stroke is true */ - if (strcmp(prop_id, "timing_mode") == 0) + if (STREQ(prop_id, "timing_mode")) return true; if (timing_mode != GP_STROKECONVERT_TIMING_NONE) { /* Only show when link_stroke is true and stroke timing is enabled */ - if (strcmp(prop_id, "frame_range") == 0 || - strcmp(prop_id, "start_frame") == 0) + if (STREQ(prop_id, "frame_range") || + STREQ(prop_id, "start_frame")) { return true; } /* Only show if we have valid timing data! */ - if (valid_timing && strcmp(prop_id, "use_realtime") == 0) + if (valid_timing && STREQ(prop_id, "use_realtime")) return true; /* Only show if realtime or valid_timing is false! */ - if ((!realtime || !valid_timing) && strcmp(prop_id, "end_frame") == 0) + if ((!realtime || !valid_timing) && STREQ(prop_id, "end_frame")) return true; if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) { /* Only show for custom gaps! */ - if (strcmp(prop_id, "gap_duration") == 0) + if (STREQ(prop_id, "gap_duration")) return true; /* Only show randomness for non-null custom gaps! */ - if (strcmp(prop_id, "gap_randomness") == 0 && (gap_duration > 0.0f)) + if (STREQ(prop_id, "gap_randomness") && (gap_duration > 0.0f)) return true; /* Only show seed for randomize action! */ - if (strcmp(prop_id, "seed") == 0 && (gap_duration > 0.0f) && (gap_randomness > 0.0f)) + if (STREQ(prop_id, "seed") && (gap_duration > 0.0f) && (gap_randomness > 0.0f)) return true; } } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index e6f6644fd24..c03766a95e1 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -999,7 +999,7 @@ static void gp_session_validatebuffer(tGPsdata *p) } /* (re)init new painting data */ -static int gp_session_initdata(bContext *C, tGPsdata *p) +static bool gp_session_initdata(bContext *C, tGPsdata *p) { bGPdata **gpd_ptr = NULL; ScrArea *curarea = CTX_wm_area(C); @@ -1082,7 +1082,13 @@ static int gp_session_initdata(bContext *C, tGPsdata *p) case SPACE_CLIP: { SpaceClip *sc = curarea->spacedata.first; + MovieClip *clip = ED_space_clip_get_clip(sc); + if (clip == NULL) { + p->status = GP_STATUS_ERROR; + return false; + } + /* set the current area */ p->sa = curarea; p->ar = ar; @@ -1097,13 +1103,18 @@ static int gp_session_initdata(bContext *C, tGPsdata *p) p->custom_color[3] = 0.9f; if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) { - MovieClip *clip = ED_space_clip_get_clip(sc); int framenr = ED_space_clip_get_clip_frame_number(sc); MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking); - MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); - - p->imat[3][0] -= marker->pos[0]; - p->imat[3][1] -= marker->pos[1]; + MovieTrackingMarker *marker = track ? BKE_tracking_marker_get(track, framenr) : NULL; + + if (marker) { + p->imat[3][0] -= marker->pos[0]; + p->imat[3][1] -= marker->pos[1]; + } + else { + p->status = GP_STATUS_ERROR; + return false; + } } invert_m4_m4(p->mat, p->imat); diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 7967d6a4d95..9ba77a4244e 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -136,11 +136,14 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op) bGPDspoint *pt; int i; - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - pt->flag &= ~GP_SPOINT_SELECT; + /* only edit strokes that are valid in this view... */ + if (ED_gpencil_stroke_can_use(C, gps)) { + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + pt->flag &= ~GP_SPOINT_SELECT; + } + + gps->flag &= ~GP_STROKE_SELECT; } - - gps->flag &= ~GP_STROKE_SELECT; } } } diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c index 5f0647fb43d..34e640a4b7b 100644 --- a/source/blender/editors/gpencil/gpencil_undo.c +++ b/source/blender/editors/gpencil/gpencil_undo.c @@ -76,7 +76,7 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name) if (step == 1) { /* undo */ //printf("\t\tGP - undo step\n"); if (cur_node->prev) { - if (!name || strcmp(cur_node->name, name) == 0) { + if (!name || STREQ(cur_node->name, name)) { cur_node = cur_node->prev; new_gpd = cur_node->gpd; } @@ -85,7 +85,7 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name) else if (step == -1) { //printf("\t\tGP - redo step\n"); if (cur_node->next) { - if (!name || strcmp(cur_node->name, name) == 0) { + if (!name || STREQ(cur_node->name, name)) { cur_node = cur_node->next; new_gpd = cur_node->gpd; } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 4a913c3d2e5..289cbc568d2 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -90,6 +90,42 @@ bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]), /* ******************************************************** */ +/* Check whether given stroke can be edited given the supplied context */ +// XXX: do we need additional flags for screenspace vs dataspace? +bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps) +{ + /* sanity check */ + if (ELEM(NULL, sa, gps)) + return false; + + /* filter stroke types by flags + spacetype */ + if (gps->flag & GP_STROKE_3DSPACE) { + /* 3D strokes - only in 3D view */ + return (sa->spacetype == SPACE_VIEW3D); + } + else if (gps->flag & GP_STROKE_2DIMAGE) { + /* Special "image" strokes - only in Image Editor */ + return (sa->spacetype == SPACE_IMAGE); + } + else if (gps->flag & GP_STROKE_2DSPACE) { + /* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */ + return (sa->spacetype != SPACE_VIEW3D); + } + else { + /* view aligned - anything goes */ + return true; + } +} + +/* Check whether given stroke can be edited in the current context */ +bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps) +{ + ScrArea *sa = CTX_wm_area(C); + return ED_gpencil_stroke_can_use_direct(sa, gps); +} + +/* ******************************************************** */ + /* Init handling for space-conversion function (from passed-in parameters) */ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc) { @@ -127,7 +163,9 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc) } -/* Convert Grease Pencil points to screen-space values */ +/* Convert Grease Pencil points to screen-space values + * WARNING: This assumes that the caller has already checked whether the stroke in question can be drawn + */ void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt, int *r_x, int *r_y) { @@ -135,7 +173,12 @@ void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt, View2D *v2d = gsc->v2d; rctf *subrect = gsc->subrect; int xyval[2]; - + + /* sanity checks */ + BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D)); + BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D)); + + if (gps->flag & GP_STROKE_3DSPACE) { if (ED_view3d_project_int_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { *r_x = xyval[0]; @@ -152,11 +195,13 @@ void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt, UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], r_x, r_y); } else { - if (subrect == NULL) { /* normal 3D view */ + if (subrect == NULL) { + /* normal 3D view (or view space) */ *r_x = (int)(pt->x / 100 * ar->winx); *r_y = (int)(pt->y / 100 * ar->winy); } - else { /* camera view, use subrect */ + else { + /* camera view, use subrect */ *r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin; *r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin; } diff --git a/source/blender/editors/include/BIF_gl.h b/source/blender/editors/include/BIF_gl.h index b06af01bab6..3b7d7bac44f 100644 --- a/source/blender/editors/include/BIF_gl.h +++ b/source/blender/editors/include/BIF_gl.h @@ -35,10 +35,6 @@ #include "GPU_glew.h" -/* hacking pointsize and linewidth */ -#define glPointSize(f) glPointSize(U.pixelsize * (f)) -#define glLineWidth(f) glLineWidth(U.pixelsize * (f)) - /* * these should be phased out. cpack should be replaced in * code with calls to glColor3ub. - zr @@ -51,7 +47,6 @@ * */ void cpack(unsigned int x); - #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) # define glMultMatrixf(x) \ glMultMatrixf(_Generic((x), \ @@ -71,9 +66,14 @@ void cpack(unsigned int x); float (*)[4]: (float *)(x), \ float [4][4]: (float *)(x)) \ ) +/* hacking pointsize and linewidth */ +#define glPointSize(f) glPointSize(U.pixelsize * _Generic((f), double: (float)(f), default: (f))) +#define glLineWidth(f) glLineWidth(U.pixelsize * _Generic((f), double: (float)(f), default: (f))) #else # define glMultMatrixf(x) glMultMatrixf((float *)(x)) # define glLoadMatrixf(x) glLoadMatrixf((float *)(x)) +#define glPointSize(f) glPointSize(U.pixelsize * (f)) +#define glLineWidth(f) glLineWidth(U.pixelsize * (f)) #endif #define GLA_PIXEL_OFS 0.375f diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index b0d1be1bf5d..c4f08ca4775 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -43,6 +43,7 @@ struct Object; struct bGPdata; struct bGPDlayer; struct bGPDframe; +struct bGPDstroke; struct PointerRNA; struct ImBuf; struct wmKeyConfig; @@ -80,6 +81,11 @@ struct bGPdata *ED_gpencil_data_get_active_direct(struct ID *screen_id, struct S /* 3D View */ struct bGPdata *ED_gpencil_data_get_active_v3d(struct Scene *scene, struct View3D *v3d); +/* ----------- Stroke Editing Utilities ---------------- */ + +bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *sa, const struct bGPDstroke *gps); +bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps); + /* ----------- Grease Pencil Operators ----------------- */ void ED_keymap_gpencil(struct wmKeyConfig *keyconf); diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index 1188ecd0aa5..704876e1261 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -35,6 +35,7 @@ struct Main; struct bContext; struct Image; struct ImageUser; +struct ImBuf; struct ToolSettings; struct uiBlock; struct wmWindowManager; @@ -58,6 +59,8 @@ void ED_space_image_get_aspect(struct SpaceImage *sima, float *aspx, float *aspy void ED_space_image_get_zoom(struct SpaceImage *sima, struct ARegion *ar, float *zoomx, float *zoomy); void ED_space_image_get_uv_aspect(struct SpaceImage *sima, float *aspx, float *aspy); +void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *sima, struct ImBuf *ibuf, bool use_view_settings); + void ED_space_image_paint_update(struct wmWindowManager *wm, struct ToolSettings *settings); void ED_space_image_uv_sculpt_update(struct wmWindowManager *wm, struct ToolSettings *settings); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 900da3ee07c..ccdde39f263 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -141,9 +141,9 @@ bool ED_object_editmode_load(struct Object *obedit); void ED_object_location_from_view(struct bContext *C, float loc[3]); void ED_object_rotation_from_view(struct bContext *C, float rot[3], const char align_axis); void ED_object_base_init_transform(struct bContext *C, struct Base *base, const float loc[3], const float rot[3]); -float ED_object_new_primitive_matrix(struct bContext *C, struct Object *editob, - const float loc[3], const float rot[3], float primmat[4][4], - bool apply_diameter); +float ED_object_new_primitive_matrix( + struct bContext *C, struct Object *editob, + const float loc[3], const float rot[3], float primmat[4][4]); void ED_object_add_unit_props(struct wmOperatorType *ot); void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index b790c656b61..8c33395cc49 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -107,7 +107,7 @@ void ED_screen_set_subwinactive(struct bContext *C, struct wmEvent *event); void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen); void ED_screen_animation_timer(struct bContext *C, int redraws, int refresh, int sync, int enable); void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh); -void ED_screen_retore_temp_type(struct bContext *C, ScrArea *sa, bool is_screen_change); +void ED_screen_restore_temp_type(struct bContext *C, ScrArea *sa); ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *sa, int type); void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa); void ED_screen_full_restore(struct bContext *C, ScrArea *sa); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 76ad4ba7bdb..b62d9960117 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -310,7 +310,6 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D bool draw_background, int alpha_mode, char err_out[256]); struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype, bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, char err_out[256]); -void ED_view3d_offscreen_sky_color_get(struct Scene *scene, float sky_color[3]); struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]); void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip); diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index fa349c4f006..bfb7a3420c9 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -54,7 +54,7 @@ DEF_ICON(DOT) DEF_ICON(COLLAPSEMENU) DEF_ICON(X) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK005) + DEF_ICON(BLANK005) /* XXX 'DOWNARROW' icon! */ #endif DEF_ICON(GO_LEFT) DEF_ICON(PLUG) @@ -461,9 +461,9 @@ DEF_ICON(FORCE_SMOKEFLOW) DEF_ICON(BLANK685) /* EMPTY */ - DEF_ICON(BLANK690) - DEF_ICON(BLANK691) - DEF_ICON(BLANK692) + DEF_ICON(BLANK690) /* XXX 'Temperature' icon! */ + DEF_ICON(BLANK691) /* XXX 'Temperature' icon! */ + DEF_ICON(BLANK692) /* XXX 'Gear' icon! */ DEF_ICON(BLANK693) DEF_ICON(BLANK694) DEF_ICON(BLANK695) @@ -590,8 +590,8 @@ DEF_ICON(MOD_SKIN) DEF_ICON(MOD_TRIANGULATE) DEF_ICON(MOD_WIREFRAME) DEF_ICON(MOD_DATA_TRANSFER) +DEF_ICON(MOD_NORMALEDIT) #ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK168) DEF_ICON(BLANK169) DEF_ICON(BLANK170) DEF_ICON(BLANK171) @@ -689,7 +689,7 @@ DEF_ICON(RNDCURVE) DEF_ICON(PROP_OFF) DEF_ICON(PROP_ON) DEF_ICON(PROP_CON) -DEF_ICON(SCULPT_DYNTOPO) +DEF_ICON(SCULPT_DYNTOPO) /* XXX Empty icon! */ DEF_ICON(PARTICLE_POINT) DEF_ICON(PARTICLE_TIP) DEF_ICON(PARTICLE_PATH) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 8789e837f17..590ab1d694d 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -316,6 +316,10 @@ void UI_draw_roundbox_shade_x(int mode, float minx, float miny, float maxx, floa void UI_draw_roundbox_shade_y(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadeLeft, float shadeRight); void UI_draw_text_underline(int pos_x, int pos_y, int len, int height); +void UI_draw_safe_areas( + float x1, float x2, float y1, float y2, + const float title_aspect[2], const float action_aspect[2]); + /* state for scrolldrawing */ #define UI_SCROLL_PRESSED (1 << 0) #define UI_SCROLL_ARROWS (1 << 1) @@ -888,6 +892,7 @@ void uiTemplateGameStates(uiLayout *layout, struct PointerRNA *ptr, const char * void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, int compact); void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, int color_management); void uiTemplateImageLayers(uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser); +void uiTemplateImageInfo(uiLayout *layout, struct bContext *C, Image *ima, ImageUser *iuser); void uiTemplateRunningJobs(uiLayout *layout, struct bContext *C); void UI_but_func_operator_search(uiBut *but); void uiTemplateOperatorSearch(uiLayout *layout); @@ -970,15 +975,20 @@ void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop); /* Styled text draw */ -void UI_fontstyle_set(struct uiFontStyle *fs); +void UI_fontstyle_set(const struct uiFontStyle *fs); void UI_fontstyle_draw_ex( - struct uiFontStyle *fs, const struct rcti *rect, const char *str, + const struct uiFontStyle *fs, const struct rcti *rect, const char *str, size_t len, float *r_xofs, float *r_yofs); -void UI_fontstyle_draw(struct uiFontStyle *fs, const struct rcti *rect, const char *str); -void UI_fontstyle_draw_rotated(struct uiFontStyle *fs, const struct rcti *rect, const char *str); +void UI_fontstyle_draw(const struct uiFontStyle *fs, const struct rcti *rect, const char *str); +void UI_fontstyle_draw_rotated(const struct uiFontStyle *fs, const struct rcti *rect, const char *str); +void UI_fontstyle_draw_simple(const struct uiFontStyle *fs, float x, float y, const char *str); +void UI_fontstyle_draw_simple_backdrop( + const uiFontStyle *fs, float x, float y, const char *str, + const unsigned char fg[4], const unsigned char bg[4]); + +int UI_fontstyle_string_width(const struct uiFontStyle *fs, const char *str); +int UI_fontstyle_height_max(const struct uiFontStyle *fs); -int UI_fontstyle_string_width(const char *str); // XXX temp -void UI_draw_string(float x, float y, const char *str); // XXX temp void UI_draw_icon_tri(float x, float y, char dir); uiStyle *UI_style_get(void); /* use for fonts etc */ @@ -1009,6 +1019,9 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p); /* Float precision helpers */ #define UI_PRECISION_FLOAT_MAX 7 +/* Typical UI text */ +#define UI_FSTYLE_WIDGET (const uiFontStyle *)&(UI_style_get()->widget) + int UI_calc_float_precision(int prec, double value); #endif /* __UI_INTERFACE_H__ */ diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index d289e90c257..4a6d9911d3b 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -293,6 +293,8 @@ enum { TH_INFO_DEBUG, TH_INFO_DEBUG_TEXT, TH_VIEW_OVERLAY, + + TH_V3D_CLIPPING_BORDER }; /* XXX WARNING: previous is saved in file, so do not change order! */ diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 0b1d1c8c30c..8fa604d57cb 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -297,7 +297,7 @@ void ui_block_bounds_calc(uiBlock *block) /* hardcoded exception... but that one is annoying with larger safety */ bt = block->buttons.first; - if (bt && strncmp(bt->str, "ERROR", 5) == 0) xof = 10; + if (bt && STREQLEN(bt->str, "ERROR", 5)) xof = 10; else xof = 40; block->safety.xmin = block->rect.xmin - xof; diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index bcd9b9a5547..e03ea5efba4 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -450,6 +450,51 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w #endif } +/** + * Draw title and text safe areas. + * + * The first 4 parameters are the offsets for the view, not the zones. + */ +void UI_draw_safe_areas( + float x1, float x2, float y1, float y2, + const float title_aspect[2], const float action_aspect[2]) +{ + const float size_x_half = (x2 - x1) * 0.5f; + const float size_y_half = (y2 - y1) * 0.5f; + + const float *safe_areas[] = {title_aspect, action_aspect}; + int i, safe_len = ARRAY_SIZE(safe_areas); + bool is_first = true; + + for (i = 0; i < safe_len; i++) { + if (safe_areas[i][0] || safe_areas[i][1]) { + float margin_x, margin_y; + float minx, miny, maxx, maxy; + + if (is_first) { + UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0); + is_first = false; + } + + margin_x = safe_areas[i][0] * size_x_half; + margin_y = safe_areas[i][1] * size_y_half; + + minx = x1 + margin_x; + miny = y1 + margin_y; + maxx = x2 - margin_x; + maxy = y2 - margin_y; + + glBegin(GL_LINE_LOOP); + glVertex2f(maxx, miny); + glVertex2f(maxx, maxy); + glVertex2f(minx, maxy); + glVertex2f(minx, miny); + glEnd(); + } + } +} + + static void draw_scope_end(const rctf *rect, GLint *scissor) { /* restore scissortest */ @@ -494,7 +539,7 @@ static void histogram_draw_one(float r, float g, float b, float alpha, glColor4f(r, g, b, alpha); glShadeModel(GL_FLAT); - glBegin(GL_QUAD_STRIP); + glBegin(GL_TRIANGLE_STRIP); glVertex2f(x, y); glVertex2f(x, y + (data[0] * h)); for (i = 1; i < res; i++) { @@ -777,8 +822,8 @@ static void vectorscope_draw_target(float centerx, float centery, float diam, co if (u > 0 && v >= 0) tangle = atanf(v / u); else if (u > 0 && v < 0) tangle = atanf(v / u) + 2.0f * (float)M_PI; else if (u < 0) tangle = atanf(v / u) + (float)M_PI; - else if (u == 0 && v > 0.0f) tangle = (float)M_PI / 2.0f; - else if (u == 0 && v < 0.0f) tangle = -(float)M_PI / 2.0f; + else if (u == 0 && v > 0.0f) tangle = M_PI_2; + else if (u == 0 && v < 0.0f) tangle = -M_PI_2; tampli = sqrtf(u * u + v * v); /* small target vary by 2.5 degree and 2.5 IRE unit */ @@ -1102,7 +1147,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti v1[1] = y1 + sizey_solid; v2[1] = rect->ymax; - glBegin(GL_QUAD_STRIP); + glBegin(GL_TRIANGLE_STRIP); for (a = 0; a <= sizex; a++) { pos = ((float)a) / sizex; do_colorband(coba, pos, colf); @@ -1121,7 +1166,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti v1[1] = y1; v2[1] = y1 + sizey_solid; - glBegin(GL_QUAD_STRIP); + glBegin(GL_TRIANGLE_STRIP); for (a = 0; a <= sizex; a++) { pos = ((float)a) / sizex; do_colorband(coba, pos, colf); diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index d7a4720d595..f5b24f49f98 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -73,10 +73,13 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, const char *name) { - int width; + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; wmWindow *win = CTX_wm_window(C); int x = win->eventstate->x; int y = win->eventstate->y; + const unsigned char fg[4] = {255, 255, 255, 255}; + const unsigned char bg[4] = {0, 0, 0, 50}; + if ((name[0] == '\0') || (BLI_rcti_isect_pt(&ar->winrct, x, y) == false)) @@ -84,19 +87,12 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c return; } - width = UI_fontstyle_string_width(name); x = x - ar->winrct.xmin; y = y - ar->winrct.ymin; - y += 20; - - glColor4ub(0, 0, 0, 50); - - UI_draw_roundbox_corner_set(UI_CNR_ALL | UI_RB_ALPHA); - UI_draw_roundbox(x, y, x + width + 8, y + 15, 4); + y += U.widget_unit; - glColor4ub(255, 255, 255, 255); - UI_draw_string(x + 4, y + 4, name); + UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg); } /** \} */ @@ -176,43 +172,42 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int /* we could use some clever */ wmWindow *win = CTX_wm_window(C); - ScrArea *sa; - for (sa = win->screen->areabase.first; sa; sa = sa->next) { - if (BLI_rcti_isect_pt(&sa->totrct, mx, my)) { - if (sa->spacetype == SPACE_IMAGE) { - ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); - if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { - SpaceImage *sima = sa->spacedata.first; - int mval[2] = {mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - - if (ED_space_image_color_sample(CTX_data_scene(C), sima, ar, mval, r_col)) { - return; - } + ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my); + + if (sa) { + if (sa->spacetype == SPACE_IMAGE) { + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { + SpaceImage *sima = sa->spacedata.first; + int mval[2] = {mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + + if (ED_space_image_color_sample(CTX_data_scene(C), sima, ar, mval, r_col)) { + return; } } - else if (sa->spacetype == SPACE_NODE) { - ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); - if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { - SpaceNode *snode = sa->spacedata.first; - int mval[2] = {mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - - if (ED_space_node_color_sample(CTX_data_scene(C), snode, ar, mval, r_col)) { - return; - } + } + else if (sa->spacetype == SPACE_NODE) { + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { + SpaceNode *snode = sa->spacedata.first; + int mval[2] = {mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + + if (ED_space_node_color_sample(CTX_data_scene(C), snode, ar, mval, r_col)) { + return; } } - else if (sa->spacetype == SPACE_CLIP) { - ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); - if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { - SpaceClip *sc = sa->spacedata.first; - int mval[2] = {mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - - if (ED_space_clip_color_sample(CTX_data_scene(C), sc, ar, mval, r_col)) { - return; - } + } + else if (sa->spacetype == SPACE_CLIP) { + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { + SpaceClip *sc = sa->spacedata.first; + int mval[2] = {mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + + if (ED_space_clip_color_sample(CTX_data_scene(C), sc, ar, mval, r_col)) { + return; } } } @@ -477,53 +472,49 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int /* we could use some clever */ wmWindow *win = CTX_wm_window(C); - ScrArea *sa; + ScrArea *sa = BKE_screen_find_area_xy(win->screen, -1, mx, my); ScrArea *area_prev = CTX_wm_area(C); ARegion *ar_prev = CTX_wm_region(C); ddr->name[0] = '\0'; - for (sa = win->screen->areabase.first; sa; sa = sa->next) { - if (BLI_rcti_isect_pt(&sa->totrct, mx, my)) { - if (sa->spacetype == SPACE_VIEW3D) { - ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); - if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { - const int mval[2] = { - mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - Base *base; - - CTX_wm_area_set(C, sa); - CTX_wm_region_set(C, ar); - - /* grr, always draw else we leave stale text */ - ED_region_tag_redraw(ar); - - base = ED_view3d_give_base_under_cursor(C, mval); - if (base) { - Object *ob = base->object; - ID *id = NULL; - if (ddr->idcode == ID_OB) { - id = (ID *)ob; - } - else if (ob->data) { - if (GS(((ID *)ob->data)->name) == ddr->idcode) { - id = (ID *)ob->data; - } - else { - BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s", - ddr->idcode_name); - } + if (sa) { + if (sa->spacetype == SPACE_VIEW3D) { + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { + const int mval[2] = { + mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + Base *base; + + CTX_wm_area_set(C, sa); + CTX_wm_region_set(C, ar); + + /* grr, always draw else we leave stale text */ + ED_region_tag_redraw(ar); + + base = ED_view3d_give_base_under_cursor(C, mval); + if (base) { + Object *ob = base->object; + ID *id = NULL; + if (ddr->idcode == ID_OB) { + id = (ID *)ob; + } + else if (ob->data) { + if (GS(((ID *)ob->data)->name) == ddr->idcode) { + id = (ID *)ob->data; } - - if (id) { - BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s", - ddr->idcode_name, id->name + 2); - *r_id = id; + else { + BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s", + ddr->idcode_name); } + } - break; + if (id) { + BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s", + ddr->idcode_name, id->name + 2); + *r_id = id; } } } @@ -760,7 +751,7 @@ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, /* we could use some clever */ wmWindow *win = CTX_wm_window(C); - ScrArea *sa; + ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my); Scene *scene = win->screen->scene; UnitSettings *unit = &scene->unit; const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0; @@ -770,47 +761,44 @@ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, ddr->name[0] = '\0'; - for (sa = win->screen->areabase.first; sa; sa = sa->next) { - if (BLI_rcti_isect_pt(&sa->totrct, mx, my)) { - if (sa->spacetype == SPACE_VIEW3D) { - ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); - if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { - View3D *v3d = sa->spacedata.first; - RegionView3D *rv3d = ar->regiondata; - /* weak, we could pass in some reference point */ - const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3]; - const int mval[2] = { - mx - ar->winrct.xmin, - my - ar->winrct.ymin}; - float co[3]; - - CTX_wm_area_set(C, sa); - CTX_wm_region_set(C, ar); - - /* grr, always draw else we leave stale text */ - ED_region_tag_redraw(ar); - - view3d_operator_needs_opengl(C); - - if (ED_view3d_autodist(scene, ar, v3d, mval, co, true, NULL)) { - const float mval_center_fl[2] = { - (float)ar->winx / 2, - (float)ar->winy / 2}; - float co_align[3]; - - /* quick way to get view-center aligned point */ - ED_view3d_win_to_3d(ar, co, mval_center_fl, co_align); - - *r_depth = len_v3v3(view_co, co_align); - - bUnit_AsString(ddr->name, sizeof(ddr->name), - (double)*r_depth, - 4, unit->system, B_UNIT_LENGTH, do_split, false); - } - else { - BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name)); - } - break; + if (sa) { + if (sa->spacetype == SPACE_VIEW3D) { + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) { + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + /* weak, we could pass in some reference point */ + const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3]; + const int mval[2] = { + mx - ar->winrct.xmin, + my - ar->winrct.ymin}; + float co[3]; + + CTX_wm_area_set(C, sa); + CTX_wm_region_set(C, ar); + + /* grr, always draw else we leave stale text */ + ED_region_tag_redraw(ar); + + view3d_operator_needs_opengl(C); + + if (ED_view3d_autodist(scene, ar, v3d, mval, co, true, NULL)) { + const float mval_center_fl[2] = { + (float)ar->winx / 2, + (float)ar->winy / 2}; + float co_align[3]; + + /* quick way to get view-center aligned point */ + ED_view3d_win_to_3d(ar, co, mval_center_fl, co_align); + + *r_depth = len_v3v3(view_co, co_align); + + bUnit_AsString(ddr->name, sizeof(ddr->name), + (double)*r_depth, + 4, unit->system, B_UNIT_LENGTH, do_split, false); + } + else { + BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name)); } } } @@ -830,8 +818,10 @@ static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float d /* set sample from accumulated values */ static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr) { - float depth; - depth = ddr->accum_depth * 1.0f / (float)ddr->accum_tot; + float depth = ddr->accum_depth; + if (ddr->accum_tot) { + depth /= (float)ddr->accum_tot; + } depthdropper_depth_set(C, ddr, depth); } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 98b065dabcf..96973194576 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -114,6 +114,7 @@ static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to); static void ui_but_link_add(bContext *C, uiBut *from, uiBut *to); static int ui_do_but_EXIT(bContext *C, uiBut *but, struct uiHandleButtonData *data, const wmEvent *event); +static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b); #ifdef USE_KEYNAV_LIMIT static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEvent *event); @@ -355,6 +356,12 @@ static enum eSnapType ui_event_to_snap(const wmEvent *event) return (event->ctrl) ? (event->shift) ? SNAP_ON_SMALL : SNAP_ON : SNAP_OFF; } +static bool ui_event_is_snap(const wmEvent *event) +{ + return (ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY) || + ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY)); +} + static void ui_color_snap_hue(const enum eSnapType snap, float *r_hue) { const float snap_increment = (snap == SNAP_ON_SMALL) ? 24 : 12; @@ -2749,7 +2756,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle case VKEY: case XKEY: case CKEY: - if (event->ctrl || event->oskey) { + if (IS_EVENT_MOD(event, ctrl, oskey)) { if (event->type == VKEY) changed = ui_textedit_copypaste(but, data, UI_TEXTEDIT_PASTE); else if (event->type == CKEY) @@ -2822,10 +2829,10 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle /* Ctrl + A: Select all */ #if defined(__APPLE__) /* OSX uses cmd-a systemwide, so add it */ - if ((event->oskey && !(event->alt || event->shift || event->ctrl)) || - (event->ctrl && !(event->alt || event->shift || event->oskey))) + if ((event->oskey && !IS_EVENT_MOD(event, shift, alt, ctrl)) || + (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey))) #else - if (event->ctrl && !(event->alt || event->shift || event->oskey)) + if (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey)) #endif { ui_textedit_move(but, data, STRCUR_DIR_PREV, @@ -2848,7 +2855,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle update = true; /* do live update for tab key */ } /* the hotkey here is not well defined, was G.qual so we check all */ - else if (event->shift || event->ctrl || event->alt || event->oskey) { + else if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) { ui_textedit_prev_but(block, but, data); button_activate_state(C, but, BUTTON_STATE_EXIT); } @@ -3342,6 +3349,38 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons button_activate_state(C, but, BUTTON_STATE_EXIT); return WM_UI_HANDLER_BREAK; } + else if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) { + /* Support alt+wheel on expanded enum rows */ + if (but->type == UI_BTYPE_ROW) { + const int direction = (event->type == WHEELDOWNMOUSE) ? -1 : 1; + uiBut *but_select = ui_but_find_select_in_enum(but, direction); + if (but_select) { + uiBut *but_other = (direction == -1) ? but_select->next : but_select->prev; + if (but_other && ui_but_find_select_in_enum__cmp(but, but_other)) { + ARegion *ar = data->region; + + data->cancel = true; + button_activate_exit(C, but, data, false, false); + + /* Activate the text button. */ + button_activate_init(C, ar, but_other, BUTTON_ACTIVATE_OVER); + data = but_other->active; + if (data) { + ui_apply_but(C, but->block, but_other, but_other->active, true); + button_activate_exit(C, but_other, data, false, false); + + /* restore active button */ + button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER); + } + else { + /* shouldn't happen */ + BLI_assert(0); + } + } + } + return WM_UI_HANDLER_BREAK; + } + } } return WM_UI_HANDLER_CONTINUE; } @@ -3706,7 +3745,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton click = 1; } } - else if (event->type == MOUSEMOVE) { + else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) { const enum eSnapType snap = ui_event_to_snap(event); float fac; @@ -4003,7 +4042,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton click = 1; } } - else if (event->type == MOUSEMOVE) { + else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) { #ifdef USE_DRAG_MULTINUM data->multi_data.drag_dir[0] += abs(data->draglastx - mx); data->multi_data.drag_dir[1] += abs(data->draglasty - my); @@ -4542,8 +4581,8 @@ static int ui_do_but_UNITVEC(bContext *C, uiBlock *block, uiBut *but, uiHandleBu } } else if (data->state == BUTTON_STATE_NUM_EDITING) { - if (event->type == MOUSEMOVE) { - if (mx != data->draglastx || my != data->draglasty) { + if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) { + if (mx != data->draglastx || my != data->draglasty || event->type != MOUSEMOVE) { const enum eSnapType snap = ui_event_to_snap(event); if (ui_numedit_but_UNITVEC(but, data, mx, my, snap)) ui_numedit_apply(C, block, but, data); @@ -4862,8 +4901,8 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu button_activate_state(C, but, BUTTON_STATE_EXIT); } } - else if (event->type == MOUSEMOVE) { - if (mx != data->draglastx || my != data->draglasty) { + else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) { + if (mx != data->draglastx || my != data->draglasty || event->type != MOUSEMOVE) { const enum eSnapType snap = ui_event_to_snap(event); if (ui_numedit_but_HSVCUBE(but, data, mx, my, snap, event->shift != 0)) @@ -5134,8 +5173,8 @@ static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandle ui_but_hsv_set(but); /* converts to rgb */ ui_numedit_apply(C, block, but, data); } - else if (event->type == MOUSEMOVE) { - if (mx != data->draglastx || my != data->draglasty) { + else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) { + if (mx != data->draglastx || my != data->draglasty || event->type != MOUSEMOVE) { const enum eSnapType snap = ui_event_to_snap(event); if (ui_numedit_but_HSVCIRCLE(but, data, mx, my, snap, event->shift != 0)) { @@ -6254,7 +6293,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * if ((data->state == BUTTON_STATE_HIGHLIGHT) || (event->type == EVT_DROP)) { /* handle copy-paste */ - if (ELEM(event->type, CKEY, VKEY) && event->val == KM_PRESS && (event->ctrl || event->oskey)) { + if (ELEM(event->type, CKEY, VKEY) && event->val == KM_PRESS && + IS_EVENT_MOD(event, ctrl, oskey)) + { /* Specific handling for listrows, we try to find their overlapping tex button. */ if (but->type == UI_BTYPE_LISTROW) { uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_OVER); @@ -6273,7 +6314,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * } /* handle eyedropper */ else if ((event->type == EKEY) && (event->val == KM_PRESS)) { - if (event->alt || event->shift || event->ctrl || event->oskey) { + if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) { /* pass */ } else { @@ -6305,7 +6346,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * } /* handle keyframing */ else if ((event->type == IKEY) && - !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey) && + !IS_EVENT_MOD(event, ctrl, oskey) && (event->val == KM_PRESS)) { if (event->alt) { @@ -6326,7 +6367,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * } /* handle drivers */ else if ((event->type == DKEY) && - !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && + !IS_EVENT_MOD(event, shift, ctrl, oskey) && (event->val == KM_PRESS)) { if (event->alt) @@ -6340,7 +6381,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * } /* handle keyingsets */ else if ((event->type == KKEY) && - !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && + !IS_EVENT_MOD(event, shift, ctrl, oskey) && (event->val == KM_PRESS)) { if (event->alt) @@ -6353,7 +6394,10 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * return WM_UI_HANDLER_BREAK; } /* handle menu */ - else if (event->type == RIGHTMOUSE && event->val == KM_PRESS) { + else if ((event->type == RIGHTMOUSE) && + !IS_EVENT_MOD(event, shift, ctrl, alt, oskey) && + (event->val == KM_PRESS)) + { /* RMB has two options now */ if (ui_but_menu(C, but)) { return WM_UI_HANDLER_BREAK; @@ -6591,6 +6635,45 @@ static bool ui_but_isect_pie_seg(uiBlock *block, uiBut *but) return false; } +static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b) +{ + return ((but_a->type == but_b->type) && + (but_a->alignnr == but_b->alignnr) && + (but_a->poin == but_b->poin) && + (but_a->rnapoin.type == but_b->rnapoin.type) && + (but_a->rnaprop == but_b->rnaprop)); +} + +/** + * Finds the pressed button in an aligned row (typically an expanded enum). + * + * \param direction Use when there may be multiple buttons pressed. + */ +uiBut *ui_but_find_select_in_enum(uiBut *but, int direction) +{ + uiBut *but_iter = but; + uiBut *but_found = NULL; + BLI_assert(ELEM(direction, -1, 1)); + + while ((but_iter->prev) && + ui_but_find_select_in_enum__cmp(but_iter->prev, but)) + { + but_iter = but_iter->prev; + } + + while (but_iter && ui_but_find_select_in_enum__cmp(but_iter, but)) { + if (but_iter->flag & UI_SELECT) { + but_found = but_iter; + if (direction == 1) { + break; + } + } + but_iter = but_iter->next; + } + + return but_found; +} + uiBut *ui_but_find_active_in_region(ARegion *ar) { uiBlock *block; @@ -8301,7 +8384,7 @@ static int ui_handle_menu_event( case WHEELDOWNMOUSE: case MOUSEPAN: /* arrowkeys: only handle for block_loop blocks */ - if (event->alt || event->shift || event->ctrl || event->oskey) { + if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) { /* pass */ } else if (inside || (block->flag & UI_BLOCK_LOOP)) { @@ -8446,9 +8529,7 @@ static int ui_handle_menu_event( case ZKEY: { if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) && - (event->shift == 0) && - (event->ctrl == 0) && - (event->oskey == 0)) + !IS_EVENT_MOD(event, shift, ctrl, oskey)) { if (ui_menu_pass_event_to_parent_if_nonactive(menu, but, level, retval)) break; @@ -8825,7 +8906,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle block->pie_data.duration_gesture = duration; } - if (len_sq < 1.0) { + if (len_sq < 1.0f) { uiBut *but = ui_but_find_active_in_region(menu->region); if (but) { @@ -8940,9 +9021,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle case ZKEY: { if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) && - (event->shift == 0) && - (event->ctrl == 0) && - (event->oskey == 0)) + !IS_EVENT_MOD(event, shift, ctrl, oskey)) { for (but = block->buttons.first; but; but = but->next) { if (but->menu_key == event->type) { @@ -9123,13 +9202,13 @@ static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata)) ui_apply_but_funcs_after(C); } +/* handle buttons at the window level, modal, for example while + * number sliding, text editing, or when a menu block is open */ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSED(userdata)) { ARegion *ar; uiBut *but; - /* here we handle buttons at the window level, modal, for example - * while number sliding, text editing, or when a menu block is open */ ar = CTX_wm_menu(C); if (!ar) ar = CTX_wm_region(C); @@ -9137,13 +9216,32 @@ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSE but = ui_but_find_active_in_region(ar); if (but) { + bScreen *screen = CTX_wm_screen(C); + ARegion *ar_temp; uiBut *but_other; uiHandleButtonData *data; + bool is_inside_menu = false; + + /* look for a popup menu containing the mouse */ + for (ar_temp = screen->regionbase.first; ar_temp; ar_temp = ar_temp->next) { + rcti rect = ar_temp->winrct; + + /* resize region rect to ignore shadow */ + BLI_rcti_resize(&rect, (BLI_rcti_size_x(&ar_temp->winrct) - UI_ThemeMenuShadowWidth() * 2), + (BLI_rcti_size_y(&ar_temp->winrct) - UI_ThemeMenuShadowWidth() * 2)); + if (BLI_rcti_isect_pt_v(&rect, &event->x)) { + BLI_assert(ar_temp->type->regionid == RGN_TYPE_TEMPORARY); + + is_inside_menu = true; + break; + } + } /* handle activated button events */ data = but->active; if ((data->state == BUTTON_STATE_MENU_OPEN) && + (is_inside_menu == false) && /* make sure mouse isn't inside another menu (see T43247) */ (but->type == UI_BTYPE_PULLDOWN) && (but_other = ui_but_find_mouse_over(ar, event)) && (but != but_other) && diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 54ba3d784d1..458e268170f 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -616,6 +616,7 @@ extern void ui_but_active_free(const struct bContext *C, uiBut *but); extern bool ui_but_is_active(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT; extern int ui_but_menu_direction(uiBut *but); extern void ui_but_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore); +extern uiBut *ui_but_find_select_in_enum(uiBut *but, int direction); extern uiBut *ui_but_find_active_in_region(struct ARegion *ar); bool ui_but_is_editable(const uiBut *but); bool ui_but_is_editable_as_text(const uiBut *but); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index f02c6a234a9..fb73b8ec34c 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -235,9 +235,10 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool variable = (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X); if (variable) { + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; /* it may seem odd that the icon only adds (UI_UNIT_X / 4) * but taking margins into account its fine */ - return (UI_fontstyle_string_width(name) + + return (UI_fontstyle_string_width(fstyle, name) + (UI_UNIT_X * ((compact ? 1.25f : 1.50f) + (icon ? 0.25f : 0.0f)))); } @@ -639,7 +640,7 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *n if (name[0]) { /* XXX UI_fontstyle_string_width is not accurate */ #if 0 - labelw = UI_fontstyle_string_width(name); + labelw = UI_fontstyle_string_width(fstyle, name); CLAMP(labelw, w / 4, 3 * w / 4); #endif labelw = w / 3; @@ -1003,7 +1004,7 @@ void uiItemEnumO_value(uiLayout *layout, const char *name, int icon, const char PointerRNA ptr; PropertyRNA *prop; - UI_OPERATOR_ERROR_RET(ot, opname, return ); + UI_OPERATOR_ERROR_RET(ot, opname, return); WM_operator_properties_create_ptr(&ptr, ot); @@ -1035,7 +1036,7 @@ void uiItemEnumO_string(uiLayout *layout, const char *name, int icon, const char int value; bool free; - UI_OPERATOR_ERROR_RET(ot, opname, return ); + UI_OPERATOR_ERROR_RET(ot, opname, return); WM_operator_properties_create_ptr(&ptr, ot); @@ -1074,7 +1075,7 @@ void uiItemBooleanO(uiLayout *layout, const char *name, int icon, const char *op wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ PointerRNA ptr; - UI_OPERATOR_ERROR_RET(ot, opname, return ); + UI_OPERATOR_ERROR_RET(ot, opname, return); WM_operator_properties_create_ptr(&ptr, ot); RNA_boolean_set(&ptr, propname, value); @@ -1087,7 +1088,7 @@ void uiItemIntO(uiLayout *layout, const char *name, int icon, const char *opname wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ PointerRNA ptr; - UI_OPERATOR_ERROR_RET(ot, opname, return ); + UI_OPERATOR_ERROR_RET(ot, opname, return); WM_operator_properties_create_ptr(&ptr, ot); RNA_int_set(&ptr, propname, value); @@ -1100,7 +1101,7 @@ void uiItemFloatO(uiLayout *layout, const char *name, int icon, const char *opna wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ PointerRNA ptr; - UI_OPERATOR_ERROR_RET(ot, opname, return ); + UI_OPERATOR_ERROR_RET(ot, opname, return); WM_operator_properties_create_ptr(&ptr, ot); RNA_float_set(&ptr, propname, value); @@ -1113,7 +1114,7 @@ void uiItemStringO(uiLayout *layout, const char *name, int icon, const char *opn wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ PointerRNA ptr; - UI_OPERATOR_ERROR_RET(ot, opname, return ); + UI_OPERATOR_ERROR_RET(ot, opname, return); WM_operator_properties_create_ptr(&ptr, ot); RNA_string_set(&ptr, propname, value); @@ -1877,7 +1878,7 @@ void uiItemMenuEnumO(uiLayout *layout, bContext *C, const char *opname, const ch MenuItemLevel *lvl; uiBut *but; - UI_OPERATOR_ERROR_RET(ot, opname, return ); + UI_OPERATOR_ERROR_RET(ot, opname, return); if (!ot->srna) { ui_item_disabled(layout, opname); diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 074faaa86bc..19e389154e4 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -515,7 +515,7 @@ static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b) (but_a->rnaprop == but_b->rnaprop) && (but_a->optype == but_b->optype) && (but_a->unit_type == but_b->unit_type) && - (strncmp(but_a->drawstr, but_b->drawstr, UI_MAX_DRAW_STR) == 0)) + STREQLEN(but_a->drawstr, but_b->drawstr, UI_MAX_DRAW_STR)) { return true; } @@ -858,7 +858,7 @@ int UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(e void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop) { - uiDragColorHandle *drag_info = (uiDragColorHandle *)drag->poin; + uiDragColorHandle *drag_info = drag->poin; RNA_float_set_array(drop->ptr, "color", drag_info->color); RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index e68c86353a3..d165e2719c5 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -1490,7 +1490,7 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) } BLF_enable(fontid, BLF_ROTATION); - BLF_rotation(fontid, M_PI / 2); + BLF_rotation(fontid, M_PI_2); //UI_fontstyle_set(&style->widget); ui_fontscale(&fstyle_points, aspect / (U.pixelsize * 1.1f)); BLF_size(fontid, fstyle_points, U.dpi); @@ -1757,7 +1757,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 && !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) { + if (event->type == AKEY && ((event->ctrl + event->oskey + event->shift + event->alt) == 0)) { if (pa->flag & PNL_CLOSEDY) { if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 0ec59e4e4cd..b6a93c8306d 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -1919,7 +1919,7 @@ static void ui_update_color_picker_buts_rgb(uiBlock *block, ColorPicker *cpicker ui_but_v3_set(bt, rgb); } - else if (strcmp(bt->str, "Hex: ") == 0) { + else if (STREQ(bt->str, "Hex: ")) { float rgb_gamma[3]; unsigned char rgb_gamma_uchar[3]; double intpart; @@ -2726,7 +2726,8 @@ static uiBlock *ui_block_func_PIE(bContext *UNUSED(C), uiPopupBlockHandle *handl static float ui_pie_menu_title_width(const char *name, int icon) { - return (UI_fontstyle_string_width(name) + + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + return (UI_fontstyle_string_width(fstyle, name) + (UI_UNIT_X * (1.50f + (icon ? 0.25f : 0.0f)))); } diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 8b2ce90dcf5..2f46c0906ae 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -45,6 +45,7 @@ #include "BKE_global.h" +#include "BIF_gl.h" #include "BLF_api.h" #ifdef WITH_INTERNATIONAL @@ -147,8 +148,9 @@ static uiFont *uifont_to_blfont(int id) /* *************** draw ************************ */ -void UI_fontstyle_draw_ex(uiFontStyle *fs, const rcti *rect, const char *str, - size_t len, float *r_xofs, float *r_yofs) +void UI_fontstyle_draw_ex( + const uiFontStyle *fs, const rcti *rect, const char *str, + size_t len, float *r_xofs, float *r_yofs) { float height; int xofs = 0, yofs; @@ -194,15 +196,17 @@ void UI_fontstyle_draw_ex(uiFontStyle *fs, const rcti *rect, const char *str, *r_yofs = yofs; } -void UI_fontstyle_draw(uiFontStyle *fs, const rcti *rect, const char *str) +void UI_fontstyle_draw(const uiFontStyle *fs, const rcti *rect, const char *str) { float xofs, yofs; - UI_fontstyle_draw_ex(fs, rect, str, - BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs); + + UI_fontstyle_draw_ex( + fs, rect, str, + BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs); } /* drawn same as above, but at 90 degree angle */ -void UI_fontstyle_draw_rotated(uiFontStyle *fs, const rcti *rect, const char *str) +void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const char *str) { float height; int xofs, yofs; @@ -220,7 +224,7 @@ void UI_fontstyle_draw_rotated(uiFontStyle *fs, const rcti *rect, const char *st /* rotate counter-clockwise for now (assumes left-to-right language)*/ xofs += height; yofs = BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX) + 5; - angle = (float)M_PI / 2.0f; + angle = M_PI_2; /* translate rect to vertical */ txtrect.xmin = rect->xmin - BLI_rcti_size_y(rect); @@ -255,6 +259,66 @@ void UI_fontstyle_draw_rotated(uiFontStyle *fs, const rcti *rect, const char *st BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT); } +/** + * Similar to #UI_fontstyle_draw + * but ignore alignment, shadow & no clipping rect. + * + * For drawing on-screen labels. + */ +void UI_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const char *str) +{ + if (fs->kerning == 1) + BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT); + + UI_fontstyle_set(fs); + BLF_position(fs->uifont_id, x, y, 0.0f); + BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); + + if (fs->kerning == 1) + BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT); +} + +/** + * Same as #UI_fontstyle_draw but draw a colored backdrop. + */ +void UI_fontstyle_draw_simple_backdrop( + const uiFontStyle *fs, float x, float y, const char *str, + const unsigned char fg[4], const unsigned char bg[4]) +{ + if (fs->kerning == 1) + BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT); + + UI_fontstyle_set(fs); + + { + const float width = BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); + const float height = BLF_height_max(fs->uifont_id); + const float decent = BLF_descender(fs->uifont_id); + const float margin = height / 4.0f; + + /* backdrop */ + glColor4ubv(bg); + + UI_draw_roundbox_corner_set(UI_CNR_ALL | UI_RB_ALPHA); + UI_draw_roundbox( + x - margin, + (y + decent) - margin, + x + width + margin, + (y + decent) + height + margin, + margin); + + glColor4ubv(fg); + } + + + BLF_position(fs->uifont_id, x, y, 0.0f); + BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); + + if (fs->kerning == 1) + BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT); +} + + /* ************** helpers ************************ */ /* XXX: read a style configure */ uiStyle *UI_style_get(void) @@ -291,41 +355,29 @@ uiStyle *UI_style_get_dpi(void) return &_style; } -/* temporarily, does widget font */ -int UI_fontstyle_string_width(const char *str) +int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str) { - uiStyle *style = UI_style_get(); - uiFontStyle *fstyle = &style->widget; int width; - if (fstyle->kerning == 1) /* for BLF_width */ - BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); + if (fs->kerning == 1) /* for BLF_width */ + BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT); - UI_fontstyle_set(fstyle); - width = BLF_width(fstyle->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); + UI_fontstyle_set(fs); + width = BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); - if (fstyle->kerning == 1) - BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); + if (fs->kerning == 1) + BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT); return width; } -/* temporarily, does widget font */ -void UI_draw_string(float x, float y, const char *str) +int UI_fontstyle_height_max(const uiFontStyle *fs) { - uiStyle *style = UI_style_get(); - - if (style->widget.kerning == 1) - BLF_enable(style->widget.uifont_id, BLF_KERNING_DEFAULT); - - UI_fontstyle_set(&style->widget); - BLF_position(style->widget.uifont_id, x, y, 0.0f); - BLF_draw(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX); - - if (style->widget.kerning == 1) - BLF_disable(style->widget.uifont_id, BLF_KERNING_DEFAULT); + UI_fontstyle_set(fs); + return BLF_height_max(fs->uifont_id); } + /* ************** init exit ************************ */ /* called on each startup.blend read */ @@ -398,11 +450,10 @@ void uiStyleInit(void) if (font->blf_id == -1) { font->blf_id = BLF_load_mem("default", (unsigned char *)datatoc_bfont_ttf, datatoc_bfont_ttf_size); } - else { - BLF_default_set(font->blf_id); - } } + BLF_default_set(font->blf_id); + if (font->blf_id == -1) { if (G.debug & G_DEBUG) printf("%s: error, no fonts available\n", __func__); @@ -453,7 +504,7 @@ void uiStyleInit(void) BLF_size(blf_mono_font_render, 12 * U.pixelsize, 72); } -void UI_fontstyle_set(uiFontStyle *fs) +void UI_fontstyle_set(const uiFontStyle *fs) { uiFont *font = uifont_to_blfont(fs->uifont_id); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 407843d663c..5ac991cbd94 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2862,7 +2862,7 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co /* validate arguments */ /* Forbid default UI_UL_DEFAULT_CLASS_NAME list class without a custom list_id! */ - if (!strcmp(UI_UL_DEFAULT_CLASS_NAME, listtype_name) && !(list_id && list_id[0])) { + if (STREQ(UI_UL_DEFAULT_CLASS_NAME, listtype_name) && !(list_id && list_id[0])) { RNA_warning("template_list using default '%s' UIList class must provide a custom list_id", UI_UL_DEFAULT_CLASS_NAME); return; @@ -3570,8 +3570,7 @@ void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char colorspace_settings_ptr = RNA_property_pointer_get(ptr, prop); - uiItemL(layout, IFACE_("Input Color Space:"), ICON_NONE); - uiItemR(layout, &colorspace_settings_ptr, "name", 0, "", ICON_NONE); + uiItemR(layout, &colorspace_settings_ptr, "name", 0, IFACE_("Color Space"), ICON_NONE); } void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr, const char *propname) diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 04a886ba2a8..9b22f8a1e7f 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -610,36 +610,36 @@ static void round_box_shade_col4_r(unsigned char r_col[4], const char col1[4], c r_col[3] = (faci * col1[3] + facm * col2[3]) >> 8; } -static void widget_verts_to_quad_strip(uiWidgetBase *wtb, const int totvert, float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2]) +static void widget_verts_to_triangle_strip(uiWidgetBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]) { int a; for (a = 0; a < totvert; a++) { - copy_v2_v2(quad_strip[a * 2], wtb->outer_v[a]); - copy_v2_v2(quad_strip[a * 2 + 1], wtb->inner_v[a]); + copy_v2_v2(triangle_strip[a * 2], wtb->outer_v[a]); + copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[a]); } - copy_v2_v2(quad_strip[a * 2], wtb->outer_v[0]); - copy_v2_v2(quad_strip[a * 2 + 1], wtb->inner_v[0]); + copy_v2_v2(triangle_strip[a * 2], wtb->outer_v[0]); + copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[0]); } -static void widget_verts_to_quad_strip_open(uiWidgetBase *wtb, const int totvert, float quad_strip[WIDGET_SIZE_MAX * 2][2]) +static void widget_verts_to_triangle_strip_open(uiWidgetBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX * 2][2]) { int a; for (a = 0; a < totvert; a++) { - quad_strip[a * 2][0] = wtb->outer_v[a][0]; - quad_strip[a * 2][1] = wtb->outer_v[a][1]; - quad_strip[a * 2 + 1][0] = wtb->outer_v[a][0]; - quad_strip[a * 2 + 1][1] = wtb->outer_v[a][1] - 1.0f; + triangle_strip[a * 2][0] = wtb->outer_v[a][0]; + triangle_strip[a * 2][1] = wtb->outer_v[a][1]; + triangle_strip[a * 2 + 1][0] = wtb->outer_v[a][0]; + triangle_strip[a * 2 + 1][1] = wtb->outer_v[a][1] - 1.0f; } } static void widgetbase_outline(uiWidgetBase *wtb) { - float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */ - widget_verts_to_quad_strip(wtb, wtb->totvert, quad_strip); + float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */ + widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip); glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, quad_strip); - glDrawArrays(GL_QUAD_STRIP, 0, wtb->totvert * 2 + 2); + glVertexPointer(2, GL_FLOAT, 0, triangle_strip); + glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2); glDisableClientState(GL_VERTEX_ARRAY); } @@ -733,18 +733,18 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) /* for each AA step */ if (wtb->outline) { - float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */ - float quad_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */ + float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */ + float triangle_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */ const unsigned char tcol[4] = {wcol->outline[0], wcol->outline[1], wcol->outline[2], wcol->outline[3] / WIDGET_AA_JITTER}; - widget_verts_to_quad_strip(wtb, wtb->totvert, quad_strip); + widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip); if (wtb->emboss) { - widget_verts_to_quad_strip_open(wtb, wtb->halfwayvert, quad_strip_emboss); + widget_verts_to_triangle_strip_open(wtb, wtb->halfwayvert, triangle_strip_emboss); } glEnableClientState(GL_VERTEX_ARRAY); @@ -757,8 +757,8 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) /* outline */ glColor4ubv(tcol); - glVertexPointer(2, GL_FLOAT, 0, quad_strip); - glDrawArrays(GL_QUAD_STRIP, 0, wtb->totvert * 2 + 2); + glVertexPointer(2, GL_FLOAT, 0, triangle_strip); + glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2); /* emboss bottom shadow */ if (wtb->emboss) { @@ -766,8 +766,8 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) if (emboss[3]) { glColor4ubv(emboss); - glVertexPointer(2, GL_FLOAT, 0, quad_strip_emboss); - glDrawArrays(GL_QUAD_STRIP, 0, wtb->halfwayvert * 2); + glVertexPointer(2, GL_FLOAT, 0, triangle_strip_emboss); + glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->halfwayvert * 2); } } @@ -2098,7 +2098,7 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r rcti rect1 = *rect; float alphastep; int step, totvert; - float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2]; + float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; const float radout = UI_ThemeMenuShadowWidth(); /* disabled shadow */ @@ -2126,10 +2126,10 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r glColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac)); - widget_verts_to_quad_strip(&wtb, totvert, quad_strip); + widget_verts_to_triangle_strip(&wtb, totvert, triangle_strip); - glVertexPointer(2, GL_FLOAT, 0, quad_strip); - glDrawArrays(GL_QUAD_STRIP, 0, totvert * 2); /* add + 2 for getting a complete soft rect. Now it skips top edge to allow transparent menus */ + glVertexPointer(2, GL_FLOAT, 0, triangle_strip); + glDrawArrays(GL_TRIANGLE_STRIP, 0, totvert * 2); /* add + 2 for getting a complete soft rect. Now it skips top edge to allow transparent menus */ } glDisableClientState(GL_VERTEX_ARRAY); @@ -2210,7 +2210,7 @@ void ui_hsvcircle_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f; float ang, radius_t; - ang = 2.0f * (float)M_PI * hsv[0] + 0.5f * (float)M_PI; + ang = 2.0f * (float)M_PI * hsv[0] + (float)M_PI_2; if ((but->flag & UI_BUT_COLOR_CUBIC) && (U.color_picker_type == USER_CP_CIRCLE_HSV)) radius_t = (1.0f - pow3f(1.0f - hsv[1])); @@ -3007,11 +3007,8 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat float height = rect->ymax - rect->ymin; /* find color luminance and change it slightly */ float bw = rgb_to_bw(col); - - if (bw > 0.5) - bw -= 0.5; - else - bw += 0.5; + + bw += (bw < 0.5f) ? 0.5f : -0.5f; glColor4f(bw, bw, bw, 1.0); glBegin(GL_TRIANGLES); @@ -3947,7 +3944,7 @@ void ui_draw_pie_center(uiBlock *block) int subd = 40; float angle = atan2f(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); + float range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? M_PI_2 : M_PI_4; glPushMatrix(); glTranslatef(cx, cy, 0.0f); diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index aa5b2570952..dab4b6a941c 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -682,6 +682,9 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo case TH_INFO_DEBUG_TEXT: cp = ts->info_debug_text; break; + case TH_V3D_CLIPPING_BORDER: + cp = ts->clipping_border_3d; + break; } } } @@ -951,6 +954,7 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tv3d.gradients.high_gradient, 58, 58, 58, 255); btheme->tv3d.gradients.show_grad = false; + rgba_char_args_set(btheme->tv3d.clipping_border_3d, 50, 50, 50, 255); /* space buttons */ /* to have something initialized */ btheme->tbuts = btheme->tv3d; @@ -1574,7 +1578,7 @@ void init_userdef_do_versions(void) U.tb_rightmouse = 5; } if (U.mixbufsize == 0) U.mixbufsize = 2048; - if (strcmp(U.tempdir, "/") == 0) { + if (STREQ(U.tempdir, "/")) { BKE_tempdir_system_init(U.tempdir); } if (U.autokey_mode == 0) { @@ -1907,39 +1911,39 @@ void init_userdef_do_versions(void) wmKeyMap *km; for (km = U.user_keymaps.first; km; km = km->next) { - if (strcmp(km->idname, "Armature_Sketch") == 0) + if (STREQ(km->idname, "Armature_Sketch")) strcpy(km->idname, "Armature Sketch"); - else if (strcmp(km->idname, "View3D") == 0) + else if (STREQ(km->idname, "View3D")) strcpy(km->idname, "3D View"); - else if (strcmp(km->idname, "View3D Generic") == 0) + else if (STREQ(km->idname, "View3D Generic")) strcpy(km->idname, "3D View Generic"); - else if (strcmp(km->idname, "EditMesh") == 0) + else if (STREQ(km->idname, "EditMesh")) strcpy(km->idname, "Mesh"); - else if (strcmp(km->idname, "TimeLine") == 0) + else if (STREQ(km->idname, "TimeLine")) strcpy(km->idname, "Timeline"); - else if (strcmp(km->idname, "UVEdit") == 0) + else if (STREQ(km->idname, "UVEdit")) strcpy(km->idname, "UV Editor"); - else if (strcmp(km->idname, "Animation_Channels") == 0) + else if (STREQ(km->idname, "Animation_Channels")) strcpy(km->idname, "Animation Channels"); - else if (strcmp(km->idname, "GraphEdit Keys") == 0) + else if (STREQ(km->idname, "GraphEdit Keys")) strcpy(km->idname, "Graph Editor"); - else if (strcmp(km->idname, "GraphEdit Generic") == 0) + else if (STREQ(km->idname, "GraphEdit Generic")) strcpy(km->idname, "Graph Editor Generic"); - else if (strcmp(km->idname, "Action_Keys") == 0) + else if (STREQ(km->idname, "Action_Keys")) strcpy(km->idname, "Dopesheet"); - else if (strcmp(km->idname, "NLA Data") == 0) + else if (STREQ(km->idname, "NLA Data")) strcpy(km->idname, "NLA Editor"); - else if (strcmp(km->idname, "Node Generic") == 0) + else if (STREQ(km->idname, "Node Generic")) strcpy(km->idname, "Node Editor"); - else if (strcmp(km->idname, "Logic Generic") == 0) + else if (STREQ(km->idname, "Logic Generic")) strcpy(km->idname, "Logic Editor"); - else if (strcmp(km->idname, "File") == 0) + else if (STREQ(km->idname, "File")) strcpy(km->idname, "File Browser"); - else if (strcmp(km->idname, "FileMain") == 0) + else if (STREQ(km->idname, "FileMain")) strcpy(km->idname, "File Browser Main"); - else if (strcmp(km->idname, "FileButtons") == 0) + else if (STREQ(km->idname, "FileButtons")) strcpy(km->idname, "File Browser Buttons"); - else if (strcmp(km->idname, "Buttons Generic") == 0) + else if (STREQ(km->idname, "Buttons Generic")) strcpy(km->idname, "Property Editor"); } } @@ -2572,6 +2576,25 @@ void init_userdef_do_versions(void) } } + if (U.versionfile < 273 || (U.versionfile == 273 && U.subversionfile < 5)) { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + unsigned char *cp = (unsigned char *)btheme->tv3d.clipping_border_3d; + int c; + copy_v4_v4_char((char *)cp, btheme->tv3d.back); + c = cp[0] - 8; + CLAMP(c, 0, 255); + cp[0] = c; + c = cp[1] - 8; + CLAMP(c, 0, 255); + cp[1] = c; + c = cp[2] - 8; + CLAMP(c, 0, 255); + cp[2] = c; + cp[3] = 255; + } + } + if (U.pixelsize == 0.0f) U.pixelsize = 1.0f; diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index de46d47e5a3..b4a120b2dea 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -371,7 +371,8 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_ float winx, winy; rctf *cur, *tot; - /* use mask as size of region that View2D resides in, as it takes into account scrollbars already */ + /* use mask as size of region that View2D resides in, as it takes into account + * scrollbars already - keep in sync with zoomx/zoomy in view_zoomstep_apply_ex! */ winx = (float)(BLI_rcti_size_x(&v2d->mask) + 1); winy = (float)(BLI_rcti_size_y(&v2d->mask) + 1); @@ -393,6 +394,7 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_ */ totwidth = BLI_rctf_size_x(tot); totheight = BLI_rctf_size_y(tot); + /* keep in sync with zoomx/zoomy in view_zoomstep_apply_ex! */ curwidth = width = BLI_rctf_size_x(cur); curheight = height = BLI_rctf_size_y(cur); @@ -1851,7 +1853,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v /* draw vertical steps */ if (dfac > 0.0f) { - BLF_rotation_default(M_PI / 2); + BLF_rotation_default(M_PI_2); BLF_enable_default(BLF_ROTATION); for (; fac < vert.ymax - 10; fac += dfac, val += grid->dy) { diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 297d8d0f258..88140d897ae 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -625,6 +625,7 @@ static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool { ARegion *ar = CTX_wm_region(C); View2D *v2d = &ar->v2d; + const rctf cur_old = v2d->cur; float dx, dy; /* calculate amount to move view by, ensuring symmetry so the @@ -651,17 +652,23 @@ static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool v2d->cur.xmax -= 2 * dx; } else { + + v2d->cur.xmin += dx; + v2d->cur.xmax -= dx; + if (use_mousepos && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) { - float mval_fac = (vzd->mx_2d - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur); - float mval_faci = 1.0f - mval_fac; - float ofs = (mval_fac * dx) - (mval_faci * dx); - - v2d->cur.xmin += ofs + dx; - v2d->cur.xmax += ofs - dx; - } - else { - v2d->cur.xmin += dx; - v2d->cur.xmax -= dx; + /* get zoom fac the same way as in ui_view2d_curRect_validate_resize - better keep in sync! */ + const float zoomx = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur); + + /* only move view to mouse if zoom fac is inside minzoom/maxzoom */ + if (IN_RANGE_INCL(zoomx, v2d->minzoom, v2d->maxzoom)) { + float mval_fac = (vzd->mx_2d - cur_old.xmin) / BLI_rctf_size_x(&cur_old); + float mval_faci = 1.0f - mval_fac; + float ofs = (mval_fac * dx) - (mval_faci * dx); + + v2d->cur.xmin += ofs; + v2d->cur.xmax += ofs; + } } } } @@ -676,17 +683,23 @@ static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool v2d->cur.ymax -= 2 * dy; } else { + + v2d->cur.ymin += dy; + v2d->cur.ymax -= dy; + if (use_mousepos && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) { - float mval_fac = (vzd->my_2d - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur); - float mval_faci = 1.0f - mval_fac; - float ofs = (mval_fac * dy) - (mval_faci * dy); - - v2d->cur.ymin += ofs + dy; - v2d->cur.ymax += ofs - dy; - } - else { - v2d->cur.ymin += dy; - v2d->cur.ymax -= dy; + /* get zoom fac the same way as in ui_view2d_curRect_validate_resize - better keep in sync! */ + const float zoomy = (float)(BLI_rcti_size_y(&v2d->mask) + 1) / BLI_rctf_size_y(&v2d->cur); + + /* only move view to mouse if zoom fac is inside minzoom/maxzoom */ + if (IN_RANGE_INCL(zoomy, v2d->minzoom, v2d->maxzoom)) { + float mval_fac = (vzd->my_2d - cur_old.ymin) / BLI_rctf_size_y(&cur_old); + float mval_faci = 1.0f - mval_fac; + float ofs = (mval_fac * dy) - (mval_faci * dy); + + v2d->cur.ymin += ofs; + v2d->cur.ymax += ofs; + } } } } diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index b288a02a3d1..6ce5e8a304b 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -32,6 +32,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BLI_math.h" #include "BLF_translation.h" @@ -71,7 +72,7 @@ static Object *make_prim_init(bContext *C, const char *idname, *was_editmode = true; } - *dia = ED_object_new_primitive_matrix(C, obedit, loc, rot, mat, false); + *dia = ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); return obedit; } @@ -421,7 +422,9 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op) { Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float mat[4][4]; + float loc[3], rot[3]; + float dia; bool enter_editmode; unsigned int layer; bool was_editmode; @@ -431,9 +434,7 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op) obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Suzanne"), &dia, mat, &was_editmode, loc, rot, layer); dia = RNA_float_get(op->ptr, "radius"); - mat[0][0] *= dia; - mat[1][1] *= dia; - mat[2][2] *= dia; + mul_mat3_m4_fl(mat, dia); em = BKE_editmesh_from_object(obedit); diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 0a78f299159..e8a5202029b 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1241,7 +1241,9 @@ static BMElem *bm_elem_from_knife_vert(KnifeVert *kfv, KnifeEdge **r_kfe) for (ref = kfv->edges.first; ref; ref = ref->next) { kfe = ref->ref; if (kfe->e) { - *r_kfe = kfe; + if (r_kfe) { + *r_kfe = kfe; + } break; } } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index a480b2051cc..16b74c3bddd 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -964,6 +964,40 @@ void MESH_OT_vert_connect(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (!EDBM_op_call_and_selectf( + em, op, + "faces.out", true, + "connect_verts_concave faces=%hf", + BM_ELEM_SELECT)) + { + return OPERATOR_CANCELLED; + } + + + EDBM_update_generic(em, true, true); + return OPERATOR_FINISHED; +} + +void MESH_OT_vert_connect_concave(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Split Concave Faces"; + ot->idname = "MESH_OT_vert_connect_concave"; + ot->description = "Make all faces convex"; + + /* api callbacks */ + ot->exec = edbm_vert_connect_concave_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op) { @@ -4541,7 +4575,7 @@ static int edbm_noise_exec(bContext *C, wmOperator *op) BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { float tin, dum; - externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL); + externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL, false); eve->co[2] += fac * tin; } } diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 152d055d239..30e9a85d083 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -57,6 +57,7 @@ #include "ED_mesh.h" #include "ED_object.h" +#include "ED_screen.h" #include "ED_uvedit.h" #include "ED_view3d.h" @@ -838,6 +839,71 @@ void MESH_OT_customdata_clear_skin(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* Clear custom loop normals */ +static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = ED_object_context(C); + Mesh *me = ob->data; + + if (!BKE_mesh_has_custom_loop_normals(me)) { + CustomData *data = GET_CD_DATA(me, ldata); + + if (me->edit_btmesh) { + BM_data_layer_add(me->edit_btmesh->bm, data, CD_CUSTOMLOOPNORMAL); + } + else { + CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop); + } + + DAG_id_tag_update(&me->id, 0); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, me); + + return OPERATOR_FINISHED; + } + return OPERATOR_CANCELLED; +} + +void MESH_OT_customdata_custom_splitnormals_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Custom Split Normals Data"; + ot->idname = "MESH_OT_customdata_custom_splitnormals_add"; + ot->description = "Add a custom split normals layer, if none exists yet"; + + /* api callbacks */ + ot->exec = mesh_customdata_custom_splitnormals_add_exec; + ot->poll = ED_operator_object_active_editable_mesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int mesh_customdata_custom_splitnormals_clear_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = ED_object_context(C); + Mesh *me = ob->data; + + if (BKE_mesh_has_custom_loop_normals(me)) { + return mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_CUSTOMLOOPNORMAL); + } + return OPERATOR_CANCELLED; +} + +void MESH_OT_customdata_custom_splitnormals_clear(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Clear Custom Split Normals Data"; + ot->idname = "MESH_OT_customdata_custom_splitnormals_clear"; + ot->description = "Remove the custom split normals layer, if it exists"; + + /* api callbacks */ + ot->exec = mesh_customdata_custom_splitnormals_clear_exec; + ot->poll = ED_operator_object_active_editable_mesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /************************** Add Geometry Layers *************************/ void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges, int calc_tessface) diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 6ba91097ec4..8f5ecaed524 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -175,6 +175,7 @@ void MESH_OT_normals_make_consistent(struct wmOperatorType *ot); void MESH_OT_vertices_smooth(struct wmOperatorType *ot); void MESH_OT_vertices_smooth_laplacian(struct wmOperatorType *ot); void MESH_OT_vert_connect(struct wmOperatorType *ot); +void MESH_OT_vert_connect_concave(struct wmOperatorType *ot); void MESH_OT_vert_connect_nonplanar(struct wmOperatorType *ot); void MESH_OT_edge_split(struct wmOperatorType *ot); void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot); @@ -237,6 +238,8 @@ void MESH_OT_vertex_color_remove(struct wmOperatorType *ot); /* no create_mask yet */ void MESH_OT_customdata_clear_mask(struct wmOperatorType *ot); void MESH_OT_customdata_clear_skin(struct wmOperatorType *ot); +void MESH_OT_customdata_custom_splitnormals_add(struct wmOperatorType *ot); +void MESH_OT_customdata_custom_splitnormals_clear(struct wmOperatorType *ot); void MESH_OT_drop_named_image(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index e7dc5a69d53..59d0de87de6 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -153,6 +153,8 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_vertex_color_remove); WM_operatortype_append(MESH_OT_customdata_clear_mask); WM_operatortype_append(MESH_OT_customdata_clear_skin); + WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_add); + WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_clear); WM_operatortype_append(MESH_OT_drop_named_image); WM_operatortype_append(MESH_OT_edgering_select); @@ -161,6 +163,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_solidify); WM_operatortype_append(MESH_OT_select_nth); WM_operatortype_append(MESH_OT_vert_connect); + WM_operatortype_append(MESH_OT_vert_connect_concave); WM_operatortype_append(MESH_OT_vert_connect_nonplanar); WM_operatortype_append(MESH_OT_knife_tool); WM_operatortype_append(MESH_OT_knife_project); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 19040062fda..dee216d9c73 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -329,7 +329,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) if (odg) { /* Search for a match in the new object, and set new index */ for (dg = ob->defbase.first, index = 0; dg; dg = dg->next, index++) { - if (!strcmp(dg->name, odg->name)) { + if (STREQ(dg->name, odg->name)) { dvert[i].dw[j].def_nr = index; break; } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index c3edd63b2d4..1180c082783 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -162,14 +162,13 @@ void ED_object_rotation_from_view(bContext *C, float rot[3], const char align_ax BLI_assert(align_axis >= 'X' && align_axis <= 'Z'); if (rv3d) { - const float pi_2 = (float)M_PI / 2.0f; float quat[4]; switch (align_axis) { case 'X': { float quat_y[4]; - axis_angle_to_quat(quat_y, rv3d->viewinv[1], -pi_2); + axis_angle_to_quat(quat_y, rv3d->viewinv[1], -M_PI_2); mul_qt_qtqt(quat, rv3d->viewquat, quat_y); quat[0] = -quat[0]; @@ -182,7 +181,7 @@ void ED_object_rotation_from_view(bContext *C, float rot[3], const char align_ax quat[0] = -quat[0]; quat_to_eul(rot, quat); - rot[0] -= pi_2; + rot[0] -= (float)M_PI_2; break; } case 'Z': @@ -219,9 +218,9 @@ void ED_object_base_init_transform(bContext *C, Base *base, const float loc[3], /* Uses context to figure out transform for primitive. * Returns standard diameter. */ -float ED_object_new_primitive_matrix(bContext *C, Object *obedit, - const float loc[3], const float rot[3], float primmat[4][4], - bool apply_diameter) +float ED_object_new_primitive_matrix( + bContext *C, Object *obedit, + const float loc[3], const float rot[3], float primmat[4][4]) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -246,13 +245,6 @@ float ED_object_new_primitive_matrix(bContext *C, Object *obedit, { const float dia = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) : ED_scene_grid_scale(scene, NULL); - - if (apply_diameter) { - primmat[0][0] *= dia; - primmat[1][1] *= dia; - primmat[2][2] *= dia; - } - return dia; } @@ -516,7 +508,7 @@ static int effector_add_exec(bContext *C, wmOperator *op) 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); + ED_object_new_primitive_matrix(C, ob, loc, rot, mat); 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); @@ -639,7 +631,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op) DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); } - ED_object_new_primitive_matrix(C, obedit, loc, rot, mat, false); + ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); dia = RNA_float_get(op->ptr, "radius"); add_metaball_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type")); diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 83eeedfef52..fca527f8931 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -916,7 +916,7 @@ cage_cleanup: BakeData *bake = &scene->r.bake; char name[FILE_MAX]; - BKE_makepicstring_from_type(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false); + BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false); if (is_automatic_name) { BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_"); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 2596ea0a064..8f793f7f7f9 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -471,7 +471,7 @@ static void test_constraints(Object *owner, bPoseChannel *pchan) /* TODO: clear subtarget? */ curcon->flag |= CONSTRAINT_DISABLE; } - else if (strcmp(pchan->name, ct->subtarget) == 0) { + else if (STREQ(pchan->name, ct->subtarget)) { /* cannot target self */ ct->subtarget[0] = '\0'; curcon->flag |= CONSTRAINT_DISABLE; diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index f6cf0312e2d..c57cae41bf4 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -42,6 +42,7 @@ #include "BKE_context.h" #include "BKE_data_transfer.h" +#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_remap.h" @@ -82,6 +83,7 @@ static EnumPropertyItem DT_layer_items[] = { {DT_TYPE_BWEIGHT_EDGE, "BEVEL_WEIGHT_EDGE", 0, "Bevel Weight", "Transfer bevel weights"}, {DT_TYPE_FREESTYLE_EDGE, "FREESTYLE_EDGE", 0, "Freestyle Mark", "Transfer Freestyle edge mark"}, {0, "", 0, "Face Corner Data", ""}, + {DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"}, {DT_TYPE_VCOL, "VCOL", 0, "VCol", "Vertex (face corners) colors"}, {DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"}, {0, "", 0, "Face Data", ""}, @@ -393,6 +395,8 @@ static int data_transfer_exec(bContext *C, wmOperator *op) } } + DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); + if (reverse_transfer) { SWAP(Object *, ob_src, ob_dst); } @@ -400,6 +404,8 @@ static int data_transfer_exec(bContext *C, wmOperator *op) BLI_freelistN(&ctx_objects); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + #if 0 /* TODO */ /* Note: issue with that is that if canceled, operator cannot be redone... Nasty in our case. */ return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED; @@ -592,6 +598,8 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op) BKE_object_data_transfer_layout(scene, ob_src, ob_dst, dtmd->data_types, use_delete, dtmd->layers_select_src, dtmd->layers_select_dst); + + DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); } else { Object *ob_src = ob_act; @@ -621,11 +629,15 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op) BKE_object_data_transfer_layout(scene, ob_src, ob_dst, data_type, use_delete, layers_select_src, layers_select_dst); } + + DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); } BLI_freelistN(&ctx_objects); } + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 0a053d771df..64004de1087 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -42,6 +42,8 @@ #include "BLI_utildefines.h" #include "BLI_ghash.h" +#include "BLF_translation.h" + #include "DNA_armature_types.h" #include "DNA_curve_types.h" #include "DNA_group_types.h" @@ -1347,7 +1349,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op) ID *data; Curve *cu; Nurb *nu; - int clear = (strcmp(op->idname, "OBJECT_OT_shade_flat") == 0); + int clear = (STREQ(op->idname, "OBJECT_OT_shade_flat")); bool done = false, linked_data = false; CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects) @@ -1701,7 +1703,7 @@ static int game_property_new_exec(bContext *C, wmOperator *op) BLI_strncpy(prop->name, name, sizeof(prop->name)); } - BKE_bproperty_unique(NULL, prop, 0); // make_unique_prop_names(prop->name); + BLI_uniquename(&ob->prop, prop, DATA_("Property"), '.', offsetof(bProperty, name), sizeof(prop->name)); WM_event_add_notifier(C, NC_LOGIC, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index 20e2e22cdf8..3c43f2729bd 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -61,47 +61,6 @@ /********************* 3d view operators ***********************/ -static bool group_link_early_exit_check(Group *group, Object *object) -{ - GroupObject *group_object; - - for (group_object = group->gobject.first; group_object; group_object = group_object->next) { - if (group_object->ob == object) { - return true; - } - } - - return false; -} - -static bool check_object_instances_group_recursive(Object *object, Group *group) -{ - if (object->dup_group) { - Group *dup_group = object->dup_group; - if ((dup_group->id.flag & LIB_DOIT) == 0) { - /* Cycle already exists in groups, let's prevent further crappyness */ - return true; - } - /* flag the object to identify cyclic dependencies in further dupli groups */ - dup_group->id.flag &= ~LIB_DOIT; - - if (dup_group == group) - return true; - else { - GroupObject *gob; - for (gob = dup_group->gobject.first; gob; gob = gob->next) { - if (check_object_instances_group_recursive(gob->ob, group)) - return true; - } - } - - /* un-flag the object, it's allowed to have the same group multiple times in parallel */ - dup_group->id.flag |= LIB_DOIT; - } - - return false; -} - /* can be called with C == NULL */ static EnumPropertyItem *group_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { @@ -185,15 +144,12 @@ static int objects_add_active_exec(bContext *C, wmOperator *op) if (!BKE_group_object_exists(group, ob)) continue; - /* for recursive check */ - BKE_main_id_tag_listbase(&bmain->group, true); - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) { - if (group_link_early_exit_check(group, base->object)) + if (BKE_group_object_exists(group, base->object)) continue; - if (!check_object_instances_group_recursive(base->object, group)) { + if (!BKE_group_object_cyclic_check(bmain, base->object, group)) { BKE_group_object_add(group, base->object, scene, base); updated = true; } @@ -486,7 +442,7 @@ static int group_link_exec(bContext *C, wmOperator *op) * we could sckip all the dependency check and just consider * operator is finished. */ - if (group_link_early_exit_check(group, ob)) { + if (BKE_group_object_exists(group, ob)) { return OPERATOR_FINISHED; } @@ -495,8 +451,7 @@ static int group_link_exec(bContext *C, wmOperator *op) * It is also bad idea to add object to group which is in group which * contains our current object. */ - BKE_main_id_tag_listbase(&bmain->group, true); - if (check_object_instances_group_recursive(ob, group)) { + if (BKE_group_object_cyclic_check(bmain, ob, group)) { BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 9f9a647c9f1..1d764ced524 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -503,6 +503,15 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob unit_m4(pose_mat); + invert_m4_m4(obedit->imat, obedit->obmat); + if (mode == OBJECT_ADDHOOK_NEWOB) { + /* pass */ + } + else { + /* may overwrite with pose-bone location, below */ + mul_v3_m4v3(cent, obedit->imat, ob->obmat[3]); + } + if (mode == OBJECT_ADDHOOK_SELOB_BONE) { bArmature *arm = ob->data; BLI_assert(ob->type == OB_ARMATURE); @@ -514,6 +523,8 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob pchan_act = BKE_pose_channel_active(ob); if (LIKELY(pchan_act)) { invert_m4_m4(pose_mat, pchan_act->pose_mat); + mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]); + mul_v3_m4v3(cent, obedit->imat, cent); } } else { @@ -521,6 +532,9 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob } } + copy_v3_v3(hmd->cent, cent); + + /* matrix calculus */ /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */ /* (parentinv ) */ diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 5a479af83b5..bed85444101 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -440,9 +440,9 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene * for (a = 0; a < totpart; a++) { key = cache[a]; - if (key->steps > 0) { - totvert += key->steps + 1; - totedge += key->steps; + if (key->segments > 0) { + totvert += key->segments + 1; + totedge += key->segments; } } @@ -450,9 +450,9 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene * for (a = 0; a < totchild; a++) { key = cache[a]; - if (key->steps > 0) { - totvert += key->steps + 1; - totedge += key->steps; + if (key->segments > 0) { + totvert += key->segments + 1; + totedge += key->segments; } } @@ -476,7 +476,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene * cache = psys->pathcache; for (a = 0; a < totpart; a++) { key = cache[a]; - kmax = key->steps; + kmax = key->segments; for (k = 0; k <= kmax; k++, key++, cvert++, mvert++) { copy_v3_v3(mvert->co, key->co); if (k) { @@ -495,7 +495,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene * cache = psys->childcache; for (a = 0; a < totchild; a++) { key = cache[a]; - kmax = key->steps; + kmax = key->segments; for (k = 0; k <= kmax; k++, key++, cvert++, mvert++) { copy_v3_v3(mvert->co, key->co); if (k) { diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 67b5c8061cd..430994aed60 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -973,7 +973,7 @@ void OBJECT_OT_parent_set(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", ""); + ot->prop = RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", ""); RNA_def_boolean(ot->srna, "xmirror", false, "X Mirror", "Apply weights symmetrically along X axis, for Envelope/Automatic vertex groups creation"); RNA_def_boolean(ot->srna, "keep_transform", false, "Keep Transform", @@ -2344,10 +2344,8 @@ void OBJECT_OT_make_local(wmOperatorType *ot) } enum { - /* Be careful with those values, they are used as bitflags in some cases, in others as bool... - * See single_object_users, single_obdata_users, single_object_action_users, etc.< */ - MAKE_SINGLE_USER_ALL = 0, - MAKE_SINGLE_USER_SELECTED = SELECT, + MAKE_SINGLE_USER_ALL = 1, + MAKE_SINGLE_USER_SELECTED = 2, }; static int make_single_user_exec(bContext *C, wmOperator *op) @@ -2355,7 +2353,7 @@ static int make_single_user_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); /* ok if this is NULL */ - const int flag = RNA_enum_get(op->ptr, "type"); + const int flag = (RNA_enum_get(op->ptr, "type") == MAKE_SINGLE_USER_SELECTED) ? SELECT : 0; const bool copy_groups = false; bool update_deps = false; @@ -2421,7 +2419,7 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", type_items, SELECT, "Type", ""); + ot->prop = RNA_def_enum(ot->srna, "type", type_items, MAKE_SINGLE_USER_SELECTED, "Type", ""); RNA_def_boolean(ot->srna, "object", 0, "Object", "Make single user objects"); RNA_def_boolean(ot->srna, "obdata", 0, "Object Data", "Make single user object data"); diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index e70281c502b..f885cbbb24f 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -1646,7 +1646,7 @@ static void vgroup_blend_subset(Object *ob, const bool *vgroup_validmap, const i BMesh *bm = em ? em->bm : NULL; Mesh *me = em ? NULL : ob->data; - MeshElemMap *emap ; + MeshElemMap *emap; int *emap_mem; BLI_SMALLSTACK_DECLARE(dv_stack, MDeformVert *); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 5e30ca4ed2f..fd32aad852d 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -61,7 +61,7 @@ #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_report.h" - +#include "BKE_bvhutils.h" #include "BKE_pointcache.h" #include "BIF_gl.h" @@ -85,8 +85,10 @@ static void PE_create_particle_edit_from_psys(Scene *scene, Object *ob, ParticleSystem *psys); static void PE_create_particle_edit_from_cache(Scene *scene, Object *ob, PointCache *cache, ListBase *mem_cache); -static void PTCacheUndo_clear(PTCacheEdit *edit); -static void recalc_emitter_field(Object *ob, ParticleSystem *psys); +void PTCacheUndo_clear(PTCacheEdit *edit); +void recalc_lengths(PTCacheEdit *edit); +void recalc_emitter_field(Object *ob, ParticleSystem *psys); +void update_world_cos(Object *ob, PTCacheEdit *edit); #define KEY_K PTCacheEditKey *key; int k #define POINT_P PTCacheEditPoint *point; int p @@ -362,6 +364,7 @@ typedef struct PEData { Object *ob; DerivedMesh *dm; PTCacheEdit *edit; + BVHTreeFromMesh shape_bvh; const int *mval; rcti *rect; @@ -418,6 +421,25 @@ static void PE_set_view3d_data(bContext *C, PEData *data) } } +static void PE_create_shape_tree(PEData *data, Object *shapeob) +{ + DerivedMesh *dm = shapeob->derivedFinal; + + memset(&data->shape_bvh, 0, sizeof(data->shape_bvh)); + + if (!dm) { + return; + } + + DM_ensure_tessface(dm); + bvhtree_from_mesh_faces(&data->shape_bvh, dm, 0.0f, 4, 8); +} + +static void PE_free_shape_tree(PEData *data) +{ + free_bvhtree_from_mesh(&data->shape_bvh); +} + /*************************** selection utilities *******************************/ static bool key_test_depth(PEData *data, const float co[3], const int screen_co[2]) @@ -1062,7 +1084,7 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit) } } /* set current distances to be kept between neighbouting keys */ -static void recalc_lengths(PTCacheEdit *edit) +void recalc_lengths(PTCacheEdit *edit) { POINT_P; KEY_K; @@ -1078,7 +1100,7 @@ static void recalc_lengths(PTCacheEdit *edit) } /* calculate a tree for finding nearest emitter's vertice */ -static void recalc_emitter_field(Object *ob, ParticleSystem *psys) +void recalc_emitter_field(Object *ob, ParticleSystem *psys) { DerivedMesh *dm=psys_get_modifier(ob, psys)->dm; PTCacheEdit *edit= psys->edit; @@ -1166,7 +1188,7 @@ static void PE_update_selection(Scene *scene, Object *ob, int useflag) point->flag &= ~PEP_EDIT_RECALC; } -static void update_world_cos(Object *ob, PTCacheEdit *edit) +void update_world_cos(Object *ob, PTCacheEdit *edit) { ParticleSystem *psys = edit->psys; ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys); @@ -3236,7 +3258,7 @@ static void brush_puff(PEData *data, int point_index) static void BKE_brush_weight_get(PEData *data, float UNUSED(mat[4][4]), float UNUSED(imat[4][4]), int point_index, int key_index, PTCacheEditKey *UNUSED(key)) { - /* roots have full weight allways */ + /* roots have full weight always */ if (key_index) { PTCacheEdit *edit = data->edit; ParticleSystem *psys = edit->psys; @@ -4039,6 +4061,180 @@ void PARTICLE_OT_brush_edit(wmOperatorType *ot) RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); } +/*********************** cut shape ***************************/ + +static int shape_cut_poll(bContext *C) +{ + if (PE_hair_poll(C)) { + Scene *scene= CTX_data_scene(C); + ParticleEditSettings *pset= PE_settings(scene); + + if (pset->shape_object) + return true; + } + + return false; +} + +typedef struct PointInsideBVH { + BVHTreeFromMesh bvhdata; + int num_hits; +} PointInsideBVH; + +static void point_inside_bvh_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + PointInsideBVH *data = userdata; + + data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit); + + if (hit->index != -1) + ++data->num_hits; +} + +/* true if the point is inside the shape mesh */ +static bool shape_cut_test_point(PEData *data, ParticleCacheKey *key) +{ + BVHTreeFromMesh *shape_bvh = &data->shape_bvh; + const float dir[3] = {1.0f, 0.0f, 0.0f}; + PointInsideBVH userdata; + + userdata.bvhdata = data->shape_bvh; + userdata.num_hits = 0; + + BLI_bvhtree_ray_cast_all(shape_bvh->tree, key->co, dir, 0.0f, point_inside_bvh_cb, &userdata); + + /* for any point inside a watertight mesh the number of hits is uneven */ + return (userdata.num_hits % 2) == 1; +} + +static void shape_cut(PEData *data, int pa_index) +{ + PTCacheEdit *edit = data->edit; + Object *ob = data->ob; + ParticleEditSettings *pset = PE_settings(data->scene); + ParticleCacheKey *key; + + bool cut; + float cut_time = 1.0; + int k, totkeys = 1 << pset->draw_step; + + /* don't cut hidden */ + if (edit->points[pa_index].flag & PEP_HIDE) + return; + + cut = false; + + /* check if root is inside the cut shape */ + key = edit->pathcache[pa_index]; + if (!shape_cut_test_point(data, key)) { + cut_time = -1.0f; + cut = true; + } + else { + for (k = 0; k < totkeys; k++, key++) { + BVHTreeRayHit hit; + float dir[3]; + float len; + + sub_v3_v3v3(dir, (key+1)->co, key->co); + len = normalize_v3(dir); + + memset(&hit, 0, sizeof(hit)); + hit.index = -1; + hit.dist = len; + BLI_bvhtree_ray_cast(data->shape_bvh.tree, key->co, dir, 0.0f, &hit, data->shape_bvh.raycast_callback, &data->shape_bvh); + if (hit.index >= 0) { + if (hit.dist < len) { + cut_time = (hit.dist / len + (float)k) / (float)totkeys; + cut = true; + break; + } + } + } + } + + if (cut) { + if (cut_time < 0.0f) { + edit->points[pa_index].flag |= PEP_TAG; + } + else { + rekey_particle_to_time(data->scene, ob, pa_index, cut_time); + edit->points[pa_index].flag |= PEP_EDIT_RECALC; + } + } +} + +static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + ParticleEditSettings *pset = PE_settings(scene); + PTCacheEdit *edit = PE_get_current(scene, ob); + Object *shapeob = pset->shape_object; + int selected = count_selected_keys(scene, edit); + int lock_root = pset->flag & PE_LOCK_FIRST; + + if (!PE_start_edit(edit)) + return OPERATOR_CANCELLED; + + /* disable locking temporatily for disconnected hair */ + if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) + pset->flag &= ~PE_LOCK_FIRST; + + if (edit->psys && edit->pathcache) { + PEData data; + int removed; + + PE_set_data(C, &data); + PE_create_shape_tree(&data, shapeob); + + if (selected) + foreach_selected_point(&data, shape_cut); + else + foreach_point(&data, shape_cut); + + removed = remove_tagged_particles(ob, edit->psys, pe_x_mirror(ob)); + recalc_lengths(edit); + + if (removed) { + update_world_cos(ob, edit); + psys_free_path_cache(NULL, edit); + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + else + PE_update_object(scene, ob, 1); + + if (edit->psys) { + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); + } + else { + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); + } + + PE_free_shape_tree(&data); + } + + pset->flag |= lock_root; + + return OPERATOR_FINISHED; +} + +void PARTICLE_OT_shape_cut(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Shape Cut"; + ot->idname = "PARTICLE_OT_shape_cut"; + ot->description = "Cut hair to conform to the set shape object"; + + /* api callbacks */ + ot->exec = shape_cut_exec; + ot->poll = shape_cut_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; +} + /*********************** undo ***************************/ static void free_PTCacheUndo(PTCacheUndo *undo) @@ -4266,7 +4462,7 @@ int PE_undo_valid(Scene *scene) return 0; } -static void PTCacheUndo_clear(PTCacheEdit *edit) +void PTCacheUndo_clear(PTCacheEdit *edit) { PTCacheUndo *undo; diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 5a61f77e5a8..dba6d6f5085 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -40,18 +40,21 @@ #include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_utildefines.h" +#include "BLI_string.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_cdderivedmesh.h" #include "BKE_global.h" +#include "BKE_library.h" #include "BKE_main.h" +#include "BKE_modifier.h" +#include "BKE_object.h" #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_report.h" - #include "RNA_access.h" #include "RNA_define.h" @@ -62,8 +65,37 @@ #include "ED_screen.h" #include "ED_object.h" +#include "UI_resources.h" + #include "physics_intern.h" +extern void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys); +extern void PTCacheUndo_clear(PTCacheEdit *edit); +extern void recalc_lengths(PTCacheEdit *edit); +extern void recalc_emitter_field(Object *ob, ParticleSystem *psys); +extern void update_world_cos(Object *ob, PTCacheEdit *edit); + +#define KEY_K PTCacheEditKey *key; int k +#define POINT_P PTCacheEditPoint *point; int p +#define LOOP_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) +#if 0 +#define LOOP_VISIBLE_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!(point->flag & PEP_HIDE)) +#define LOOP_SELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point_is_selected(point)) +#define LOOP_UNSELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!point_is_selected(point)) +#define LOOP_EDITED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_EDIT_RECALC) +#define LOOP_TAGGED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_TAG) +#endif +#define LOOP_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) +#if 0 +#define LOOP_VISIBLE_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (!(key->flag & PEK_HIDE)) +#define LOOP_SELECTED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if ((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE)) +#define LOOP_TAGGED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (key->flag & PEK_TAG) + +#define KEY_WCO (key->flag & PEK_USE_WCO ? key->world_co : key->co) +#endif + +static float I[4][4] = {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}; + /********************** particle system slot operators *********************/ static int particle_system_add_exec(bContext *C, wmOperator *UNUSED(op)) @@ -623,38 +655,50 @@ void PARTICLE_OT_disconnect_hair(wmOperatorType *ot) RNA_def_boolean(ot->srna, "all", 0, "All hair", "Disconnect all hair systems from the emitter mesh"); } -static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) +/* from/to_world_space : whether from/to particles are in world or hair space + * from/to_mat : additional transform for from/to particles (e.g. for using object space copying) + */ +static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys, + Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit, + float from_mat[4][4], float to_mat[4][4], bool from_global, bool to_global) { - ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - ParticleData *pa; - PTCacheEdit *edit; - PTCacheEditPoint *point; - PTCacheEditKey *ekey = NULL; - HairKey *key; + ParticleSystemModifierData *target_psmd = psys_get_modifier(target_ob, target_psys); + ParticleData *pa, *tpa; + PTCacheEditPoint *edit_point; + PTCacheEditKey *ekey; BVHTreeFromMesh bvhtree= {NULL}; - BVHTreeNearest nearest; MFace *mface = NULL, *mf; MEdge *medge = NULL, *me; MVert *mvert; - DerivedMesh *dm = NULL; + DerivedMesh *dm, *target_dm; int numverts; int i, k; - float hairmat[4][4], imat[4][4]; - float v[4][3], vec[3]; + float from_ob_imat[4][4], to_ob_imat[4][4]; + float from_imat[4][4], to_imat[4][4]; - if (!psys || !psys->part || psys->part->type != PART_HAIR || !psmd->dm) + if (!target_psmd->dm) + return false; + if (!psys->part || psys->part->type != PART_HAIR) return false; + if (!target_psys->part || target_psys->part->type != PART_HAIR) + return false; + + edit_point = target_edit ? target_edit->points : NULL; - edit= psys->edit; - point= edit ? edit->points : NULL; + invert_m4_m4(from_ob_imat, ob->obmat); + invert_m4_m4(to_ob_imat, target_ob->obmat); + invert_m4_m4(from_imat, from_mat); + invert_m4_m4(to_imat, to_mat); - if (psmd->dm->deformedOnly) { - /* we don't want to mess up psmd->dm when converting to global coordinates below */ - dm = psmd->dm; + if (target_psmd->dm->deformedOnly) { + /* we don't want to mess up target_psmd->dm when converting to global coordinates below */ + dm = target_psmd->dm; } else { - dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); + /* warning: this rebuilds target_psmd->dm! */ + dm = mesh_get_derived_deform(scene, target_ob, CD_MASK_BAREMESH); } + target_dm = target_psmd->dm; /* don't modify the original vertices */ dm = CDDM_copy(dm); @@ -662,12 +706,11 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) DM_ensure_tessface(dm); numverts = dm->getNumVerts(dm); - mvert = dm->getVertArray(dm); /* convert to global coordinates */ for (i=0; i<numverts; i++) - mul_m4_v3(ob->obmat, mvert[i].co); + mul_m4_v3(to_mat, mvert[i].co); if (dm->getNumTessFaces(dm) != 0) { mface = dm->getTessFaceArray(dm); @@ -682,13 +725,23 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) return false; } - for (i=0, pa= psys->particles; i<psys->totpart; i++, pa++) { - key = pa->hair; + for (i = 0, tpa = target_psys->particles, pa = psys->particles; + i < target_psys->totpart; + i++, tpa++, pa++) { + + float from_co[3]; + BVHTreeNearest nearest; + + if (from_global) + mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].co); + else + mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].world_co); + mul_m4_v3(from_mat, from_co); nearest.index = -1; nearest.dist_sq = FLT_MAX; - BLI_bvhtree_find_nearest(bvhtree.tree, key->co, &nearest, bvhtree.nearest_callback, &bvhtree); + BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree); if (nearest.index == -1) { if (G.debug & G_DEBUG) @@ -697,6 +750,8 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) } if (mface) { + float v[4][3]; + mf = &mface[nearest.index]; copy_v3_v3(v[0], mvert[mf->v1].co); @@ -704,44 +759,80 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) copy_v3_v3(v[2], mvert[mf->v3].co); if (mf->v4) { copy_v3_v3(v[3], mvert[mf->v4].co); - interp_weights_poly_v3(pa->fuv, v, 4, nearest.co); + interp_weights_poly_v3(tpa->fuv, v, 4, nearest.co); } else - interp_weights_poly_v3(pa->fuv, v, 3, nearest.co); + interp_weights_poly_v3(tpa->fuv, v, 3, nearest.co); + tpa->foffset = 0.0f; - pa->num = nearest.index; - pa->num_dmcache = psys_particle_dm_face_lookup(ob, psmd->dm, pa->num, pa->fuv, NULL); + tpa->num = nearest.index; + tpa->num_dmcache = psys_particle_dm_face_lookup(target_ob, target_dm, tpa->num, tpa->fuv, NULL); } else { me = &medge[nearest.index]; - pa->fuv[1] = line_point_factor_v3(nearest.co, - mvert[me->v2].co, - mvert[me->v2].co); - pa->fuv[0] = 1.0f - pa->fuv[1]; - pa->fuv[2] = pa->fuv[3] = 0.0f; + tpa->fuv[1] = line_point_factor_v3(nearest.co, + mvert[me->v1].co, + mvert[me->v2].co); + tpa->fuv[0] = 1.0f - tpa->fuv[1]; + tpa->fuv[2] = tpa->fuv[3] = 0.0f; + tpa->foffset = 0.0f; - pa->num = nearest.index; - pa->num_dmcache = -1; + tpa->num = nearest.index; + tpa->num_dmcache = -1; } - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); - invert_m4_m4(imat, hairmat); - - sub_v3_v3v3(vec, nearest.co, key->co); - - if (point) { - ekey = point->keys; - point++; - } - - for (k=0, key=pa->hair; k<pa->totkey; k++, key++) { - add_v3_v3(key->co, vec); - mul_m4_v3(imat, key->co); - - if (ekey) { - ekey->flag |= PEK_USE_WCO; - ekey++; + /* translate hair keys */ + { + HairKey *key, *tkey; + float hairmat[4][4], imat[4][4]; + float offset[3]; + + if (to_global) + copy_m4_m4(imat, target_ob->obmat); + else { + /* note: using target_dm here, which is in target_ob object space and has full modifiers */ + psys_mat_hair_to_object(target_ob, target_dm, target_psys->part->from, tpa, hairmat); + invert_m4_m4(imat, hairmat); + } + mul_m4_m4m4(imat, imat, to_imat); + + /* offset in world space */ + sub_v3_v3v3(offset, nearest.co, from_co); + + if (edit_point) { + for (k=0, key=pa->hair, tkey=tpa->hair, ekey = edit_point->keys; k<tpa->totkey; k++, key++, tkey++, ekey++) { + float co_orig[3]; + + if (from_global) + mul_v3_m4v3(co_orig, from_ob_imat, key->co); + else + mul_v3_m4v3(co_orig, from_ob_imat, key->world_co); + mul_m4_v3(from_mat, co_orig); + + add_v3_v3v3(tkey->co, co_orig, offset); + + mul_m4_v3(imat, tkey->co); + + ekey->flag |= PEK_USE_WCO; + } + + edit_point++; + } + else { + for (k=0, key=pa->hair, tkey=tpa->hair; k<tpa->totkey; k++, key++, tkey++) { + float co_orig[3]; + + if (from_global) + mul_v3_m4v3(co_orig, from_ob_imat, key->co); + else + mul_v3_m4v3(co_orig, from_ob_imat, key->world_co); + mul_m4_v3(from_mat, co_orig); + + add_v3_v3v3(tkey->co, co_orig, offset); + + mul_m4_v3(imat, tkey->co); + } } } } @@ -749,15 +840,26 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) free_bvhtree_from_mesh(&bvhtree); dm->release(dm); - psys_free_path_cache(psys, psys->edit); + psys_free_path_cache(target_psys, target_edit); - psys->flag &= ~PSYS_GLOBAL_HAIR; - - PE_update_object(scene, ob, 0); + PE_update_object(scene, target_ob, 0); return true; } +static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) +{ + bool ok; + + if (!psys) + return false; + + ok = remap_hair_emitter(scene, ob, psys, ob, psys, psys->edit, ob->obmat, ob->obmat, psys->flag & PSYS_GLOBAL_HAIR, false); + psys->flag &= ~PSYS_GLOBAL_HAIR; + + return ok; +} + static int connect_hair_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); @@ -805,3 +907,284 @@ void PARTICLE_OT_connect_hair(wmOperatorType *ot) RNA_def_boolean(ot->srna, "all", 0, "All hair", "Connect all hair systems to the emitter mesh"); } +/************************ particle system copy operator *********************/ + +typedef enum eCopyParticlesSpace { + PAR_COPY_SPACE_OBJECT = 0, + PAR_COPY_SPACE_WORLD = 1, +} eCopyParticlesSpace; + +static void copy_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystem *psys_from) +{ + PTCacheEdit *edit_from = psys_from->edit, *edit; + ParticleData *pa; + KEY_K; + POINT_P; + + if (!edit_from) + return; + + edit = MEM_dupallocN(edit_from); + edit->psys = psys; + psys->edit = edit; + + edit->pathcache = NULL; + BLI_listbase_clear(&edit->pathcachebufs); + + edit->emitter_field = NULL; + edit->emitter_cosnos = NULL; + + BLI_listbase_clear(&edit->undo); + edit->curundo = NULL; + + edit->points = MEM_dupallocN(edit_from->points); + pa = psys->particles; + LOOP_POINTS { + HairKey *hkey = pa->hair; + + point->keys= MEM_dupallocN(point->keys); + LOOP_KEYS { + key->co = hkey->co; + key->time = &hkey->time; + key->flag = hkey->editflag; + if (!(psys->flag & PSYS_GLOBAL_HAIR)) { + key->flag |= PEK_USE_WCO; + hkey->editflag |= PEK_USE_WCO; + } + + hkey++; + } + + pa++; + } + update_world_cos(ob, edit); + + UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col); + UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col); + + recalc_lengths(edit); + recalc_emitter_field(ob, psys); + PE_update_object(scene, ob, true); + + PTCacheUndo_clear(edit); + PE_undo_push(scene, "Original"); +} + +static void remove_particle_systems_from_object(Object *ob_to) +{ + ModifierData *md, *md_next; + + if (ob_to->type != OB_MESH) + return; + if (!ob_to->data || ((ID *)ob_to->data)->lib) + return; + + for (md = ob_to->modifiers.first; md; md = md_next) { + md_next = md->next; + + /* remove all particle system modifiers as well, + * these need to sync to the particle system list + */ + if (ELEM(md->type, eModifierType_ParticleSystem, eModifierType_DynamicPaint, eModifierType_Smoke)) { + BLI_remlink(&ob_to->modifiers, md); + modifier_free(md); + } + } + + BKE_object_free_particlesystems(ob_to); +} + +/* single_psys_from is optional, if NULL all psys of ob_from are copied */ +static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, ParticleSystem *single_psys_from, Object *ob_to, int space) +{ + ModifierData *md; + ParticleSystem *psys_start, *psys, *psys_from; + ParticleSystem **tmp_psys; + DerivedMesh *final_dm; + CustomDataMask cdmask; + int i, totpsys; + + if (ob_to->type != OB_MESH) + return false; + if (!ob_to->data || ((ID *)ob_to->data)->lib) + return false; + + /* For remapping we need a valid DM. + * Because the modifiers are appended at the end it's safe to use + * the final DM of the object without particles. + * However, when evaluating the DM all the particle modifiers must be valid, + * i.e. have the psys assigned already. + * To break this hen/egg problem we create all psys separately first (to collect required customdata masks), + * then create the DM, then add them to the object and make the psys modifiers ... + */ + #define PSYS_FROM_FIRST (single_psys_from ? single_psys_from : ob_from->particlesystem.first) + #define PSYS_FROM_NEXT(cur) (single_psys_from ? NULL : (cur)->next) + totpsys = single_psys_from ? 1 : BLI_listbase_count(&ob_from->particlesystem); + + tmp_psys = MEM_mallocN(sizeof(ParticleSystem*) * totpsys, "temporary particle system array"); + + cdmask = 0; + for (psys_from = PSYS_FROM_FIRST, i = 0; + psys_from; + psys_from = PSYS_FROM_NEXT(psys_from), ++i) { + + psys = BKE_object_copy_particlesystem(psys_from); + tmp_psys[i] = psys; + + if (psys_start == NULL) + psys_start = psys; + + cdmask |= psys_emitter_customdata_mask(psys); + } + /* to iterate source and target psys in sync, + * we need to know where the newly added psys start + */ + psys_start = totpsys > 0 ? tmp_psys[0] : NULL; + + /* get the DM (psys and their modifiers have not been appended yet) */ + final_dm = mesh_get_derived_final(scene, ob_to, cdmask); + + /* now append psys to the object and make modifiers */ + for (i = 0, psys_from = PSYS_FROM_FIRST; + i < totpsys; + ++i, psys_from = PSYS_FROM_NEXT(psys_from)) { + + ParticleSystemModifierData *psmd; + + psys = tmp_psys[i]; + + /* append to the object */ + BLI_addtail(&ob_to->particlesystem, psys); + + /* add a particle system modifier for each system */ + md = modifier_new(eModifierType_ParticleSystem); + psmd = (ParticleSystemModifierData *)md; + /* push on top of the stack, no use trying to reproduce old stack order */ + BLI_addtail(&ob_to->modifiers, md); + + BLI_snprintf(md->name, sizeof(md->name), "ParticleSystem %i", i); + modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd); + + psmd->psys = psys; + psmd->dm = CDDM_copy(final_dm); + CDDM_calc_normals(psmd->dm); + DM_ensure_tessface(psmd->dm); + + if (psys_from->edit) + copy_particle_edit(scene, ob_to, psys, psys_from); + } + MEM_freeN(tmp_psys); + + /* note: do this after creating DM copies for all the particle system modifiers, + * the remapping otherwise makes final_dm invalid! + */ + for (psys = psys_start, psys_from = PSYS_FROM_FIRST, i = 0; + psys; + psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), ++i) { + + float (*from_mat)[4], (*to_mat)[4]; + + switch (space) { + case PAR_COPY_SPACE_OBJECT: + from_mat = I; + to_mat = I; + break; + case PAR_COPY_SPACE_WORLD: + from_mat = ob_from->obmat; + to_mat = ob_to->obmat; + break; + default: + /* should not happen */ + BLI_assert(false); + break; + } + + remap_hair_emitter(scene, ob_from, psys_from, ob_to, psys, psys->edit, from_mat, to_mat, psys_from->flag & PSYS_GLOBAL_HAIR, psys->flag & PSYS_GLOBAL_HAIR); + + /* tag for recalc */ +// psys->recalc |= PSYS_RECALC_RESET; + } + + #undef PSYS_FROM_FIRST + #undef PSYS_FROM_NEXT + + DAG_id_tag_update(&ob_to->id, OB_RECALC_DATA); + WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, ob_to); + return true; +} + +static int copy_particle_systems_poll(bContext *C) +{ + Object *ob; + if (!ED_operator_object_active_editable(C)) + return false; + + ob = ED_object_active_context(C); + if (BLI_listbase_is_empty(&ob->particlesystem)) + return false; + + return true; +} + +static int copy_particle_systems_exec(bContext *C, wmOperator *op) +{ + const int space = RNA_enum_get(op->ptr, "space"); + const bool remove_target_particles = RNA_boolean_get(op->ptr, "remove_target_particles"); + const bool use_active = RNA_boolean_get(op->ptr, "use_active"); + Scene *scene = CTX_data_scene(C); + Object *ob_from = ED_object_active_context(C); + ParticleSystem *psys_from = use_active ? CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data : NULL; + + int changed_tot = 0; + int fail = 0; + + CTX_DATA_BEGIN (C, Object *, ob_to, selected_editable_objects) + { + if (ob_from != ob_to) { + bool changed = false; + if (remove_target_particles) { + remove_particle_systems_from_object(ob_to); + changed = true; + } + if (copy_particle_systems_to_object(scene, ob_from, psys_from, ob_to, space)) + changed = true; + else + fail++; + + if (changed) + changed_tot++; + } + } + CTX_DATA_END; + + if ((changed_tot == 0 && fail == 0) || fail) { + BKE_reportf(op->reports, RPT_ERROR, + "Copy particle systems to selected: %d done, %d failed", + changed_tot, fail); + } + + return OPERATOR_FINISHED; +} + +void PARTICLE_OT_copy_particle_systems(wmOperatorType *ot) +{ + static EnumPropertyItem space_items[] = { + {PAR_COPY_SPACE_OBJECT, "OBJECT", 0, "Object", "Copy inside each object's local space"}, + {PAR_COPY_SPACE_WORLD, "WORLD", 0, "World", "Copy in world space"}, + {0, NULL, 0, NULL, NULL} + }; + + ot->name = "Copy Particle Systems"; + ot->description = "Copy particle systems from the active object to selected objects"; + ot->idname = "PARTICLE_OT_copy_particle_systems"; + + ot->poll = copy_particle_systems_poll; + ot->exec = copy_particle_systems_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "space", space_items, PAR_COPY_SPACE_OBJECT, "Space", "Space transform for copying from one object to another"); + RNA_def_boolean(ot->srna, "remove_target_particles", true, "Remove Target Particles", "Remove particle systems on the target objects"); + RNA_def_boolean(ot->srna, "use_active", false, "Use Active", "Use the active particle system from the context"); +} diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h index 8c49bf21191..88542515553 100644 --- a/source/blender/editors/physics/physics_intern.h +++ b/source/blender/editors/physics/physics_intern.h @@ -56,6 +56,8 @@ void PARTICLE_OT_mirror(struct wmOperatorType *ot); void PARTICLE_OT_brush_edit(struct wmOperatorType *ot); +void PARTICLE_OT_shape_cut(struct wmOperatorType *ot); + void PARTICLE_OT_particle_edit_toggle(struct wmOperatorType *ot); void PARTICLE_OT_edited_clear(struct wmOperatorType *ot); @@ -70,6 +72,7 @@ void PARTICLE_OT_target_move_up(struct wmOperatorType *ot); void PARTICLE_OT_target_move_down(struct wmOperatorType *ot); void PARTICLE_OT_connect_hair(struct wmOperatorType *ot); void PARTICLE_OT_disconnect_hair(struct wmOperatorType *ot); +void PARTICLE_OT_copy_particle_systems(struct wmOperatorType *ot); void PARTICLE_OT_dupliob_copy(struct wmOperatorType *ot); void PARTICLE_OT_dupliob_remove(struct wmOperatorType *ot); diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c index 37cf95e5c2d..8f32b0dffe9 100644 --- a/source/blender/editors/physics/physics_ops.c +++ b/source/blender/editors/physics/physics_ops.c @@ -64,6 +64,8 @@ static void operatortypes_particle(void) WM_operatortype_append(PARTICLE_OT_brush_edit); + WM_operatortype_append(PARTICLE_OT_shape_cut); + WM_operatortype_append(PARTICLE_OT_particle_edit_toggle); WM_operatortype_append(PARTICLE_OT_edited_clear); @@ -78,6 +80,7 @@ static void operatortypes_particle(void) WM_operatortype_append(PARTICLE_OT_target_move_down); WM_operatortype_append(PARTICLE_OT_connect_hair); WM_operatortype_append(PARTICLE_OT_disconnect_hair); + WM_operatortype_append(PARTICLE_OT_copy_particle_systems); WM_operatortype_append(PARTICLE_OT_dupliob_copy); WM_operatortype_append(PARTICLE_OT_dupliob_remove); diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 8024add41cf..fc6ff4eb0c0 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -315,8 +315,9 @@ static void screen_opengl_render_apply(OGLRender *oglrender) /* rr->rectf is now filled with image data */ - if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) - BKE_stamp_buf(scene, camera, rect, rr->rectf, rr->rectx, rr->recty, 4); + if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) { + BKE_image_stamp_buf(scene, camera, rect, rr->rectf, rr->rectx, rr->recty, 4); + } RE_ReleaseResult(oglrender->re); @@ -335,8 +336,9 @@ static void screen_opengl_render_apply(OGLRender *oglrender) IMB_color_to_bw(ibuf); } - BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, - &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false); + BKE_image_path_from_imformat( + name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, + &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false); ok = BKE_imbuf_write_as(ibuf, name, &scene->r.im_format, true); /* no need to stamp here */ if (ok) printf("OpenGL Render written to '%s'\n", name); else printf("OpenGL Render failed to write '%s'\n", name); @@ -564,8 +566,9 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype); if (!is_movie) { - BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, - &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true); + BKE_image_path_from_imformat( + name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, + &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true); if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) { BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index ea80a07fdd4..99edaff759e 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -359,7 +359,7 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre for (base = sce->base.first; base; base = base->next) { if (base->object->type == OB_LAMP) { /* if doesn't match 'Lamp.002' --> main key light */ - if (strcmp(base->object->id.name + 2, "Lamp.002") != 0) { + if (!STREQ(base->object->id.name + 2, "Lamp.002")) { if (mat->material_type == MA_TYPE_VOLUME) base->object->restrictflag |= OB_RESTRICT_RENDER; else @@ -1100,7 +1100,7 @@ static void icon_preview_free(void *customdata) void ED_preview_icon_render(Scene *scene, ID *id, unsigned int *rect, int sizex, int sizey) { - IconPreview ip = {0}; + IconPreview ip = {NULL}; short stop = false, update = false; float progress = 0.0f; diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 91c689373be..94a3defa95a 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -1412,7 +1412,7 @@ static int envmap_save_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", path); if (scene->r.scemode & R_EXTENSION) { - BKE_add_image_extension(path, &scene->r.im_format); + BKE_image_path_ensure_ext_from_imformat(path, &scene->r.im_format); } WM_cursor_wait(1); diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c index ab28f5fa675..fe357a7a0e2 100644 --- a/source/blender/editors/render/render_view.c +++ b/source/blender/editors/render/render_view.c @@ -161,11 +161,19 @@ ScrArea *render_view_open(bContext *C, int mx, int my) } else if (scene->r.displaymode == R_OUTPUT_SCREEN) { sa = CTX_wm_area(C); - if (sa && sa->spacetype == SPACE_IMAGE) - area_was_image = true; - /* this function returns with changed context */ - sa = ED_screen_full_newspace(C, sa, SPACE_IMAGE); + /* if the active screen is already in fullscreen mode, skip this and + * unset the area, so that the fullscreen area is just changed later */ + if (sa && sa->full) { + sa = NULL; + } + else { + if (sa && sa->spacetype == SPACE_IMAGE) + area_was_image = true; + + /* this function returns with changed context */ + sa = ED_screen_full_newspace(C, sa, SPACE_IMAGE); + } } if (!sa) { @@ -186,10 +194,15 @@ ScrArea *render_view_open(bContext *C, int mx, int my) /* makes ESC go back to prev space */ sima->flag |= SI_PREVSPACE; + + /* we already had a fullscreen here -> mark new space as a stacked fullscreen */ + if (sa->full) { + sa->flag |= AREA_FLAG_STACKED_FULLSCREEN; + } } else { /* use any area of decent size */ - sa = BKE_screen_find_big_area(CTX_wm_screen(C), -1, 0); + sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0); if (sa->spacetype != SPACE_IMAGE) { // XXX newspace(sa, SPACE_IMAGE); sima = sa->spacedata.first; diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 71714bdcda9..83b22bb1a8a 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1645,6 +1645,8 @@ void ED_area_prevspace(bContext *C, ScrArea *sa) /* no change */ return; } + sa->flag &= ~AREA_FLAG_STACKED_FULLSCREEN; + ED_area_tag_redraw(sa); /* send space change notifier */ @@ -2161,4 +2163,3 @@ void ED_region_cache_draw_cached_segments(const ARegion *ar, const int num_segme } } } - diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 134feb59d55..4c1698bd1d4 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -1136,9 +1136,9 @@ void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int void cpack(unsigned int x) { - glColor3ub( ( (x) & 0xFF), - (((x) >> 8) & 0xFF), - (((x) >> 16) & 0xFF) ); + glColor3ub(( (x) & 0xFF), + (((x) >> 8) & 0xFF), + (((x) >> 16) & 0xFF)); } void glaDrawBorderCorners(const rcti *border, float zoomx, float zoomy) diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index ce9c608247b..3431ce9f50a 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -497,7 +497,9 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult bGPDstroke *gps; for (gps = gpf->strokes.first; gps; gps = gps->next) { - CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps); + if (ED_gpencil_stroke_can_use_direct(sa, gps)) { + CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps); + } } } } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 3972d00293c..f338fa160f5 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1762,15 +1762,16 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type) void ED_screen_full_prevspace(bContext *C, ScrArea *sa) { - wmWindow *win = CTX_wm_window(C); - - ED_area_prevspace(C, sa); - - if (sa->full) - ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED); + if (sa->flag & AREA_FLAG_STACKED_FULLSCREEN) { + /* stacked fullscreen -> only go back to previous screen and don't toggle out of fullscreen */ + ED_area_prevspace(C, sa); + } + else { + ED_screen_restore_temp_type(C, sa); + } } -void ED_screen_retore_temp_type(bContext *C, ScrArea *sa, bool is_screen_change) +void ED_screen_restore_temp_type(bContext *C, ScrArea *sa) { /* incase nether functions below run */ ED_area_tag_redraw(sa); @@ -1780,7 +1781,7 @@ void ED_screen_retore_temp_type(bContext *C, ScrArea *sa, bool is_screen_change) sa->flag &= ~AREA_FLAG_TEMP_TYPE; } - if (is_screen_change && sa->full) { + if (sa->full) { ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED); } } @@ -1793,25 +1794,11 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa) bScreen *screen = CTX_wm_screen(C); short state = (screen ? screen->state : SCREENMAXIMIZED); - /* if fullscreen area has a secondary space (such as a file browser or fullscreen render - * overlaid on top of a existing setup) then return to the previous space */ + /* if fullscreen area has a temporary space (such as a file browser or fullscreen render + * overlaid on top of an existing setup) then return to the previous space */ if (sl->next) { - /* specific checks for space types */ - - /* Special check added for non-render image window (back from fullscreen through "Back to Previous" button) */ - if (sl->spacetype == SPACE_IMAGE) { - SpaceImage *sima = sa->spacedata.first; - - if (sima->flag & (SI_PREVSPACE | SI_FULLWINDOW)) { - sima->flag &= ~SI_PREVSPACE; - sima->flag &= ~SI_FULLWINDOW; - ED_screen_full_prevspace(C, sa); - } - else - ED_screen_state_toggle(C, win, sa, state); - } - else if (sa->flag & AREA_FLAG_TEMP_TYPE) { + if (sa->flag & AREA_FLAG_TEMP_TYPE) { ED_screen_full_prevspace(C, sa); } else { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 39321ec0770..ad3d2d1a21a 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -598,19 +598,6 @@ typedef struct sActionzoneData { int x, y, gesture_dir, modifier; } sActionzoneData; -/* used by other operators too */ -static ScrArea *screen_areahascursor(bScreen *scr, int x, int y) -{ - ScrArea *sa = NULL; - sa = scr->areabase.first; - while (sa) { - if (BLI_rcti_isect_pt(&sa->totrct, x, y)) break; - sa = sa->next; - } - - return sa; -} - /* quick poll to save operators to be created and handled */ static int actionzone_area_poll(bContext *C) { @@ -808,7 +795,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) /* gesture is large enough? */ if (is_gesture) { /* second area, for join when (sa1 != sa2) */ - sad->sa2 = screen_areahascursor(sc, event->x, event->y); + sad->sa2 = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y); /* apply sends event */ actionzone_apply(C, op, sad->az->type); actionzone_exit(op); @@ -929,7 +916,7 @@ static int area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event) switch (event->type) { case MOUSEMOVE: /* second area, for join */ - sad->sa2 = screen_areahascursor(CTX_wm_screen(C), event->x, event->y); + sad->sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y); break; case LEFTMOUSE: /* release LMB */ if (event->val == KM_RELEASE) { @@ -1679,7 +1666,8 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V); ED_area_tag_redraw(sd->sarea); } - sd->sarea = screen_areahascursor(CTX_wm_screen(C), event->x, event->y); /* area context not set */ + /* area context not set */ + sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y); if (sd->sarea) { ED_area_tag_redraw(sd->sarea); @@ -2482,8 +2470,8 @@ static int area_join_init(bContext *C, wmOperator *op) x2 = RNA_int_get(op->ptr, "max_x"); y2 = RNA_int_get(op->ptr, "max_y"); - sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1); - sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2); + sa1 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, x1, y1); + sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, x2, y2); if (sa1 == NULL || sa2 == NULL || sa1 == sa2) return 0; @@ -2616,7 +2604,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) case MOUSEMOVE: { - ScrArea *sa = screen_areahascursor(sc, event->x, event->y); + ScrArea *sa = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y); int dir; if (sa) { @@ -3399,7 +3387,12 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv (sad->flag & ANIMPLAY_FLAG_REVERSE) == false && finite(time = sound_sync_scene(scene))) { - scene->r.cfra = (double)time * FPS + 0.5; + double newfra = (double)time * FPS; + /* give some space here to avoid jumps */ + if (newfra + 0.5 > scene->r.cfra && newfra - 0.5 < scene->r.cfra) + scene->r.cfra++; + else + scene->r.cfra = newfra + 0.5; } else { if (sync) { @@ -3476,11 +3469,29 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv for (sa = window->screen->areabase.first; sa; sa = sa->next) { ARegion *ar; for (ar = sa->regionbase.first; ar; ar = ar->next) { + bool redraw = false; if (ar == sad->ar) { - ED_region_tag_redraw(ar); + redraw = true; } else if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws)) { + redraw = true; + } + + if (redraw) { ED_region_tag_redraw(ar); + /* do follow here if editor type supports it */ + if ((sad->redraws & TIME_FOLLOW)) { + if ((ar->regiontype == RGN_TYPE_WINDOW && + ELEM (sa->spacetype, SPACE_SEQ, SPACE_TIME, SPACE_IPO, SPACE_ACTION, SPACE_NLA)) || + (sa->spacetype == SPACE_CLIP && ar->regiontype == RGN_TYPE_PREVIEW)) + { + float w = BLI_rctf_size_x(&ar->v2d.cur); + if (scene->r.cfra < ar->v2d.cur.xmin || scene->r.cfra > (ar->v2d.cur.xmax)) { + ar->v2d.cur.xmin = scene->r.cfra; + ar->v2d.cur.xmax = ar->v2d.cur.xmin + w; + } + } + } } } @@ -3546,6 +3557,8 @@ int ED_screen_animation_play(bContext *C, int sync, int mode) /* stop playback now */ ED_screen_animation_timer(C, 0, 0, 0, 0); sound_stop_scene(scene); + + WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); } else { int refresh = SPACE_TIME; /* these settings are currently only available from a menu in the TimeLine */ @@ -3707,9 +3720,9 @@ static int fullscreen_back_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found"); return OPERATOR_CANCELLED; } - - ED_screen_full_restore(C, sa); - + + ED_screen_full_prevspace(C, sa); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index e7f256e414a..9c05f1d4780 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -377,8 +377,9 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float char name[FILE_MAX]; int ok; - BKE_makepicstring(name, rd.pic, sj->bmain->name, rd.cfra, - &rd.im_format, (rd.scemode & R_EXTENSION) != 0, true); + BKE_image_path_from_imformat( + name, rd.pic, sj->bmain->name, rd.cfra, + &rd.im_format, (rd.scemode & R_EXTENSION) != 0, true); ibuf->rect = sj->dumprect; ok = BKE_imbuf_write(ibuf, name, &rd.im_format); diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 430ea1cc11d..2d425b7e5a0 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -652,16 +652,12 @@ static void paint_draw_tex_overlay(UnifiedPaintSettings *ups, Brush *brush, } /* set quad color. Colored overlay does not get blending */ - if (col) - glColor4f(1.0, - 1.0, - 1.0, - overlay_alpha / 100.0f); - else - glColor4f(U.sculpt_paint_overlay_col[0], - U.sculpt_paint_overlay_col[1], - U.sculpt_paint_overlay_col[2], - overlay_alpha / 100.0f); + if (col) { + glColor4f(1.0, 1.0, 1.0, overlay_alpha / 100.0f); + } + else { + glColor4f(UNPACK3(U.sculpt_paint_overlay_col), overlay_alpha / 100.0f); + } /* draw textured quad */ glBegin(GL_QUADS); diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c index 1f5ee708ad0..439c2a639bd 100644 --- a/source/blender/editors/sculpt_paint/paint_curve.c +++ b/source/blender/editors/sculpt_paint/paint_curve.c @@ -108,7 +108,7 @@ static void paintcurve_undo_restore(bContext *C, ListBase *lb) uc = (UndoCurve *)lb->first; - if (strncmp(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname))) == 0) { + if (STREQLEN(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname)))) { SWAP(PaintCurvePoint *, pc->points, uc->points); SWAP(int, pc->tot_points, uc->tot_points); SWAP(int, pc->add_index, uc->active_point); diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index d52b17372f7..5cfbd164153 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -158,9 +158,10 @@ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, Cop } } else { - if (mode == RESTORE_COPY) + 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); + 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); @@ -192,7 +193,7 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi for (tile = lb->first; tile; tile = tile->next) { if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) { if (tile->use_float == use_float) { - if (strcmp(tile->idname, ima->id.name) == 0 && strcmp(tile->ibufname, ibuf->name) == 0) { + if (STREQ(tile->idname, ima->id.name) && STREQ(tile->ibufname, ibuf->name)) { if (mask) { /* allocate mask if requested */ if (!tile->mask) { @@ -327,7 +328,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb) short use_float; /* find image based on name, pointer becomes invalid with global undo */ - if (ima && strcmp(tile->idname, ima->id.name) == 0) { + if (ima && STREQ(tile->idname, ima->id.name)) { /* ima is valid */ } else { @@ -336,7 +337,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb) ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - if (ima && ibuf && strcmp(tile->ibufname, ibuf->name) != 0) { + if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) { /* current ImBuf filename was changed, probably current frame * was changed when painting on image sequence, rather than storing * full image user (which isn't so obvious, btw) try to find ImBuf with diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 3e675012d05..098477ed2a1 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -203,6 +203,7 @@ typedef struct ProjPaintState { /* the paint color. It can change depending of inverted mode or not */ float paint_color[3]; float paint_color_linear[3]; + float dither; Brush *brush; short tool, blend, mode; @@ -422,17 +423,19 @@ static int project_bucket_offset_safe(const ProjPaintState *ps, const float proj } } -static float VecZDepthOrtho(const float pt[2], - const float v1[3], const float v2[3], const float v3[3], - float w[3]) +static float VecZDepthOrtho( + const float pt[2], + const float v1[3], const float v2[3], const float v3[3], + float w[3]) { barycentric_weights_v2(v1, v2, v3, pt, w); return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]); } -static float VecZDepthPersp(const float pt[2], - const float v1[4], const float v2[4], const float v3[4], - float w[3]) +static float VecZDepthPersp( + const float pt[2], + const float v1[4], const float v2[4], const float v3[4], + float w[3]) { float wtot_inv, wtot; float w_tmp[3]; @@ -542,8 +545,9 @@ static void uvco_to_wrapped_pxco(const float uv[2], int ibuf_x, int ibuf_y, floa } /* Set the top-most face color that the screen space coord 'pt' touches (or return 0 if none touch) */ -static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2], - float *rgba_fp, unsigned char *rgba, const bool interp) +static bool project_paint_PickColor( + const ProjPaintState *ps, const float pt[2], + float *rgba_fp, unsigned char *rgba, const bool interp) { float w[3], uv[2]; int side; @@ -637,9 +641,10 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2], * 1 : occluded * 2 : occluded with w[3] weights set (need to know in some cases) */ -static int project_paint_occlude_ptv(const float pt[3], - const float v1[4], const float v2[4], const float v3[4], - float w[3], const bool is_ortho) +static int project_paint_occlude_ptv( + const float pt[3], + const float v1[4], const float v2[4], const float v3[4], + float w[3], const bool is_ortho) { /* if all are behind us, return false */ if (v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2]) @@ -669,9 +674,10 @@ static int project_paint_occlude_ptv(const float pt[3], } -static int project_paint_occlude_ptv_clip(const ProjPaintState *ps, const MFace *mf, - const float pt[3], const float v1[4], const float v2[4], const float v3[4], - const int side) +static int project_paint_occlude_ptv_clip( + const ProjPaintState *ps, const MFace *mf, + const float pt[3], const float v1[4], const float v2[4], const float v3[4], + const int side) { float w[3], wco[3]; int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, ps->is_ortho); @@ -699,8 +705,9 @@ static int project_paint_occlude_ptv_clip(const ProjPaintState *ps, const MFace /* Check if a screenspace location is occluded by any other faces * check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison * and doesn't need to be correct in relation to X and Y coords (this is the case in perspective view) */ -static bool project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *bucketFace, - const int orig_face, const float pixelScreenCo[4]) +static bool project_bucket_point_occluded( + const ProjPaintState *ps, LinkNode *bucketFace, + const int orig_face, const float pixelScreenCo[4]) { MFace *mf; int face_index; @@ -912,9 +919,10 @@ static void project_face_winding_init(const ProjPaintState *ps, const int face_i /* This function returns 1 if this face has a seam along the 2 face-vert indices * 'orig_i1_fidx' and 'orig_i2_fidx' */ -static bool check_seam(const ProjPaintState *ps, - const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx, - int *other_face, int *orig_fidx) +static bool check_seam( + const ProjPaintState *ps, + const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx, + int *other_face, int *orig_fidx) { LinkNode *node; int face_index; @@ -1003,8 +1011,9 @@ BLI_INLINE float shell_v2v2_normal_dir_to_dist(float n[2], float d[2]) /* Calculate outset UV's, this is not the same as simply scaling the UVs, * since the outset coords are a margin that keep an even distance from the original UV's, * note that the image aspect is taken into account */ -static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const float scaler, - const int ibuf_x, const int ibuf_y, const bool is_quad, const bool cw) +static void uv_image_outset( + float (*orig_uv)[2], float (*outset_uv)[2], const float scaler, + const int ibuf_x, const int ibuf_y, const bool is_quad, const bool cw) { float a1, a2, a3, a4 = 0.0f; float puv[4][2]; /* pixelspace uv's */ @@ -1212,8 +1221,9 @@ static void screen_px_from_persp( } -static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const float w[3], - int side, unsigned char rgba_ub[4], float rgba_f[4]) +static void project_face_pixel( + const MTFace *tf_other, ImBuf *ibuf_other, const float w[3], + int side, unsigned char rgba_ub[4], float rgba_f[4]) { const float *uvCo1, *uvCo2, *uvCo3; float uv_other[2], x, y; @@ -1454,7 +1464,7 @@ static ProjPixel *project_paint_uvpixel_init( y_px = mod_i(y_px, ibuf->y); BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool)); - projPixel = (ProjPixel *)BLI_memarena_alloc(arena, ps->pixel_sizeof); + 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 */ @@ -1585,7 +1595,7 @@ static ProjPixel *project_paint_uvpixel_init( } static bool line_clip_rect2f( - rctf *rect, + const rctf *rect, const float l1[2], const float l2[2], float l1_clip[2], float l2_clip[2]) { @@ -1800,7 +1810,7 @@ static float len_squared_v2v2_alt(const float v1[2], const float v2_1, const flo /* note, use a squared value so we can use len_squared_v2v2 * be sure that you have done a bounds check first or this may fail */ /* only give bucket_bounds as an arg because we need it elsewhere */ -static bool project_bucket_isect_circle(const float cent[2], const float radius_squared, rctf *bucket_bounds) +static bool project_bucket_isect_circle(const float cent[2], const float radius_squared, const rctf *bucket_bounds) { /* Would normally to a simple intersection test, however we know the bounds of these 2 already intersect @@ -1855,7 +1865,7 @@ static bool project_bucket_isect_circle(const float cent[2], const float radius_ * however switching back to this for ortho is always an option */ static void rect_to_uvspace_ortho( - rctf *bucket_bounds, + const rctf *bucket_bounds, const float *v1coSS, const float *v2coSS, const float *v3coSS, const float *uv1co, const float *uv2co, const float *uv3co, float bucket_bounds_uv[4][2], @@ -1888,7 +1898,7 @@ static void rect_to_uvspace_ortho( /* same as above but use barycentric_weights_v2_persp */ static void rect_to_uvspace_persp( - rctf *bucket_bounds, + const rctf *bucket_bounds, const float *v1coSS, const float *v2coSS, const float *v3coSS, const float *uv1co, const float *uv2co, const float *uv3co, float bucket_bounds_uv[4][2], @@ -1964,7 +1974,7 @@ static int float_z_sort(const void *p1, const void *p2) /* assumes one point is within the rectangle */ static void line_rect_clip( - rctf *rect, + const rctf *rect, const float l1[4], const float l2[4], const float uv1[2], const float uv2[2], float uv[2], bool is_ortho) @@ -1989,14 +1999,14 @@ static void line_rect_clip( tmp = (is_ortho) ? 1.0f : (l1[3] + min * (l2[3] - l1[3])); - uv[0] = (uv1[0] + min * (uv2[0] - uv1[0])) / tmp; - uv[1] = (uv1[1] + min * (uv2[1] - uv1[1])) / tmp; + uv[0] = (uv1[0] + min / tmp * (uv2[0] - uv1[0])); + uv[1] = (uv1[1] + min / tmp * (uv2[1] - uv1[1])); } static void project_bucket_clip_face( const bool is_ortho, - rctf *bucket_bounds, + const rctf *bucket_bounds, float *v1coSS, float *v2coSS, float *v3coSS, const float *uv1co, const float *uv2co, const float *uv3co, float bucket_bounds_uv[8][2], @@ -2004,7 +2014,8 @@ static void project_bucket_clip_face( { int inside_bucket_flag = 0; int inside_face_flag = 0; - const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f)); + const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != + (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f)); bool colinear = false; float bucket_bounds_ss[4][2]; @@ -2020,7 +2031,8 @@ static void project_bucket_clip_face( inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2; if (inside_bucket_flag == ISECT_ALL3) { - /* all screenspace points are inside the bucket bounding box, this means we don't need to clip and can simply return the UVs */ + /* all screenspace points are inside the bucket bounding box, + * this means we don't need to clip and can simply return the UVs */ if (flip) { /* facing the back? */ copy_v2_v2(bucket_bounds_uv[0], uv3co); copy_v2_v2(bucket_bounds_uv[1], uv2co); @@ -2076,8 +2088,8 @@ static void project_bucket_clip_face( /* at this point we have all uv points needed in a row. all that's needed is to invert them if necessary */ if (flip) { /* flip only to the middle of the array */ - int i, max = *tot / 2; - for (i = 0; i < max; i++) { + int i, max = *tot - 1, mid = *tot / 2; + for (i = 0; i < mid; i++) { SWAP(float, bucket_bounds_uv[i][0], bucket_bounds_uv[max - i][0]); SWAP(float, bucket_bounds_uv[i][1], bucket_bounds_uv[max - i][1]); } @@ -2205,7 +2217,8 @@ static void project_bucket_clip_face( for (i = 0; i < (*tot); i++) { v2_clipSS[0] = isectVCosSS[i][0] - cent[0]; v2_clipSS[1] = isectVCosSS[i][1] - cent[1]; - isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0], v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]); + isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0], + v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]); } if (flip) qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort_flip); @@ -2260,7 +2273,9 @@ static void project_bucket_clip_face( int i; if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip); else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip); - printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ", test_uv[0][0], test_uv[0][1], test_uv[1][0], test_uv[1][1], test_uv[2][0], test_uv[2][1], test_uv[3][0], test_uv[3][1]); + printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ", + test_uv[0][0], test_uv[0][1], test_uv[1][0], test_uv[1][1], + test_uv[2][0], test_uv[2][1], test_uv[3][0], test_uv[3][1]); printf(" [(%f,%f), (%f,%f), (%f,%f)], ", uv1co[0], uv1co[1], uv2co[0], uv2co[1], uv3co[0], uv3co[1]); @@ -2358,9 +2373,15 @@ static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot return 1; } -/* 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, ImBuf *ibuf, ImBuf **tmpibuf, const short clamp_u, const short clamp_v) +/* 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, + const 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]; @@ -2824,7 +2845,7 @@ static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x, /* Fill this bucket with pixels from the faces that intersect it. * * have bucket_bounds as an argument so we don't need to give bucket_x/y the rect function needs */ -static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, rctf *bucket_bounds) +static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const rctf *bucket_bounds) { LinkNode *node; int face_index, image_index = 0; @@ -3000,145 +3021,9 @@ static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf, #endif } -/* run once per stroke before projection painting */ -static void project_paint_begin(ProjPaintState *ps) +/* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */ +static void proj_paint_state_non_cddm_init(ProjPaintState *ps) { - /* Viewport vars */ - float mat[3][3]; - - float no[3]; - - float *projScreenCo; /* Note, we could have 4D vectors are only needed for */ - float projMargin; - - /* Image Vars - keep track of images we have used */ - LinkNode *image_LinkList = NULL; - LinkNode *node; - - 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_base; - - MTFace **tf_clone; - MTFace *tf_clone_base = NULL; - - int a, i; /* generic looping vars */ - int image_index = -1, face_index; - - /* double lookup */ - const int *index_mf_to_mpoly = NULL; - const int *index_mp_to_orig = NULL; - - MVert *mv; - - MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */ - - const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush); - - bool reset_threads = false; - - /* ---- end defines ---- */ - - if (ps->source == PROJ_SRC_VIEW) - ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */ - - ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0); - - /* paint onto the derived mesh */ - - /* Workaround for subsurf selection, try the display mesh first */ - if (ps->source == PROJ_SRC_IMAGE_CAM) { - /* using render mesh, assume only camera was rendered from */ - ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE); - ps->dm_release = true; - } - else if (ps->ob->derivedFinal && - CustomData_has_layer(&ps->ob->derivedFinal->faceData, CD_MTFACE) && - (ps->do_face_sel == false || CustomData_has_layer(&ps->ob->derivedFinal->polyData, CD_ORIGINDEX))) - { - ps->dm = ps->ob->derivedFinal; - ps->dm_release = false; - } - else { - ps->dm = mesh_get_derived_final( - ps->scene, ps->ob, - ps->scene->customdata_mask | CD_MASK_MTFACE | (ps->do_face_sel ? CD_ORIGINDEX : 0)); - ps->dm_release = true; - } - - if (!CustomData_has_layer(&ps->dm->faceData, CD_MTFACE)) { - - if (ps->dm_release) - ps->dm->release(ps->dm); - - ps->dm = NULL; - return; - } - - 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); - if (index_mf_to_mpoly == NULL) { - index_mp_to_orig = NULL; - } - else { - mpoly_orig = ((Mesh *)ps->ob->data)->mpoly; - } - } - else { - mpoly_orig = NULL; - } - - /* use clone mtface? */ - if (ps->do_layer_clone) { - ps->dm_mtface_clone = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces"); - } - - 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) { - /* 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 */ if (ps->dm->type != DM_TYPE_CDDM) { ps->dm_mvert = MEM_dupallocN(ps->dm_mvert); ps->dm_mface = MEM_dupallocN(ps->dm_mface); @@ -3149,97 +3034,108 @@ static void project_paint_begin(ProjPaintState *ps) ps->dm_mtface_stencil = MEM_dupallocN(ps->dm_mtface_stencil); #endif } +} + +static void proj_paint_state_viewport_init(ProjPaintState *ps) +{ + float mat[3][3]; + float viewmat[4][4]; + float viewinv[4][4]; ps->viewDir[0] = 0.0f; ps->viewDir[1] = 0.0f; ps->viewDir[2] = 1.0f; - { - float viewmat[4][4]; - float viewinv[4][4]; + invert_m4_m4(ps->ob->imat, ps->ob->obmat); - invert_m4_m4(ps->ob->imat, ps->ob->obmat); + if (ELEM(ps->source, PROJ_SRC_VIEW, PROJ_SRC_VIEW_FILL)) { + /* normal drawing */ + ps->winx = ps->ar->winx; + ps->winy = ps->ar->winy; - if (ELEM(ps->source, PROJ_SRC_VIEW, PROJ_SRC_VIEW_FILL)) { - /* normal drawing */ - ps->winx = ps->ar->winx; - ps->winy = ps->ar->winy; + copy_m4_m4(viewmat, ps->rv3d->viewmat); + copy_m4_m4(viewinv, ps->rv3d->viewinv); - copy_m4_m4(viewmat, ps->rv3d->viewmat); - copy_m4_m4(viewinv, ps->rv3d->viewinv); + ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->projectMat); - ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->projectMat); + ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true); + } + else { + /* re-projection */ + float winmat[4][4]; + float vmat[4][4]; - ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true); - } - else { - /* re-projection */ - float winmat[4][4]; - float vmat[4][4]; + ps->winx = ps->reproject_ibuf->x; + ps->winy = ps->reproject_ibuf->y; - ps->winx = ps->reproject_ibuf->x; - ps->winy = ps->reproject_ibuf->y; + if (ps->source == PROJ_SRC_IMAGE_VIEW) { + /* image stores camera data, tricky */ + IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0); + IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID); - if (ps->source == PROJ_SRC_IMAGE_VIEW) { - /* image stores camera data, tricky */ - IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0); - IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID); + const float *array = (float *)IDP_Array(view_data); - const float *array = (float *)IDP_Array(view_data); + /* use image array, written when creating image */ + memcpy(winmat, array, sizeof(winmat)); array += sizeof(winmat) / sizeof(float); + memcpy(viewmat, array, sizeof(viewmat)); array += sizeof(viewmat) / sizeof(float); + ps->clipsta = array[0]; + ps->clipend = array[1]; + ps->is_ortho = array[2] ? 1 : 0; - /* use image array, written when creating image */ - memcpy(winmat, array, sizeof(winmat)); array += sizeof(winmat) / sizeof(float); - memcpy(viewmat, array, sizeof(viewmat)); array += sizeof(viewmat) / sizeof(float); - ps->clipsta = array[0]; - ps->clipend = array[1]; - ps->is_ortho = array[2] ? 1 : 0; + invert_m4_m4(viewinv, viewmat); + } + else if (ps->source == PROJ_SRC_IMAGE_CAM) { + Object *cam_ob = ps->scene->camera; + CameraParams params; - invert_m4_m4(viewinv, viewmat); - } - else if (ps->source == PROJ_SRC_IMAGE_CAM) { - Object *cam_ob = ps->scene->camera; - CameraParams params; - - /* viewmat & viewinv */ - copy_m4_m4(viewinv, cam_ob->obmat); - normalize_m4(viewinv); - invert_m4_m4(viewmat, viewinv); - - /* window matrix, clipping and ortho */ - BKE_camera_params_init(¶ms); - BKE_camera_params_from_object(¶ms, cam_ob); - BKE_camera_params_compute_viewplane(¶ms, ps->winx, ps->winy, 1.0f, 1.0f); - BKE_camera_params_compute_matrix(¶ms); - - copy_m4_m4(winmat, params.winmat); - ps->clipsta = params.clipsta; - ps->clipend = params.clipend; - ps->is_ortho = params.is_ortho; - } + /* viewmat & viewinv */ + copy_m4_m4(viewinv, cam_ob->obmat); + normalize_m4(viewinv); + invert_m4_m4(viewmat, viewinv); + + /* window matrix, clipping and ortho */ + BKE_camera_params_init(¶ms); + BKE_camera_params_from_object(¶ms, cam_ob); + BKE_camera_params_compute_viewplane(¶ms, ps->winx, ps->winy, 1.0f, 1.0f); + BKE_camera_params_compute_matrix(¶ms); - /* same as #ED_view3d_ob_project_mat_get */ - mul_m4_m4m4(vmat, viewmat, ps->ob->obmat); - mul_m4_m4m4(ps->projectMat, winmat, vmat); + copy_m4_m4(winmat, params.winmat); + ps->clipsta = params.clipsta; + ps->clipend = params.clipend; + ps->is_ortho = params.is_ortho; + } + else { + BLI_assert(0); } + /* same as #ED_view3d_ob_project_mat_get */ + mul_m4_m4m4(vmat, viewmat, ps->ob->obmat); + mul_m4_m4m4(ps->projectMat, winmat, vmat); + } - /* viewDir - object relative */ - invert_m4_m4(ps->ob->imat, ps->ob->obmat); - copy_m3_m4(mat, viewinv); - mul_m3_v3(mat, ps->viewDir); - copy_m3_m4(mat, ps->ob->imat); - mul_m3_v3(mat, ps->viewDir); - normalize_v3(ps->viewDir); - /* viewPos - object relative */ - copy_v3_v3(ps->viewPos, viewinv[3]); - copy_m3_m4(mat, ps->ob->imat); - mul_m3_v3(mat, ps->viewPos); - add_v3_v3(ps->viewPos, ps->ob->imat[3]); - } + /* viewDir - object relative */ + invert_m4_m4(ps->ob->imat, ps->ob->obmat); + copy_m3_m4(mat, viewinv); + mul_m3_v3(mat, ps->viewDir); + copy_m3_m4(mat, ps->ob->imat); + mul_m3_v3(mat, ps->viewDir); + normalize_v3(ps->viewDir); + + /* viewPos - object relative */ + copy_v3_v3(ps->viewPos, viewinv[3]); + copy_m3_m4(mat, ps->ob->imat); + mul_m3_v3(mat, ps->viewPos); + add_v3_v3(ps->viewPos, ps->ob->imat[3]); +} + +static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int diameter) +{ + MVert *mv; + float *projScreenCo; + float projMargin; + int a; - /* calculate vert screen coords - * run this early so we can calculate the x/y resolution of our bucket rect */ INIT_MINMAX2(ps->screenMin, ps->screenMax); ps->screenCoords = MEM_mallocN(sizeof(float) * ps->dm_totvert * 4, "ProjectPaint ScreenVerts"); @@ -3305,38 +3201,24 @@ static void project_paint_begin(ProjPaintState *ps) ps->screenMin[1] = 0; ps->screenMax[1] = (float)(ps->winy); } +} - /* only for convenience */ - ps->screen_width = ps->screenMax[0] - ps->screenMin[0]; - ps->screen_height = ps->screenMax[1] - ps->screenMin[1]; - - ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV)); - ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV)); - - /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */ - - if (ps->buckets_x > PROJ_BUCKET_RECT_MAX || ps->buckets_y > PROJ_BUCKET_RECT_MAX) { - reset_threads = true; - } - - /* really high values could cause problems since it has to allocate a few - * (ps->buckets_x*ps->buckets_y) sized arrays */ - CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX); - CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX); - - ps->bucketRect = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketRect"); - ps->bucketFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces"); - - ps->bucketFlags = (unsigned char *)MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces"); #ifndef PROJ_DEBUG_NOSEAMBLEED +static void proj_paint_state_seam_bleed_init(ProjPaintState *ps) +{ if (ps->seam_bleed_px > 0.0f) { - ps->vertFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->dm_totvert, "paint-vertFaces"); - ps->faceSeamFlags = (char *)MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceSeamFlags"); - ps->faceWindingFlags = (char *)MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceWindindFlags"); + ps->vertFaces = MEM_callocN(sizeof(LinkNode *) * ps->dm_totvert, "paint-vertFaces"); + ps->faceSeamFlags = MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceSeamFlags"); + ps->faceWindingFlags = MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceWindindFlags"); ps->faceSeamUVs = MEM_mallocN(sizeof(float) * ps->dm_totface * 8, "paint-faceSeamUVs"); } +} #endif +static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_threads) +{ + int a; + /* Thread stuff * * very small brushes run a lot slower multithreaded since the advantage with @@ -3360,11 +3242,15 @@ static void project_paint_begin(ProjPaintState *ps) for (a = 0; a < ps->thread_tot; a++) { ps->arena_mt[a] = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "project paint arena"); } +} - arena = ps->arena_mt[0]; - +static void proj_paint_state_vert_flags_init(ProjPaintState *ps) +{ if (ps->do_backfacecull && ps->do_mask_normal) { float viewDirPersp[3]; + MVert *mv; + float no[3]; + int a; ps->vertFlags = MEM_callocN(sizeof(char) * ps->dm_totvert, "paint-vertFlags"); @@ -3385,38 +3271,339 @@ static void project_paint_begin(ProjPaintState *ps) } } } - - for (face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index < ps->dm_totface; mf++, tf++, face_index++) { - bool is_face_sel; + else { + ps->vertFlags = NULL; + } +} #ifndef PROJ_DEBUG_NOSEAMBLEED - /* add face user if we have bleed enabled, set the UV seam flags later */ - /* annoying but we need to add all faces even ones we never use elsewhere */ - if (ps->seam_bleed_px > 0.0f) { - BLI_linklist_prepend_arena(&ps->vertFaces[mf->v1], SET_INT_IN_POINTER(face_index), arena); - BLI_linklist_prepend_arena(&ps->vertFaces[mf->v2], SET_INT_IN_POINTER(face_index), arena); - BLI_linklist_prepend_arena(&ps->vertFaces[mf->v3], SET_INT_IN_POINTER(face_index), arena); - if (mf->v4) { - BLI_linklist_prepend_arena(&ps->vertFaces[mf->v4], SET_INT_IN_POINTER(face_index), arena); - } +static void project_paint_bleed_add_face_user( + const ProjPaintState *ps, MemArena *arena, + const MFace *mf, const int face_index) +{ + /* add face user if we have bleed enabled, set the UV seam flags later */ + /* annoying but we need to add all faces even ones we never use elsewhere */ + if (ps->seam_bleed_px > 0.0f) { + BLI_linklist_prepend_arena(&ps->vertFaces[mf->v1], SET_INT_IN_POINTER(face_index), arena); + BLI_linklist_prepend_arena(&ps->vertFaces[mf->v2], SET_INT_IN_POINTER(face_index), arena); + BLI_linklist_prepend_arena(&ps->vertFaces[mf->v3], SET_INT_IN_POINTER(face_index), arena); + if (mf->v4) { + BLI_linklist_prepend_arena(&ps->vertFaces[mf->v4], SET_INT_IN_POINTER(face_index), arena); } + } +} #endif - if (ps->do_face_sel) { - int orig_index; - if (index_mp_to_orig && ((orig_index = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, - face_index))) != ORIGINDEX_NONE) - { - MPoly *mp = &mpoly_orig[orig_index]; - is_face_sel = ((mp->flag & ME_FACE_SEL) != 0); +/* Return true if DM can be painted on, false otherwise */ +static bool proj_paint_state_dm_init(ProjPaintState *ps) +{ + /* Workaround for subsurf selection, try the display mesh first */ + if (ps->source == PROJ_SRC_IMAGE_CAM) { + /* using render mesh, assume only camera was rendered from */ + ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE); + ps->dm_release = true; + } + else if (ps->ob->derivedFinal && + CustomData_has_layer(&ps->ob->derivedFinal->faceData, CD_MTFACE) && + (ps->do_face_sel == false || CustomData_has_layer(&ps->ob->derivedFinal->polyData, CD_ORIGINDEX))) + { + ps->dm = ps->ob->derivedFinal; + ps->dm_release = false; + } + else { + ps->dm = mesh_get_derived_final( + ps->scene, ps->ob, + ps->scene->customdata_mask | CD_MASK_MTFACE | (ps->do_face_sel ? CD_ORIGINDEX : 0)); + ps->dm_release = true; + } + + if (!CustomData_has_layer(&ps->dm->faceData, CD_MTFACE)) { + + if (ps->dm_release) + ps->dm->release(ps->dm); + + ps->dm = NULL; + return false; + } + + 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"); + + return true; +} + +typedef struct { + MTFace *tf_clone_base; + MTFace **tf_clone; + TexPaintSlot *slot_last_clone; + TexPaintSlot *slot_clone; +} ProjPaintLayerClone; + +static void proj_paint_layer_clone_init( + ProjPaintState *ps, + ProjPaintLayerClone *layer_clone) +{ + MTFace *tf_clone_base = NULL; + + /* use clone mtface? */ + if (ps->do_layer_clone) { + const int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY); + + ps->dm_mtface_clone = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces"); + + 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); + } + + } + + memset(layer_clone, 0, sizeof(*layer_clone)); + layer_clone->tf_clone_base = tf_clone_base; +} + +/* Return true if face should be skipped, false otherwise */ +static bool project_paint_clone_face_skip( + ProjPaintState *ps, + ProjPaintLayerClone *lc, + const TexPaintSlot *slot, + const int face_index) +{ + if (ps->do_layer_clone) { + if (ps->do_material_slots) { + lc->slot_clone = project_paint_face_clone_slot(ps, face_index); + /* all faces should have a valid slot, reassert here */ + if (ELEM(lc->slot_clone, NULL, slot)) + return true; + } + else if (ps->clone_ima == ps->canvas_ima) + return true; + + lc->tf_clone = ps->dm_mtface_clone + face_index; + + if (ps->do_material_slots) { + if (lc->slot_clone != lc->slot_last_clone) { + if (!slot->uvname || + !(lc->tf_clone_base = CustomData_get_layer_named( + &ps->dm->faceData, CD_MTFACE, + lc->slot_clone->uvname))) + { + lc->tf_clone_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); + } + lc->slot_last_clone = lc->slot_clone; } - else { - is_face_sel = ((mf->flag & ME_FACE_SEL) != 0); + } + + *lc->tf_clone = lc->tf_clone_base + face_index; + } + return false; +} + +typedef struct { + MPoly *mpoly_orig; + + /* double lookup */ + const int *index_mf_to_mpoly; + const int *index_mp_to_orig; +} ProjPaintFaceLookup; + +static void proj_paint_face_lookup_init( + const ProjPaintState *ps, + ProjPaintFaceLookup *face_lookup) +{ + memset(face_lookup, 0, sizeof(*face_lookup)); + if (ps->do_face_sel) { + face_lookup->index_mf_to_mpoly = ps->dm->getTessFaceDataArray(ps->dm, CD_ORIGINDEX); + face_lookup->index_mp_to_orig = ps->dm->getPolyDataArray(ps->dm, CD_ORIGINDEX); + if (face_lookup->index_mf_to_mpoly == NULL) { + face_lookup->index_mp_to_orig = NULL; + } + else { + face_lookup->mpoly_orig = ((Mesh *)ps->ob->data)->mpoly; + } + } +} + +/* Return true if face should be considered selected, false otherwise */ +static bool project_paint_check_face_sel( + const ProjPaintState *ps, + const ProjPaintFaceLookup *face_lookup, + const MFace *mf, const int face_index) +{ + if (ps->do_face_sel) { + int orig_index; + if (face_lookup->index_mp_to_orig && + ((orig_index = DM_origindex_mface_mpoly( + face_lookup->index_mf_to_mpoly, + face_lookup->index_mp_to_orig, + face_index))) != ORIGINDEX_NONE) + { + MPoly *mp = &face_lookup->mpoly_orig[orig_index]; + return ((mp->flag & ME_FACE_SEL) != 0); + } + else { + return ((mf->flag & ME_FACE_SEL) != 0); + } + } + else { + return true; + } +} + +typedef struct { + const float *v1; + const float *v2; + const float *v3; + const float *v4; +} ProjPaintFaceCoSS; + +static void proj_paint_face_coSS_init( + const ProjPaintState *ps, const MFace *mf, + ProjPaintFaceCoSS *coSS) +{ + coSS->v1 = ps->screenCoords[mf->v1]; + coSS->v2 = ps->screenCoords[mf->v2]; + coSS->v3 = ps->screenCoords[mf->v3]; + coSS->v4 = mf->v4 ? ps->screenCoords[mf->v4] : NULL; +} + +/* Return true if face should be culled, false otherwise */ +static bool project_paint_flt_max_cull( + const ProjPaintState *ps, + const ProjPaintFaceCoSS *coSS) +{ + if (!ps->is_ortho) { + if (coSS->v1[0] == FLT_MAX || + coSS->v2[0] == FLT_MAX || + coSS->v3[0] == FLT_MAX || + (coSS->v4 && coSS->v4[0] == FLT_MAX)) + { + return true; + } + } + return false; +} + +#ifdef PROJ_DEBUG_WINCLIP +/* Return true if face should be culled, false otherwise */ +static bool project_paint_winclip( + const ProjPaintState *ps, const MFace *mf, + const ProjPaintFaceCoSS *coSS) +{ + /* ignore faces outside the view */ + return ((ps->source != PROJ_SRC_VIEW_FILL) && + ((coSS->v1[0] < ps->screenMin[0] && + coSS->v2[0] < ps->screenMin[0] && + coSS->v3[0] < ps->screenMin[0] && + (mf->v4 && coSS->v4[0] < ps->screenMin[0])) || + + (coSS->v1[0] > ps->screenMax[0] && + coSS->v2[0] > ps->screenMax[0] && + coSS->v3[0] > ps->screenMax[0] && + (mf->v4 && coSS->v4[0] > ps->screenMax[0])) || + + (coSS->v1[1] < ps->screenMin[1] && + coSS->v2[1] < ps->screenMin[1] && + coSS->v3[1] < ps->screenMin[1] && + (mf->v4 && coSS->v4[1] < ps->screenMin[1])) || + + (coSS->v1[1] > ps->screenMax[1] && + coSS->v2[1] > ps->screenMax[1] && + coSS->v3[1] > ps->screenMax[1] && + (mf->v4 && coSS->v4[1] > ps->screenMax[1])))); +} +#endif //PROJ_DEBUG_WINCLIP + +/* Return true if face should be culled, false otherwise */ +static bool project_paint_backface_cull( + const ProjPaintState *ps, const MFace *mf, + const ProjPaintFaceCoSS *coSS) +{ + if (ps->do_backfacecull) { + if (ps->do_mask_normal) { + /* Since we are interpolating the normals of faces, we want to make + * sure all the verts are pointing away from the view, + * not just the face */ + if ((ps->vertFlags[mf->v1] & PROJ_VERT_CULL) && + (ps->vertFlags[mf->v2] & PROJ_VERT_CULL) && + (ps->vertFlags[mf->v3] & PROJ_VERT_CULL) && + (mf->v4 == 0 || ps->vertFlags[mf->v4] & PROJ_VERT_CULL)) + { + return true; } } else { - is_face_sel = true; + if (line_point_side_v2(coSS->v1, coSS->v2, coSS->v3) < 0.0f) { + return true; + } + } + } + + return false; +} + +static void project_paint_build_proj_ima( + ProjPaintState *ps, MemArena *arena, + LinkNode *image_LinkList) +{ + ProjPaintImage *projIma; + LinkNode *node; + int i; + + /* build an array of images we use */ + projIma = ps->projImages = 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); + 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 = BLI_memarena_alloc(arena, size); + memset(projIma->maskRect, 0, size); + projIma->valid = BLI_memarena_alloc(arena, size); + memset(projIma->valid, 0, size); + } +} + +static void project_paint_prepare_all_faces( + ProjPaintState *ps, MemArena *arena, + const ProjPaintFaceLookup *face_lookup, + ProjPaintLayerClone *layer_clone, + MTFace *tf_base) +{ + /* Image Vars - keep track of images we have used */ + LinkNode *image_LinkList = NULL; + + Image *tpage_last = NULL, *tpage; + TexPaintSlot *slot_last = NULL; + TexPaintSlot *slot = NULL; + MTFace **tf; + MFace *mf; + int image_index = -1, face_index; + + for (face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index < ps->dm_totface; mf++, tf++, face_index++) { + bool is_face_sel; + +#ifndef PROJ_DEBUG_NOSEAMBLEED + project_paint_bleed_add_face_user(ps, arena, mf, face_index); +#endif + + is_face_sel = project_paint_check_face_sel(ps, face_lookup, mf, face_index); if (!ps->do_stencil_brush) { slot = project_paint_face_paint_slot(ps, face_index); @@ -3445,103 +3632,31 @@ static void project_paint_begin(ProjPaintState *ps) *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; + if (project_paint_clone_face_skip(ps, layer_clone, slot, face_index)) { + continue; } /* tfbase here should be non-null! */ BLI_assert (tf_base != NULL); if (is_face_sel && tpage) { - const float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL; + ProjPaintFaceCoSS coSS; + proj_paint_face_coSS_init(ps, mf, &coSS); - v1coSS = ps->screenCoords[mf->v1]; - v2coSS = ps->screenCoords[mf->v2]; - v3coSS = ps->screenCoords[mf->v3]; - if (mf->v4) { - v4coSS = ps->screenCoords[mf->v4]; - } - - - if (!ps->is_ortho) { - if (v1coSS[0] == FLT_MAX || - v2coSS[0] == FLT_MAX || - v3coSS[0] == FLT_MAX || - (mf->v4 && v4coSS[0] == FLT_MAX)) - { - continue; - } + if (project_paint_flt_max_cull(ps, &coSS)) { + continue; } #ifdef PROJ_DEBUG_WINCLIP - /* ignore faces outside the view */ - if ((ps->source != PROJ_SRC_VIEW_FILL) && - ((v1coSS[0] < ps->screenMin[0] && - v2coSS[0] < ps->screenMin[0] && - v3coSS[0] < ps->screenMin[0] && - (mf->v4 && v4coSS[0] < ps->screenMin[0])) || - - (v1coSS[0] > ps->screenMax[0] && - v2coSS[0] > ps->screenMax[0] && - v3coSS[0] > ps->screenMax[0] && - (mf->v4 && v4coSS[0] > ps->screenMax[0])) || - - (v1coSS[1] < ps->screenMin[1] && - v2coSS[1] < ps->screenMin[1] && - v3coSS[1] < ps->screenMin[1] && - (mf->v4 && v4coSS[1] < ps->screenMin[1])) || - - (v1coSS[1] > ps->screenMax[1] && - v2coSS[1] > ps->screenMax[1] && - v3coSS[1] > ps->screenMax[1] && - (mf->v4 && v4coSS[1] > ps->screenMax[1]))) - ) - { + if (project_paint_winclip(ps, mf, &coSS)) { continue; } #endif //PROJ_DEBUG_WINCLIP - if (ps->do_backfacecull) { - if (ps->do_mask_normal) { - /* Since we are interpolating the normals of faces, we want to make - * sure all the verts are pointing away from the view, - * not just the face */ - if ((ps->vertFlags[mf->v1] & PROJ_VERT_CULL) && - (ps->vertFlags[mf->v2] & PROJ_VERT_CULL) && - (ps->vertFlags[mf->v3] & PROJ_VERT_CULL) && - (mf->v4 == 0 || ps->vertFlags[mf->v4] & PROJ_VERT_CULL) - ) - { - continue; - } - } - else { - if (line_point_side_v2(v1coSS, v2coSS, v3coSS) < 0.0f) { - continue; - } - - } + if (project_paint_backface_cull(ps, mf, &coSS)) { + continue; } if (tpage_last != tpage) { @@ -3566,28 +3681,98 @@ static void project_paint_begin(ProjPaintState *ps) } /* build an array of images we use*/ - 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); - 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); - } + project_paint_build_proj_ima(ps, arena, image_LinkList); /* we have built the array, discard the linked list */ BLI_linklist_free(image_LinkList, NULL); } +/* run once per stroke before projection painting */ +static void project_paint_begin(ProjPaintState *ps) +{ + ProjPaintLayerClone layer_clone; + ProjPaintFaceLookup face_lookup; + MTFace *tf_base; + + MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */ + + const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush); + + bool reset_threads = false; + + /* ---- end defines ---- */ + + if (ps->source == PROJ_SRC_VIEW) + ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */ + + ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0); + + /* paint onto the derived mesh */ + if (!proj_paint_state_dm_init(ps)) { + return; + } + + proj_paint_face_lookup_init(ps, &face_lookup); + proj_paint_layer_clone_init(ps, &layer_clone); + + 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) { + /* 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; + } + + /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */ + proj_paint_state_non_cddm_init(ps); + + proj_paint_state_viewport_init(ps); + + /* calculate vert screen coords + * run this early so we can calculate the x/y resolution of our bucket rect */ + proj_paint_state_screen_coords_init(ps, diameter); + + /* only for convenience */ + ps->screen_width = ps->screenMax[0] - ps->screenMin[0]; + ps->screen_height = ps->screenMax[1] - ps->screenMin[1]; + + ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV)); + ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV)); + + /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */ + + if (ps->buckets_x > PROJ_BUCKET_RECT_MAX || ps->buckets_y > PROJ_BUCKET_RECT_MAX) { + reset_threads = true; + } + + /* really high values could cause problems since it has to allocate a few + * (ps->buckets_x*ps->buckets_y) sized arrays */ + CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX); + CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX); + + ps->bucketRect = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketRect"); + ps->bucketFaces = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces"); + + ps->bucketFlags = MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces"); +#ifndef PROJ_DEBUG_NOSEAMBLEED + proj_paint_state_seam_bleed_init(ps); +#endif + + proj_paint_state_thread_init(ps, reset_threads); + arena = ps->arena_mt[0]; + + proj_paint_state_vert_flags_init(ps); + + project_paint_prepare_all_faces(ps, arena, &face_lookup, &layer_clone, tf_base); +} + static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2]) { /* setup clone offset */ @@ -3773,7 +3958,9 @@ 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]) +static bool project_bucket_iter_next( + ProjPaintState *ps, int *bucket_index, + rctf *bucket_bounds, const float mval[2]) { const int diameter = 2 * ps->brush_size; @@ -4011,20 +4198,21 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo } } -static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const float texrgb[3], float mask) +static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const float texrgb[3], float mask, float dither, float u, float v) { float rgb[3]; unsigned char rgba_ub[4]; - copy_v3_v3(rgb, ps->paint_color); - if (ps->is_texbrush) { - mul_v3_v3(rgb, texrgb); + mul_v3_v3v3(rgb, texrgb, ps->paint_color_linear); /* TODO(sergey): Support texture paint color space. */ linearrgb_to_srgb_v3_v3(rgb, rgb); } + else { + copy_v3_v3(rgb, ps->paint_color); + } - rgb_float_to_uchar(rgba_ub, rgb); + float_to_byte_dither_v3(rgba_ub, rgb, dither, u, v); rgba_ub[3] = f_to_char(mask); if (ps->do_masking) { @@ -4205,7 +4393,8 @@ static void *do_projectpaint_thread(void *ph_v) } else { linearrgb_to_srgb_v3_v3(color_f, color_f); - rgba_float_to_uchar(projPixel->newColor.ch, color_f); + float_to_byte_dither_v3(projPixel->newColor.ch, color_f, ps->dither, projPixel->x_px, projPixel->y_px); + projPixel->newColor.ch[3] = FTOCHAR(color_f[3]); IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, projPixel->newColor.ch, ps->blend); } @@ -4401,7 +4590,7 @@ static void *do_projectpaint_thread(void *ph_v) break; default: if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, texrgb, mask); - else do_projectpaint_draw(ps, projPixel, texrgb, mask); + else do_projectpaint_draw(ps, projPixel, texrgb, mask, ps->dither, projPixel->x_px, projPixel->y_px); break; } } @@ -4485,13 +4674,13 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po /* thread specific */ handles[a].thread_index = a; - handles[a].projImages = (ProjPaintImage *)BLI_memarena_alloc(ps->arena_mt[a], ps->image_tot * sizeof(ProjPaintImage)); + handles[a].projImages = BLI_memarena_alloc(ps->arena_mt[a], ps->image_tot * sizeof(ProjPaintImage)); memcpy(handles[a].projImages, ps->projImages, ps->image_tot * sizeof(ProjPaintImage)); /* image bounds */ for (i = 0; i < ps->image_tot; i++) { - handles[a].projImages[i].partRedrawRect = (ImagePaintPartialRedraw *)BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); + handles[a].projImages[i].partRedrawRect = BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); memcpy(handles[a].projImages[i].partRedrawRect, ps->projImages[i].partRedrawRect, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); } @@ -4705,6 +4894,8 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int if (ps->normal_angle_range <= 0.0f) ps->do_mask_normal = false; /* no need to do blending */ + ps->dither = settings->imapaint.dither; + return; } @@ -4732,7 +4923,7 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m /* Don't allow brush size below 2 */ if (BKE_brush_size_get(ps->scene, ps->brush) < 2) - BKE_brush_size_set(ps->scene, ps->brush, 2); + BKE_brush_size_set(ps->scene, ps->brush, 2 * U.pixelsize); /* allocate and initialize spatial data structures */ project_paint_begin(ps); @@ -4851,7 +5042,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) ps.is_maskbrush = 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 */ + BKE_brush_size_set(scene, ps.brush, 32 * U.pixelsize); /* cover the whole image */ ps.tool = PAINT_TOOL_DRAW; /* so pixels are initialized with minimal info */ @@ -4945,6 +5136,9 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) image = BKE_image_add_from_imbuf(ibuf); + /* Drop reference to ibuf so that the image owns it */ + IMB_freeImBuf(ibuf); + if (image) { /* now for the trickyness. store the view projection here! * re-projection will reuse this */ @@ -4965,7 +5159,9 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op) memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += sizeof(rv3d->winmat) / sizeof(float); memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += sizeof(rv3d->viewmat) / sizeof(float); is_ortho = ED_view3d_clip_range_get(v3d, rv3d, &array[0], &array[1], true); - array[2] = is_ortho ? 1.0f : 0.0f; /* using float for a bool is dodgy but since its an extra member in the array... easier then adding a single bool prop */ + /* using float for a bool is dodgy but since its an extra member in the array... + * easier then adding a single bool prop */ + array[2] = is_ortho ? 1.0f : 0.0f; IDP_AddToGroup(idgroup, view_data); @@ -5041,17 +5237,17 @@ bool BKE_paint_proj_mesh_data_check(Scene *scene, Object *ob, bool *uvs, bool *m hasmat = true; if (!ma->texpaintslot) { /* refresh here just in case */ - BKE_texpaint_slot_refresh_cache(scene, ma); + BKE_texpaint_slot_refresh_cache(scene, ma); /* if still no slots, we have to add */ - if (ma->texpaintslot) { + if (ma->texpaintslot) { hastex = true; - break; + break; } } else { hastex = true; - break; + break; } } } @@ -5060,7 +5256,7 @@ bool BKE_paint_proj_mesh_data_check(Scene *scene, Object *ob, bool *uvs, bool *m else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) { if (imapaint->canvas == NULL) { hastex = false; - } + } } me = BKE_mesh_from_object(ob); @@ -5141,7 +5337,7 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain) RNA_string_get(op->ptr, "name", imagename); } ima = BKE_image_add_generated(bmain, width, height, imagename, alpha ? 32 : 24, use_float, - gen_type, color); + gen_type, color); return ima; } @@ -5221,7 +5417,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) DAG_id_tag_update(&ma->id, 0); ED_area_tag_redraw(CTX_wm_area(C)); - BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); return true; } @@ -5251,7 +5447,7 @@ static int texture_paint_add_texture_paint_slot_invoke(bContext *C, wmOperator * if (!ma) { ma = BKE_material_add(CTX_data_main(C), "Material"); /* no material found, just assign to first slot */ - assign_material(ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF); + assign_material(ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF); } type = RNA_enum_from_value(layer_type_items, type); @@ -5323,8 +5519,13 @@ static int texture_paint_delete_texture_paint_slot_exec(bContext *C, wmOperator slot = ma->texpaintslot + ma->paint_active_slot; - if (ma->mtex[slot->index]->tex) + if (ma->mtex[slot->index]->tex) { id_us_min(&ma->mtex[slot->index]->tex->id); + + if (ma->mtex[slot->index]->tex->ima) { + id_us_min(&ma->mtex[slot->index]->tex->ima->id); + } + } MEM_freeN(ma->mtex[slot->index]); ma->mtex[slot->index] = NULL; diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index ea5f77acc5b..fac1a05862f 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -106,15 +106,14 @@ static int brush_scale_size_exec(bContext *C, wmOperator *op) const int old_size = BKE_brush_size_get(scene, brush); int size = (int)(scalar * old_size); - if (old_size == size) { + if (abs(old_size - size) < U.pixelsize) { if (scalar > 1) { - size++; + size += U.pixelsize; } else if (scalar < 1) { - size--; + size -= U.pixelsize; } } - CLAMP(size, 1, 2000); // XXX magic number BKE_brush_size_set(scene, brush, size); } @@ -128,6 +127,8 @@ static int brush_scale_size_exec(bContext *C, wmOperator *op) BKE_brush_unprojected_radius_set(scene, brush, unprojected_radius); } + + WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush); } return OPERATOR_FINISHED; diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index bb875d2ef00..d9d0d8f5ef6 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -122,6 +122,10 @@ typedef struct PaintStroke { float zoom_2d; int pen_flip; + + /* line constraint */ + bool constrain_line; + float constrained_pos[2]; StrokeGetLocation get_location; StrokeTestStart test_start; @@ -161,13 +165,25 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata) 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); + if (stroke->constrain_line) { + sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1], + stroke->constrained_pos[0], stroke->constrained_pos[1]); + } + else { + 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 (stroke->constrain_line) { + sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1], + stroke->constrained_pos[0], stroke->constrained_pos[1]); + } + else { + sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1], + x, y); + } glDisable(GL_LINE_STIPPLE); @@ -288,7 +304,7 @@ static bool paint_brush_update(bContext *C, ups->anchored_size = ups->pixel_radius = sqrtf(dx * dx + dy * dy); - ups->brush_rotation = ups->brush_rotation_sec = atan2f(dx, dy) + M_PI; + ups->brush_rotation = ups->brush_rotation_sec = atan2f(dx, dy) + (float)M_PI; if (brush->flag & BRUSH_EDGE_TO_EDGE) { halfway[0] = dx * 0.5f + stroke->initial_mouse[0]; @@ -654,10 +670,11 @@ PaintStroke *paint_stroke_new(bContext *C, 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")) + if (stroke->stroke_mode == BRUSH_STROKE_INVERT) { - RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL); + if (br->flag & (BRUSH_CURVE | BRUSH_LINE)) { + RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL); + } } /* initialize here */ ups->overlap_factor = 1.0; @@ -996,6 +1013,34 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str return false; } +static void paint_stroke_line_constrain (PaintStroke *stroke, float mouse[2]) +{ + if (stroke->constrain_line) { + float line[2]; + float angle, len, res; + + sub_v2_v2v2(line, mouse, stroke->last_mouse_position); + angle = atan2(line[1], line[0]); + len = len_v2(line); + + /* divide angle by PI/4 */ + angle = 4.0f * angle / (float)M_PI; + + /* now take residue */ + res = angle - floorf(angle); + + /* residue decides how close we are at a certain angle */ + if (res <= 0.5f) { + angle = floorf(angle) * (float)M_PI_4; + } + else { + angle = (floorf(angle) + 1.0f) * (float)M_PI_4; + } + + mouse[0] = stroke->constrained_pos[0] = len * cosf(angle) + stroke->last_mouse_position[0]; + mouse[1] = stroke->constrained_pos[1] = len * sinf(angle) + stroke->last_mouse_position[1]; + } +} int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) { @@ -1069,7 +1114,9 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) if (event->type == stroke->event_type && !first_modal) { if (event->val == KM_RELEASE) { - paint_stroke_line_end (C, op, stroke, sample_average.mouse); + copy_v2_fl2(mouse, event->mval[0], event->mval[1]); + paint_stroke_line_constrain(stroke, mouse); + paint_stroke_line_end (C, op, stroke, mouse); stroke_done(C, op); return OPERATOR_FINISHED; } @@ -1079,13 +1126,22 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) stroke_done(C, op); return OPERATOR_FINISHED; } - else if ((br->flag & BRUSH_LINE) && stroke->stroke_started && - (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) - { - if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) { - copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position); + else if (br->flag & BRUSH_LINE) { + if (event->ctrl) + stroke->constrain_line = true; + else + stroke->constrain_line = false; + + copy_v2_fl2(mouse, event->mval[0], event->mval[1]); + paint_stroke_line_constrain(stroke, mouse); + + if (stroke->stroke_started && (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) + { + if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) { + copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position); + } + paint_calculate_rake_rotation(stroke->ups, br, mouse); } - paint_calculate_rake_rotation(stroke->ups, br, sample_average.mouse); } else if (first_modal || /* regular dabs */ diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c index 20e3155c01d..0293a0bfc00 100644 --- a/source/blender/editors/sculpt_paint/paint_undo.c +++ b/source/blender/editors/sculpt_paint/paint_undo.c @@ -210,7 +210,7 @@ static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char * /* pass */ } else { - if (!name || strcmp(stack->current->name, name) == 0) { + if (!name || STREQ(stack->current->name, name)) { if (G.debug & G_DEBUG_WM) { printf("%s: undo '%s'\n", __func__, stack->current->name); } @@ -225,7 +225,7 @@ static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char * /* pass */ } else { - if (!name || strcmp(stack->current->name, name) == 0) { + if (!name || STREQ(stack->current->name, name)) { undo = (stack->current && stack->current->next) ? stack->current->next : stack->elems.first; undo_restore(C, stack, undo); stack->current = undo; @@ -394,7 +394,7 @@ int ED_undo_paint_valid(int type, const char *name) /* pass */ } else { - if (name && strcmp(stack->current->name, name) == 0) + if (name && STREQ(stack->current->name, name)) return 1; else return stack->elems.first != stack->elems.last; diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 9c2c13f9a2d..c0ed5005397 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -177,7 +177,7 @@ float paint_get_tex_pixel(MTex *mtex, float u, float v, struct ImagePool *pool, float co[3] = {u, v, 0.0f}; externtex(mtex, co, &intensity, - rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool); + rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false); return intensity; } @@ -189,7 +189,7 @@ void paint_get_tex_pixel_col(MTex *mtex, float u, float v, float rgba[4], struct float intensity; hasrgb = externtex(mtex, co, &intensity, - rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool); + rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false); if (!hasrgb) { rgba[0] = intensity; rgba[1] = intensity; @@ -373,15 +373,15 @@ static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, c } /* 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) +static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *r_index, unsigned int totpoly) { - if (totface == 0) + if (totpoly == 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) { + if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) { return 0; } @@ -456,7 +456,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr ViewContext vc; const int mval[2] = {x, y}; unsigned int faceindex; - unsigned int totface = me->totface; + unsigned int totpoly = me->totpoly; MTFace *dm_mtface = dm->getTessFaceDataArray(dm, CD_MTFACE); if (dm_mtface) { @@ -464,7 +464,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr view3d_operator_needs_opengl(C); - if (imapaint_pick_face(&vc, mval, &faceindex, totface)) { + if (imapaint_pick_face(&vc, mval, &faceindex, totpoly)) { Image *image; if (use_material) diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index dbb29997102..69428c0f0d7 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -4248,14 +4248,14 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st sculpt_restore_mesh(sd, ob); if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) { - BKE_pbvh_bmesh_detail_size_set(ss->pbvh, - sd->constant_detail / 100.0f); + BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f); } else { - BKE_pbvh_bmesh_detail_size_set(ss->pbvh, - (ss->cache->radius / - (float)ups->pixel_radius) * - (float)sd->detail_size / 0.4f); + BKE_pbvh_bmesh_detail_size_set( + ss->pbvh, + (ss->cache->radius / + (float)ups->pixel_radius) * + (float)(sd->detail_size * U.pixelsize) / 0.4f); } if (sculpt_stroke_dynamic_topology(ss, brush)) { diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 4e9d23d3d97..a4adbc6bca8 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -104,7 +104,7 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo if (unode->maxvert) { /* regular mesh restore */ - if (ss->kb && strcmp(ss->kb->name, unode->shapeName)) { + if (ss->kb && !STREQ(ss->kb->name, unode->shapeName)) { /* shape key has been changed before calling undo operator */ Key *key = BKE_key_from_object(ob); @@ -404,7 +404,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) bool need_mask = false; for (unode = lb->first; unode; unode = unode->next) { - if (strcmp(unode->idname, ob->id.name) == 0) { + if (STREQ(unode->idname, ob->id.name)) { if (unode->type == SCULPT_UNDO_MASK) { /* is possible that we can't do the mask undo (below) * because of the vertex count */ @@ -423,7 +423,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) return; for (unode = lb->first; unode; unode = unode->next) { - if (!(strcmp(unode->idname, ob->id.name) == 0)) + if (!STREQ(unode->idname, ob->id.name)) continue; /* check if undo data matches current data well enough to @@ -550,7 +550,7 @@ static bool sculpt_undo_cleanup(bContext *C, ListBase *lb) unode = lb->first; - if (unode && strcmp(unode->idname, ob->id.name) != 0) { + if (unode && !STREQ(unode->idname, ob->id.name)) { if (unode->bm_entry) BM_log_cleanup_entry(unode->bm_entry); diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index 23bc4a483d3..a9feb9f48de 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -598,7 +598,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm UvEdge *edges; GHash *edgeHash; - GHashIterator *ghi; + GHashIterator gh_iter; bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS); int island_index = 0; @@ -754,21 +754,15 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm uv_sculpt_stroke_exit(C, op); return NULL; } - ghi = BLI_ghashIterator_new(edgeHash); - if (!ghi) { - BLI_ghash_free(edgeHash, NULL, NULL); - MEM_freeN(edges); - uv_sculpt_stroke_exit(C, op); - return NULL; - } + /* fill the edges with data */ - for (i = 0; !BLI_ghashIterator_done(ghi); BLI_ghashIterator_step(ghi)) { - data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi)); + i = 0; + GHASH_ITER (gh_iter, edgeHash) { + data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter)); } data->totalUvEdges = BLI_ghash_size(edgeHash); /* cleanup temporary stuff */ - BLI_ghashIterator_free(ghi); BLI_ghash_free(edgeHash, NULL, NULL); MEM_freeN(edges); diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index d9f4b97fe09..5ce3517696e 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -399,7 +399,7 @@ static bool sound_mixdown_check(bContext *UNUSED(C), wmOperator *op) if (item->value == container) { const char **ext = snd_ext_sound; while (*ext != NULL) { - if (!strcmp(*ext + 1, item->name)) { + if (STREQ(*ext + 1, item->name)) { extension = *ext; break; } @@ -449,9 +449,9 @@ static int sound_mixdown_invoke(bContext *C, wmOperator *op, const wmEvent *even static bool sound_mixdown_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop) { const char *prop_id = RNA_property_identifier(prop); - return !(strcmp(prop_id, "filepath") == 0 || - strcmp(prop_id, "directory") == 0 || - strcmp(prop_id, "filename") == 0); + return !(STREQ(prop_id, "filepath") || + STREQ(prop_id, "directory") || + STREQ(prop_id, "filename")); } static void sound_mixdown_draw(bContext *C, wmOperator *op) diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index a67af289f59..a263f22e072 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -559,7 +559,7 @@ static void template_texture_user_menu(bContext *C, uiLayout *layout, void *UNUS char name[UI_MAX_NAME_STR]; /* add label per category */ - if (!last_category || strcmp(last_category, user->category) != 0) { + if (!last_category || !STREQ(last_category, user->category)) { uiItemL(layout, user->category, ICON_NONE); but = block->buttons.last; but->drawflag = UI_BUT_TEXT_LEFT; diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index f8299a8d335..c32d06cf9b1 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -540,7 +540,7 @@ void uiTemplateMovieclipInformation(uiLayout *layout, PointerRNA *ptr, const cha uiItemL(col, str, ICON_NONE); /* Display current frame number. */ - framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr) ; + framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr); if (framenr <= clip->len) BLI_snprintf(str, sizeof(str), IFACE_("Frame: %d / %d"), framenr, clip->len); else diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index e3d45a297a7..b99b23c60d3 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -1342,7 +1342,8 @@ static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) if (clip->anim) { pj->index_context = IMB_anim_index_rebuild_context(clip->anim, clip->proxy.build_tc_flag, - clip->proxy.build_size_flag, clip->proxy.quality); + clip->proxy.build_size_flag, clip->proxy.quality, + true, NULL); } WM_jobs_customdata_set(wm_job, pj, proxy_freejob); diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c index 2d5e5c6e0f2..8263268898f 100644 --- a/source/blender/editors/space_console/console_ops.c +++ b/source/blender/editors/space_console/console_ops.c @@ -107,7 +107,7 @@ static ConsoleLine *console_history_find(SpaceConsole *sc, const char *str, Cons if (cl == cl_ignore) continue; - if (strcmp(str, cl->line) == 0) + if (STREQ(str, cl->line)) return cl; } @@ -722,7 +722,7 @@ static int console_history_cycle_exec(bContext *C, wmOperator *op) if (ci->prev) { ConsoleLine *ci_prev = (ConsoleLine *)ci->prev; - if (strcmp(ci->line, ci_prev->line) == 0) + if (STREQ(ci->line, ci_prev->line)) console_history_free(sc, ci_prev); } @@ -791,7 +791,7 @@ static int console_history_append_exec(bContext *C, wmOperator *op) while ((cl = console_history_find(sc, ci->line, ci))) console_history_free(sc, cl); - if (strcmp(str, ci->line) == 0) { + if (STREQ(str, ci->line)) { MEM_freeN(str); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 3f3c14d3a7d..57611930e99 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -133,7 +133,8 @@ void file_draw_buttons(const bContext *C, ARegion *ar) loadbutton = 0; } else { - loadbutton = UI_fontstyle_string_width(params->title) + btn_margin; + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + loadbutton = UI_fontstyle_string_width(fstyle, params->title) + btn_margin; CLAMP_MIN(loadbutton, btn_minw); if (available_w <= loadbutton + separator + input_minw) { loadbutton = 0; @@ -238,7 +239,7 @@ static void draw_tile(int sx, int sy, int width, int height, int colorid, int sh static int get_file_icon(struct direntry *file) { if (file->type & S_IFDIR) { - if (strcmp(file->relname, "..") == 0) { + if (FILENAME_IS_PARENT(file->relname)) { return ICON_FILE_PARENT; } if (file->flags & FILE_TYPE_APPLICATIONBUNDLE) { @@ -402,7 +403,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) BLI_strncpy(filename, sfile->params->renameedit, sizeof(filename)); BLI_make_file_string(G.main->name, newname, sfile->params->dir, filename); - if (strcmp(orgname, newname) != 0) { + if (!STREQ(orgname, newname)) { if (!BLI_exists(newname)) { BLI_rename(orgname, newname); /* to make sure we show what is on disk */ @@ -528,7 +529,7 @@ void file_draw_list(const bContext *C, ARegion *ar) int shade = (params->active_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) ? 20 : 0; /* readonly files (".." and ".") must not be drawn as selected - set color back to normal */ - if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) { + if (FILENAME_IS_CURRPAR(file->relname)) { colorid = TH_BACK; } draw_tile(sx, sy - 1, layout->tile_w + 4, sfile->layout->tile_h + layout->tile_border_y, colorid, shade); @@ -537,7 +538,7 @@ void file_draw_list(const bContext *C, ARegion *ar) UI_draw_roundbox_corner_set(UI_CNR_NONE); /* don't drag parent or refresh items */ - do_drag = !(STREQ(file->relname, "..") || STREQ(file->relname, ".")); + do_drag = !(FILENAME_IS_CURRPAR(file->relname)); if (FILE_IMGDISPLAY == params->display) { is_icon = 0; @@ -590,7 +591,7 @@ void file_draw_list(const bContext *C, ARegion *ar) if (params->display == FILE_SHORTDISPLAY) { sx += (int)layout->column_widths[COLUMN_NAME] + column_space; - if (!(file->type & S_IFDIR)) { + if ((BLI_is_dir(file->path) == false) && file->size[0]) { file_draw_string(sx, sy, file->size, layout->column_widths[COLUMN_SIZE], layout->tile_h, align); sx += (int)layout->column_widths[COLUMN_SIZE] + column_space; } @@ -619,7 +620,7 @@ void file_draw_list(const bContext *C, ARegion *ar) file_draw_string(sx, sy, file->time, layout->column_widths[COLUMN_TIME], layout->tile_h, align); sx += (int)layout->column_widths[COLUMN_TIME] + column_space; - if (!(file->type & S_IFDIR)) { + if ((BLI_is_dir(file->path) == false) && file->size[0]) { file_draw_string(sx, sy, file->size, layout->column_widths[COLUMN_SIZE], layout->tile_h, align); sx += (int)layout->column_widths[COLUMN_SIZE] + column_space; } diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 3a579820106..ba6f91e8301 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -183,11 +183,11 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) retval = FILE_SELECT_DIR; } /* the path is too long and we are not going up! */ - else if (strcmp(file->relname, "..") && strlen(params->dir) + strlen(file->relname) >= FILE_MAX) { + else if (!FILENAME_IS_PARENT(file->relname) && strlen(params->dir) + strlen(file->relname) >= FILE_MAX) { // XXX error("Path too long, cannot enter this directory"); } else { - if (strcmp(file->relname, "..") == 0) { + if (FILENAME_IS_PARENT(file->relname)) { /* avoids /../../ */ BLI_parent_dir(params->dir); } @@ -269,7 +269,7 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent * for (idx = sel.last; idx >= 0; idx--) { struct direntry *file = filelist_file(sfile->files, idx); - if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) { + if (FILENAME_IS_CURRPAR(file->relname)) { file->selflag &= ~FILE_SEL_HIGHLIGHTED; } @@ -362,7 +362,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (idx >= 0) { struct direntry *file = filelist_file(sfile->files, idx); - if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) { + if (FILENAME_IS_CURRPAR(file->relname)) { /* skip - If a readonly file (".." or ".") is selected, skip deselect all! */ } else { @@ -1531,7 +1531,7 @@ static int file_rename_poll(bContext *C) if (idx >= 0) { struct direntry *file = filelist_file(sfile->files, idx); - if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) { + if (FILENAME_IS_CURRPAR(file->relname)) { poll = 0; } } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index bcef0817ffe..f0180c3c841 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -237,9 +237,6 @@ typedef struct FileList { bool (*filterf)(struct direntry *, const char *, FileListFilter *); } FileList; -#define FILENAME_IS_BREADCRUMBS(_n) \ - ((_n)[0] == '.' && ((_n)[1] == '\0' || ((_n)[1] == '.' && (_n)[2] == '\0'))) - #define SPECIAL_IMG_SIZE 48 #define SPECIAL_IMG_ROWS 4 #define SPECIAL_IMG_COLS 4 @@ -304,10 +301,10 @@ static int compare_direntry_generic(const struct direntry *entry1, const struct if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1); /* make sure "." and ".." are always first */ - if (strcmp(entry1->relname, ".") == 0) return (-1); - if (strcmp(entry2->relname, ".") == 0) return (1); - if (strcmp(entry1->relname, "..") == 0) return (-1); - if (strcmp(entry2->relname, "..") == 0) return (1); + if (FILENAME_IS_CURRENT(entry1->relname)) return (-1); + if (FILENAME_IS_CURRENT(entry2->relname)) return (1); + if (FILENAME_IS_PARENT(entry1->relname)) return (-1); + if (FILENAME_IS_PARENT(entry2->relname)) return (1); return 0; } @@ -447,7 +444,7 @@ static bool is_filtered_file(struct direntry *file, const char *UNUSED(root), Fi { bool is_filtered = !is_hidden_file(file->relname, filter); - if (is_filtered && filter->filter && !FILENAME_IS_BREADCRUMBS(file->relname)) { + if (is_filtered && filter->filter && !FILENAME_IS_CURRPAR(file->relname)) { if ((file->type & S_IFDIR) && !(filter->filter & FILE_TYPE_FOLDER)) { is_filtered = false; } @@ -471,7 +468,7 @@ static bool is_filtered_lib(struct direntry *file, const char *root, FileListFil if (BLO_is_a_library(root, dir, group)) { is_filtered = !is_hidden_file(file->relname, filter); - if (is_filtered && filter->filter && !FILENAME_IS_BREADCRUMBS(file->relname)) { + if (is_filtered && filter->filter && !FILENAME_IS_CURRPAR(file->relname)) { if (is_filtered && (filter->filter_search[0] != '\0')) { if (fnmatch(filter->filter_search, file->relname, FNM_CASEFOLD) != 0) { is_filtered = false; @@ -634,10 +631,10 @@ ImBuf *filelist_geticon(struct FileList *filelist, const int index) fidx = filelist->fidx[index]; file = &filelist->filelist[fidx]; if (file->type & S_IFDIR) { - if (strcmp(filelist->filelist[fidx].relname, "..") == 0) { + if (FILENAME_IS_PARENT(filelist->filelist[fidx].relname)) { ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT]; } - else if (strcmp(filelist->filelist[fidx].relname, ".") == 0) { + else if (FILENAME_IS_CURRENT(filelist->filelist[fidx].relname)) { ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH]; } else { @@ -764,28 +761,20 @@ struct direntry *filelist_file(struct FileList *filelist, int index) int filelist_find(struct FileList *filelist, const char *filename) { - int index = -1; - int i; int fidx = -1; if (!filelist->fidx) return fidx; - - for (i = 0; i < filelist->numfiles; ++i) { - if (strcmp(filelist->filelist[i].relname, filename) == 0) { /* not dealing with user input so don't need BLI_path_cmp */ - index = i; - break; - } - } + for (fidx = 0; fidx < filelist->numfiltered; fidx++) { + int index = filelist->fidx[fidx]; - for (i = 0; i < filelist->numfiltered; ++i) { - if (filelist->fidx[i] == index) { - fidx = i; - break; + if (STREQ(filelist->filelist[index].relname, filename)) { + return fidx; } } - return fidx; + + return -1; } /* would recognize .blend as well */ @@ -1116,7 +1105,7 @@ static void filelist_from_library(struct FileList *filelist) filelist->filelist = malloc(filelist->numfiles * sizeof(*filelist->filelist)); memset(filelist->filelist, 0, filelist->numfiles * sizeof(*filelist->filelist)); - filelist->filelist[0].relname = BLI_strdup(".."); + filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT); filelist->filelist[0].type |= S_IFDIR; for (i = 0, l = names; i < nnames; i++, l = l->next) { @@ -1191,7 +1180,7 @@ static void filelist_from_main(struct FileList *filelist) filelist->filelist[a].type |= S_IFDIR; } - filelist->filelist[0].relname = BLI_strdup(".."); + filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT); filelist->filelist[1].relname = BLI_strdup("Scene"); filelist->filelist[2].relname = BLI_strdup("Object"); filelist->filelist[3].relname = BLI_strdup("Mesh"); @@ -1244,7 +1233,7 @@ static void filelist_from_main(struct FileList *filelist) if (!filelist->filter_data.hide_parent) { memset(&(filelist->filelist[0]), 0, sizeof(struct direntry)); - filelist->filelist[0].relname = BLI_strdup(".."); + filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT); filelist->filelist[0].type |= S_IFDIR; files++; diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 3e663275dcd..c452f2e1ff4 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -669,7 +669,7 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v)) AutoComplete *autocpl = UI_autocomplete_begin(str, FILE_MAX); while ((de = readdir(dir)) != NULL) { - if (strcmp(".", de->d_name) == 0 || strcmp("..", de->d_name) == 0) { + if (FILENAME_IS_CURRPAR(de->d_name)) { /* pass */ } else { diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index 4ab9bc6a849..05dfdf66ab6 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -283,10 +283,10 @@ void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename) if (!fp) return; while (fgets(line, sizeof(line), fp) != NULL) { /* read a line */ - if (strncmp(line, "[Bookmarks]", 11) == 0) { + if (STREQLEN(line, "[Bookmarks]", 11)) { category = FS_CATEGORY_BOOKMARKS; } - else if (strncmp(line, "[Recent]", 8) == 0) { + else if (STREQLEN(line, "[Recent]", 8)) { category = FS_CATEGORY_RECENT; } else { @@ -359,7 +359,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) continue; FSRefMakePath(&dir, path, FILE_MAX); - if (strcmp((char *)path, "/home") && strcmp((char *)path, "/net")) { + if (!STREQ((char *)path, "/home") && !STREQ((char *)path, "/net")) { /* /net and /home are meaningless on OSX, home folders are stored in /Users */ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, (char *)path, FS_INSERT_SORTED); } @@ -488,7 +488,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks) else { while ((mnt = getmntent(fp))) { /* not sure if this is right, but seems to give the relevant mnts */ - if (strncmp(mnt->mnt_fsname, "/dev", 4)) + if (!STREQLEN(mnt->mnt_fsname, "/dev", 4)) continue; len = strlen(mnt->mnt_dir); diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 9093734f25f..2d8a0a3da29 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -848,11 +848,13 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu) * NOTE: we need to scale the y-values to be valid for the units */ glBegin(GL_LINES); + { t = v2d->cur.xmin; glVertex2f(t, t * unitfac); t = v2d->cur.xmax; glVertex2f(t, t * unitfac); + } glEnd(); /* cleanup line drawing */ @@ -875,6 +877,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu) setlinestyle(5); glBegin(GL_LINES); + { /* x-axis lookup */ co[0] = x; @@ -894,6 +897,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu) co[0] = x; glVertex2fv(co); + } glEnd(); setlinestyle(0); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index b87f80c4e62..2944901663b 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -1721,7 +1721,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op) * so if the paths or the ID's don't match up, then a curve needs to be added * to a new group */ - if ((euf) && (euf->id == ale->id) && (strcmp(euf->rna_path, fcu->rna_path) == 0)) { + if ((euf) && (euf->id == ale->id) && (STREQ(euf->rna_path, fcu->rna_path))) { /* this should be fine to add to the existing group then */ euf->fcurves[fcu->array_index] = fcu; } diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 78dbae7618b..46a39806ad7 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -66,6 +66,15 @@ /* ************************************************************************** */ /* KEYFRAMES STUFF */ +static void graphkeys_auto_view(bContext *C) +{ + const SpaceIpo *sipo = CTX_wm_space_graph(C); + + if (sipo && sipo->flag & SIPO_AUTO_VIEW_SELECTED) { + WM_operator_name_call(C, "GRAPH_OT_view_selected", WM_OP_INVOKE_DEFAULT, NULL); + } +} + /* ******************** Deselect All Operator ***************************** */ /* This operator works in one of three ways: * 1) (de)select all (AKEY) - test if select all or deselect all @@ -83,7 +92,7 @@ * 2 = invert * - do_channels: whether to affect selection status of channels */ -static void deselect_graph_keys(bAnimContext *ac, short test, short sel, short do_channels) +static short deselect_graph_keys(bAnimContext *ac, short test, short sel, short do_channels) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; @@ -142,6 +151,8 @@ static void deselect_graph_keys(bAnimContext *ac, short test, short sel, short d /* Cleanup */ ANIM_animdata_freelist(&anim_data); + + return sel; } /* ------------------- */ @@ -150,6 +161,7 @@ static int graphkeys_deselectall_exec(bContext *C, wmOperator *op) { bAnimContext ac; bAnimListElem *ale_active = NULL; + short sel; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) @@ -163,9 +175,9 @@ static int graphkeys_deselectall_exec(bContext *C, wmOperator *op) /* 'standard' behavior - check if selected, then apply relevant selection */ if (RNA_boolean_get(op->ptr, "invert")) - deselect_graph_keys(&ac, 0, SELECT_INVERT, true); + sel = deselect_graph_keys(&ac, 0, SELECT_INVERT, true); else - deselect_graph_keys(&ac, 1, SELECT_ADD, true); + sel = deselect_graph_keys(&ac, 1, SELECT_ADD, true); /* restore active F-Curve... */ if (ale_active) { @@ -180,6 +192,9 @@ static int graphkeys_deselectall_exec(bContext *C, wmOperator *op) ale_active = NULL; } + if (sel != SELECT_SUBTRACT) + graphkeys_auto_view(C); + /* set notifier that things have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -374,6 +389,8 @@ static int graphkeys_borderselect_exec(bContext *C, wmOperator *op) /* apply borderselect action */ borderselect_graphkeys(&ac, &rect_fl, mode, selectmode, incl_handles, NULL); + graphkeys_auto_view(C); + /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -461,6 +478,8 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) MEM_freeN((void *)data_lasso.mcords); + graphkeys_auto_view(C); + /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -491,6 +510,14 @@ void GRAPH_OT_select_lasso(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); } +static int graph_circle_select_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (event->type == EVT_MODAL_MAP && event->val == GESTURE_MODAL_NOP) + graphkeys_auto_view(C); + + return WM_gesture_circle_modal(C, op, event); +} + static int graph_circle_select_exec(bContext *C, wmOperator *op) { bAnimContext ac; @@ -552,7 +579,7 @@ void GRAPH_OT_select_circle(wmOperatorType *ot) ot->idname = "GRAPH_OT_select_circle"; ot->invoke = WM_gesture_circle_invoke; - ot->modal = WM_gesture_circle_modal; + ot->modal = graph_circle_select_modal; ot->exec = graph_circle_select_exec; ot->poll = graphop_visible_keyframes_poll; ot->cancel = WM_gesture_circle_cancel; @@ -725,6 +752,8 @@ static int graphkeys_columnselect_exec(bContext *C, wmOperator *op) else columnselect_graph_keys(&ac, mode); + graphkeys_auto_view(C); + /* set notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -783,6 +812,8 @@ static int graphkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op)) /* Cleanup */ ANIM_animdata_freelist(&anim_data); + graphkeys_auto_view(C); + /* set notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -807,12 +838,13 @@ void GRAPH_OT_select_linked(wmOperatorType *ot) /* ******************** Select More/Less Operators *********************** */ /* Common code to perform selection */ -static void select_moreless_graph_keys(bAnimContext *ac, short mode) +static void select_moreless_graph_keys(bContext *C, bAnimContext *ac, short mode) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; int filter; + const SpaceIpo *sipo = (SpaceIpo *)ac->sl; KeyframeEditData ked; KeyframeEditFunc build_cb; @@ -842,6 +874,24 @@ static void select_moreless_graph_keys(bAnimContext *ac, short mode) /* free the selmap used here */ MEM_freeN(ked.data); ked.data = NULL; + + /* only do auto view if a bezier point is selected */ + if (sipo->flag & SIPO_AUTO_VIEW_SELECTED) { + const FCurve *fcu = (FCurve *)ale->key_data; + const BezTriple *bezt; + unsigned int i; + + /* only continue if F-Curve has keyframes */ + if (fcu->bezt == NULL) + continue; + + for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) { + if (BEZSELECTED(bezt)) { + graphkeys_auto_view(C); + break; + } + } + } } /* Cleanup */ @@ -859,7 +909,7 @@ static int graphkeys_select_more_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; /* perform select changes */ - select_moreless_graph_keys(&ac, SELMAP_MORE); + select_moreless_graph_keys(C, &ac, SELMAP_MORE); /* set notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -893,7 +943,7 @@ static int graphkeys_select_less_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; /* perform select changes */ - select_moreless_graph_keys(&ac, SELMAP_LESS); + select_moreless_graph_keys(C, &ac, SELMAP_LESS); /* set notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -1008,6 +1058,8 @@ static int graphkeys_select_leftright_exec(bContext *C, wmOperator *op) /* do the selecting now */ graphkeys_select_leftright(&ac, leftright, selectmode); + graphkeys_auto_view(C); + /* set notifier that keyframe selection (and channels too) have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL); diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 05868283b2e..fb3c140fddf 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -64,6 +64,7 @@ #include "image_intern.h" #define B_NOP -1 +#define MAX_IMAGE_INFO_LEN 128 /* proto */ @@ -640,8 +641,6 @@ static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg)) void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *userptr, int compact) { -#define MAX_INFO_LEN 128 - PropertyRNA *prop; PointerRNA imaptr; RNAUpdateCb *cb; @@ -650,7 +649,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char Scene *scene = CTX_data_scene(C); uiLayout *row, *split, *col; uiBlock *block; - char str[MAX_INFO_LEN]; + char str[MAX_IMAGE_INFO_LEN]; void *lock; @@ -687,14 +686,14 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char uiLayoutSetContextPointer(layout, "edit_image_user", userptr); if (!compact) - uiTemplateID(layout, C, ptr, propname, "IMAGE_OT_new", "IMAGE_OT_open", NULL); + uiTemplateID(layout, C, ptr, propname, ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL); if (ima) { UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL); if (ima->source == IMA_SRC_VIEWER) { ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); - image_info(scene, iuser, ima, ibuf, str, MAX_INFO_LEN); + image_info(scene, iuser, ima, ibuf, str, MAX_IMAGE_INFO_LEN); BKE_image_release_ibuf(ima, ibuf, lock); uiItemL(layout, ima->id.name + 2, ICON_NONE); @@ -763,10 +762,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char } else if (ima->source != IMA_SRC_GENERATED) { if (compact == 0) { - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); - image_info(scene, iuser, ima, ibuf, str, MAX_INFO_LEN); - BKE_image_release_ibuf(ima, ibuf, lock); - uiItemL(layout, str, ICON_NONE); + uiTemplateImageInfo(layout, C, ima, iuser); } } @@ -780,7 +776,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char bool has_alpha = true; if (ibuf) { - int imtype = BKE_ftype_to_imtype(ibuf->ftype); + int imtype = BKE_image_ftype_to_imtype(ibuf->ftype); char valid_channels = BKE_imtype_valid_channels(imtype, false); has_alpha = (valid_channels & IMA_CHAN_FLAG_ALPHA) != 0; @@ -791,7 +787,14 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char if (has_alpha) { col = uiLayoutColumn(layout, false); uiItemR(col, &imaptr, "use_alpha", 0, NULL, ICON_NONE); - uiItemR(col, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE); + row = uiLayoutRow(col, false); + uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_alpha")); + uiItemR(row, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE); + } + + if (ima->source == IMA_SRC_MOVIE) { + col = uiLayoutColumn(layout, false); + uiItemR(col, &imaptr, "use_deinterlace", 0, IFACE_("Deinterlace"), ICON_NONE); } uiItemS(layout); @@ -856,8 +859,6 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char } MEM_freeN(cb); - -#undef MAX_INFO_LEN } void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_management) @@ -977,6 +978,24 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser } } +void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *iuser) +{ + ImBuf *ibuf; + char str[MAX_IMAGE_INFO_LEN]; + void *lock; + + if (!ima || !iuser) + return; + + ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock); + + image_info(CTX_data_scene(C), iuser, ima, ibuf, str, MAX_IMAGE_INFO_LEN); + BKE_image_release_ibuf(ima, ibuf, lock); + uiItemL(layout, str, ICON_NONE); +} + +#undef MAX_IMAGE_INFO_LEN + void image_buttons_register(ARegionType *UNUSED(art)) { diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index 757059ebc29..8e2c6b97a5b 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -35,6 +35,7 @@ #include "BLI_rect.h" +#include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_image.h" @@ -290,6 +291,20 @@ void ED_image_point_pos__reverse(SpaceImage *sima, ARegion *ar, const float co[2 r_co[1] = (co[1] * height * zoomy) + (float)sy; } +void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *sima, struct ImBuf *ibuf, bool use_view_settings) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + + /* scope update can be expensive, don't update during paint modes */ + if (sima->mode == SI_MODE_PAINT) + return; + if (ob && ((ob->mode & OB_MODE_TEXTURE_PAINT) != 0)) + return; + + scopes_update(&sima->scopes, ibuf, use_view_settings ? &scene->view_settings : NULL, &scene->display_settings); +} + bool ED_space_image_show_render(SpaceImage *sima) { return (sima->image && ELEM(sima->image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 6cf53533618..af1502509f5 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -899,9 +899,9 @@ static void image_tools_area_draw(const bContext *C, ARegion *ar) BKE_histogram_update_sample_line(&sima->sample_line_hist, ibuf, &scene->view_settings, &scene->display_settings); } if (sima->image->flag & IMA_VIEW_AS_RENDER) - scopes_update(&sima->scopes, ibuf, &scene->view_settings, &scene->display_settings); + ED_space_image_scopes_update(C, sima, ibuf, true); else - scopes_update(&sima->scopes, ibuf, NULL, &scene->display_settings); + ED_space_image_scopes_update(C, sima, ibuf, false); } } ED_space_image_release_buffer(sima, ibuf, lock); diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c index 62703ba517e..2c6280f5670 100644 --- a/source/blender/editors/space_logic/logic_ops.c +++ b/source/blender/editors/space_logic/logic_ops.c @@ -39,6 +39,8 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLF_translation.h" + #include "BKE_context.h" #include "BKE_main.h" #include "BKE_sca.h" @@ -298,7 +300,7 @@ static int sensor_add_exec(bContext *C, wmOperator *op) BLI_strncpy(sens->name, sens_name, sizeof(sens->name)); } - make_unique_prop_names(C, sens->name); + BLI_uniquename(&ob->sensors, sens, DATA_("Sensor"), '.', offsetof(bSensor, name), sizeof(sens->name)); ob->scaflag |= OB_SHOWSENS; WM_event_add_notifier(C, NC_LOGIC, NULL); @@ -405,7 +407,8 @@ static int controller_add_exec(bContext *C, wmOperator *op) BLI_strncpy(cont->name, cont_name, sizeof(cont->name)); } - make_unique_prop_names(C, cont->name); + BLI_uniquename(&ob->controllers, cont, DATA_("Controller"), '.', offsetof(bController, name), sizeof(cont->name)); + /* set the controller state mask from the current object state. * A controller is always in a single state, so select the lowest bit set * from the object state */ @@ -523,7 +526,7 @@ static int actuator_add_exec(bContext *C, wmOperator *op) BLI_strncpy(act->name, act_name, sizeof(act->name)); } - make_unique_prop_names(C, act->name); + BLI_uniquename(&ob->actuators, act, DATA_("Actuator"), '.', offsetof(bActuator, name), sizeof(act->name)); ob->scaflag |= OB_SHOWACT; WM_event_add_notifier(C, NC_LOGIC, NULL); diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 21a9246d7e6..37c634672df 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -48,6 +48,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_path_util.h" #include "BKE_action.h" #include "BKE_context.h" @@ -94,87 +95,6 @@ /* proto */ static ID **get_selected_and_linked_obs(bContext *C, short *count, short scavisflag); -static int vergname(const void *v1, const void *v2) -{ - const char * const *x1 = v1, * const *x2 = v2; - return BLI_natstrcmp(*x1, *x2); -} - -void make_unique_prop_names(bContext *C, char *str) -{ - Object *ob; - bProperty *prop; - bSensor *sens; - bController *cont; - bActuator *act; - ID **idar; - short a, obcount, propcount=0, nr; - const char **names; - - /* this function is called by a Button, and gives the current - * stringpointer as an argument, this is the one that can change - */ - - idar= get_selected_and_linked_obs(C, &obcount, BUTS_SENS_SEL|BUTS_SENS_ACT|BUTS_ACT_SEL|BUTS_ACT_ACT|BUTS_CONT_SEL|BUTS_CONT_ACT); - - /* for each object, make properties and sca names unique */ - - /* count total names */ - for (a=0; a<obcount; a++) { - ob= (Object *)idar[a]; - propcount+= BLI_listbase_count(&ob->prop); - propcount+= BLI_listbase_count(&ob->sensors); - propcount+= BLI_listbase_count(&ob->controllers); - propcount+= BLI_listbase_count(&ob->actuators); - } - if (propcount==0) { - if (idar) MEM_freeN(idar); - return; - } - - /* make names array for sorting */ - names= MEM_callocN(propcount*sizeof(void *), "names"); - - /* count total names */ - nr= 0; - for (a=0; a<obcount; a++) { - ob= (Object *)idar[a]; - prop= ob->prop.first; - while (prop) { - names[nr++] = prop->name; - prop= prop->next; - } - sens= ob->sensors.first; - while (sens) { - names[nr++] = sens->name; - sens= sens->next; - } - cont= ob->controllers.first; - while (cont) { - names[nr++] = cont->name; - cont= cont->next; - } - act= ob->actuators.first; - while (act) { - names[nr++] = act->name; - act= act->next; - } - } - - qsort(names, propcount, sizeof(void *), vergname); - - /* now we check for double names, and change them */ - - for (nr=0; nr<propcount; nr++) { - if (names[nr]!=str && strcmp( names[nr], str )==0 ) { - BLI_newname(str, +1); - } - } - - MEM_freeN(idar); - MEM_freeN(names); -} - static void do_logic_buts(bContext *C, void *UNUSED(arg), int event) { Main *bmain= CTX_data_main(C); @@ -206,7 +126,7 @@ static void do_logic_buts(bContext *C, void *UNUSED(arg), int event) ob->scaflag &= ~OB_ADDSENS; sens= new_sensor(SENS_ALWAYS); BLI_addtail(&(ob->sensors), sens); - make_unique_prop_names(C, sens->name); + BLI_uniquename(&ob->sensors, sens, DATA_("Sensor"), '.', offsetof(bSensor, name), sizeof(sens->name)); ob->scaflag |= OB_SHOWSENS; } } @@ -248,7 +168,7 @@ static void do_logic_buts(bContext *C, void *UNUSED(arg), int event) if (ob->scaflag & OB_ADDCONT) { ob->scaflag &= ~OB_ADDCONT; cont= new_controller(CONT_LOGIC_AND); - make_unique_prop_names(C, cont->name); + BLI_uniquename(&ob->controllers, cont, DATA_("Controller"), '.', offsetof(bController, name), sizeof(cont->name)); ob->scaflag |= OB_SHOWCONT; BLI_addtail(&(ob->controllers), cont); /* set the controller state mask from the current object state. @@ -324,7 +244,7 @@ static void do_logic_buts(bContext *C, void *UNUSED(arg), int event) if (ob->scaflag & OB_ADDACT) { ob->scaflag &= ~OB_ADDACT; act= new_actuator(ACT_OBJECT); - make_unique_prop_names(C, act->name); + BLI_uniquename(&ob->actuators, act, DATA_("Actuator"), '.', offsetof(bActuator, name), sizeof(act->name)); BLI_addtail(&(ob->actuators), act); ob->scaflag |= OB_SHOWACT; } diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index 0abe5e42c3e..5476d1c2683 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -650,7 +650,7 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; /* get a list of the AnimData blocks being shown in the NLA */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL); + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); /* delete tracks */ diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index c45626e4284..2089dced7e3 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -38,6 +38,7 @@ #include "DNA_space_types.h" #include "DNA_screen_types.h" #include "DNA_userdef_types.h" +#include "DNA_text_types.h" #include "BKE_context.h" #include "BKE_curve.h" @@ -389,6 +390,7 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp float width, ascender; float x, y; const int font_size = data->label_size / aspect; + const float margin = (float)(NODE_DY / 4); nodeLabel(ntree, node, label, sizeof(label)); @@ -404,11 +406,42 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp /* 'x' doesn't need aspect correction */ x = BLI_rctf_cent_x(rct) - (0.5f * width); - y = rct->ymax - (((NODE_DY / 4) / aspect) + (ascender * aspect)); + y = rct->ymax - ((margin / aspect) + (ascender * aspect)); BLF_position(fontid, x, y, 0); BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX); + /* draw text body */ + if (node->id) { + Text *text = (Text *)node->id; + TextLine *line; + const float line_spacing = (BLF_height_max(fontid) * aspect) * 0.7f; + + /* 'x' doesn't need aspect correction */ + x = rct->xmin + margin; + y = rct->ymax - ((margin / aspect) + (ascender * aspect)); + y -= line_spacing; + + BLF_enable(fontid, BLF_CLIPPING); + BLF_clipping( + fontid, + rct->xmin, + rct->ymin, + rct->xmin + ((rct->xmax - rct->xmin) / aspect) - margin, + rct->ymax); + + for (line = text->lines.first; line; line = line->next) { + BLF_position(fontid, x, y, 0); + BLF_draw(fontid, line->line, line->len); + y -= line_spacing; + if (y < rct->ymin) { + break; + } + } + + BLF_disable(fontid, BLF_CLIPPING); + } + BLF_disable(fontid, BLF_ASPECT); } @@ -498,6 +531,7 @@ static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA { uiItemR(layout, ptr, "label_size", 0, IFACE_("Label Size"), ICON_NONE); uiItemR(layout, ptr, "shrink", 0, IFACE_("Shrink"), ICON_NONE); + uiItemR(layout, ptr, "text", 0, NULL, ICON_NONE); } @@ -669,10 +703,10 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr, uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE); } - col = uiLayoutColumn(layout, false); - - if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER) + if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER) { + col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE); + } } static void node_shader_buts_material(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -805,10 +839,51 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin uiLayoutSetContextPointer(layout, "image_user", &iuserptr); uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); + + node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr); + uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); +} - node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr); +static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) +{ + PointerRNA imaptr = RNA_pointer_get(ptr, "image"); + PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user"); + Image *ima = imaptr.data; + + uiLayoutSetContextPointer(layout, "image_user", &iuserptr); + uiTemplateID(layout, C, ptr, "image", ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL); + + if (!ima) + return; + + uiItemR(layout, &imaptr, "source", 0, IFACE_("Source"), ICON_NONE); + + if (!(ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER))) { + uiLayout *row = uiLayoutRow(layout, true); + + if (ima->packedfile) + uiItemO(row, "", ICON_PACKAGE, "image.unpack"); + else + uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack"); + + row = uiLayoutRow(row, true); + uiLayoutSetEnabled(row, ima->packedfile == NULL); + uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE); + uiItemO(row, "", ICON_FILE_REFRESH, "image.reload"); + } + + /* multilayer? */ + if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) { + uiTemplateImageLayers(layout, C, ima, iuserptr.data); + } + else if (ima->source != IMA_SRC_GENERATED) { + uiTemplateImageInfo(layout, C, ima, iuserptr.data); + } + + uiItemR(layout, ptr, "color_space", 0, IFACE_("Color Space"), ICON_NONE); + uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE); } static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -861,6 +936,7 @@ static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { + uiItemR(layout, ptr, "object", 0, NULL, 0); uiItemR(layout, ptr, "from_dupli", 0, NULL, 0); } @@ -1071,6 +1147,7 @@ static void node_shader_set_butfunc(bNodeType *ntype) break; case SH_NODE_TEX_ENVIRONMENT: ntype->draw_buttons = node_shader_buts_tex_environment; + ntype->draw_buttons_ex = node_shader_buts_tex_environment_ex; break; case SH_NODE_TEX_GRADIENT: ntype->draw_buttons = node_shader_buts_tex_gradient; @@ -2279,6 +2356,7 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr) { bNode *node = ptr->data; + NodePlaneTrackDeformData *data = node->storage; uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL); @@ -2307,6 +2385,12 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA); } } + + uiItemR(layout, ptr, "use_motion_blur", 0, NULL, ICON_NONE); + if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) { + uiItemR(layout, ptr, "motion_blur_samples", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "motion_blur_shutter", 0, NULL, ICON_NONE); + } } static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout), bContext *UNUSED(C), PointerRNA *UNUSED(ptr)) @@ -3053,9 +3137,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b /* somehow the offset has to be calculated inverse */ glaDefine2DArea(&ar->winrct); - /* ortho at pixel level curarea */ - /* almost #wmOrtho2_region_pixelspace, but no +1 px */ - wmOrtho2_pixelspace(ar->winx, ar->winy); + wmOrtho2_region_pixelspace(ar); x = (ar->winx - snode->zoom * ibuf->x) / 2 + snode->xof; y = (ar->winy - snode->zoom * ibuf->y) / 2 + snode->yof; diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 16ad63bcafa..87a64e95e63 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -1304,6 +1304,11 @@ void drawnodespace(const bContext *C, ARegion *ar) path = snode->treepath.last; + /* update tree path name (drawn in the bottom left) */ + if (snode->id && UNLIKELY(!STREQ(path->node_name, snode->id->name + 2))) { + BLI_strncpy(path->node_name, snode->id->name + 2, sizeof(path->node_name)); + } + /* current View2D center, will be set temporarily for parent node trees */ UI_view2d_center_get(v2d, ¢er[0], ¢er[1]); diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 1e258368b8b..f79d6e26f22 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -566,7 +566,7 @@ void snode_set_context(const bContext *C) return; } - if (snode->nodetree && strcmp(snode->nodetree->idname, snode->tree_idname) != 0) { + if (snode->nodetree && !STREQ(snode->nodetree->idname, snode->tree_idname)) { /* current tree does not match selected type, clear tree path */ ntree = NULL; id = NULL; diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index e3baddef158..62cb0bc73cd 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -668,7 +668,7 @@ static void node_main_area_draw(const bContext *C, ARegion *ar) static int node_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_ID) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; if (GS(id->name) == ID_IM) return 1; } @@ -682,7 +682,7 @@ static int node_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent * static int node_mask_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_ID) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; if (GS(id->name) == ID_MSK) return 1; } @@ -691,14 +691,14 @@ static int node_mask_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent static void node_id_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; RNA_string_set(drop->ptr, "name", id->name + 2); } static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; if (id) { RNA_string_set(drop->ptr, "name", id->name + 2); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 9bc043b384e..47bf87b360b 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -31,6 +31,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" +#include "DNA_gpencil_types.h" #include "DNA_group_types.h" #include "DNA_lamp_types.h" #include "DNA_object_types.h" @@ -346,6 +347,11 @@ static void restrictbutton_ebone_visibility_cb(bContext *C, void *UNUSED(poin), WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); } +static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), void *UNUSED(poin2)) +{ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); +} + static int group_restrict_flag(Group *gr, int flag) { GroupObject *gob; @@ -447,7 +453,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) TreeStoreElem *tselem = tsep; if (ts && tselem) { - TreeElement *te = outliner_find_tse(soops, tselem); + TreeElement *te = outliner_find_tree_element(&soops->tree, tselem); if (tselem->type == 0) { test_idbutton(tselem->id->name); // library.c, unique name and alpha sort @@ -549,6 +555,17 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); break; } + case TSE_GP_LAYER: + { + bGPdata *gpd = (bGPdata *)tselem->id; // id = GP Datablock + bGPDlayer *gpl = te->directdata; + + // XXX: name needs translation stuff + BLI_uniquename(&gpd->layers, gpl, "GP Layer", '.', + offsetof(bGPDlayer, info), sizeof(gpl->info)); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, gpd); + break; + } case TSE_R_LAYER: break; } @@ -742,6 +759,29 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar UI_block_emboss_set(block, UI_EMBOSS); } + else if (tselem->type == TSE_GP_LAYER) { + bGPDlayer *gpl = (bGPDlayer *)te->directdata; + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + + bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_HIDE, 0, ICON_RESTRICT_VIEW_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0, + TIP_("Restrict/Allow visibility in the 3D View")); + UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, NULL, gpl); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + + bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_LOCKED, 0, ICON_UNLOCKED, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0, + TIP_("Restrict/Allow editing of strokes and keyframes in this layer")); + UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, NULL, gpl); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + + /* TODO: visibility in renders */ + + UI_block_emboss_set(block, UI_EMBOSS); + } } if (TSELEM_OPEN(tselem, soops)) outliner_draw_restrictbuts(block, scene, ar, soops, &te->subtree); @@ -877,6 +917,36 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon) } +static void tselem_draw_gp_icon_uibut(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl) +{ + /* restrict column clip - skip it for now... */ + if (arg->x >= arg->xmax) { + /* pass */ + } + else { + PointerRNA ptr; + float w = 0.85f * U.widget_unit; + float h = 0.85f * UI_UNIT_Y; + + RNA_pointer_create(id, &RNA_GPencilLayer, gpl, &ptr); + + UI_block_align_begin(arg->block); + + UI_block_emboss_set(arg->block, RNA_boolean_get(&ptr, "is_stroke_visible") ? UI_EMBOSS : UI_EMBOSS_NONE); + uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb, arg->yb, w, h, + &ptr, "color", -1, + 0, 0, 0, 0, NULL); + + UI_block_emboss_set(arg->block, RNA_boolean_get(&ptr, "is_fill_visible") ? UI_EMBOSS : UI_EMBOSS_NONE); + uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb, arg->yb, w, h, + &ptr, "fill_color", -1, + 0, 0, 0, 0, NULL); + + UI_block_emboss_set(arg->block, UI_EMBOSS_NONE); + UI_block_align_end(arg->block); + } +} + static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te, float alpha) { @@ -1020,6 +1090,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */ case eModifierType_DataTransfer: UI_icon_draw(x, y, ICON_MOD_DATA_TRANSFER); break; + case eModifierType_NormalEdit: + UI_icon_draw(x, y, ICON_MOD_NORMALEDIT); break; case eModifierType_PointCache: UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */ /* Default */ @@ -1074,6 +1146,9 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto else UI_icon_draw(x, y, RNA_struct_ui_icon(te->rnaptr.type)); break; + case TSE_GP_LAYER: + tselem_draw_gp_icon_uibut(&arg, tselem->id, te->directdata); + break; default: UI_icon_draw(x, y, ICON_DOT); break; } @@ -1167,6 +1242,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); break; case ID_LS: tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break; + case ID_GD: + tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break; } } } @@ -1250,8 +1327,9 @@ static void outliner_set_coord_tree_element(SpaceOops *soops, TreeElement *te, i } -static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops, - TreeElement *te, int startx, int *starty, TreeElement **te_edit) +static void outliner_draw_tree_element( + bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ARegion *ar, SpaceOops *soops, + TreeElement *te, int startx, int *starty, TreeElement **te_edit) { TreeElement *ten; TreeStoreElem *tselem; @@ -1410,9 +1488,9 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f); else UI_ThemeColor(TH_TEXT); - UI_draw_string(startx + offsx, *starty + 5 * ufac, te->name); + UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name); - offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(te->name)); + offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name)); /* closed item, we draw the icons, not when it's a scene, or master-server list though */ if (!TSELEM_OPEN(tselem, soops)) { @@ -1450,13 +1528,15 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene if (TSELEM_OPEN(tselem, soops)) { *starty -= UI_UNIT_Y; - - for (ten = te->subtree.first; ten; ten = ten->next) - outliner_draw_tree_element(C, block, scene, ar, soops, ten, startx + UI_UNIT_X, starty, te_edit); + + for (ten = te->subtree.first; ten; ten = ten->next) { + outliner_draw_tree_element(C, block, fstyle, scene, ar, soops, ten, startx + UI_UNIT_X, starty, te_edit); + } } else { - for (ten = te->subtree.first; ten; ten = ten->next) + for (ten = te->subtree.first; ten; ten = ten->next) { outliner_set_coord_tree_element(soops, ten, startx, *starty); + } *starty -= UI_UNIT_Y; } @@ -1539,6 +1619,7 @@ static void outliner_draw_selection(ARegion *ar, SpaceOops *soops, ListBase *lb, static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops, TreeElement **te_edit) { + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; TreeElement *te; int starty, startx; float col[3]; @@ -1569,7 +1650,7 @@ static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegio starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; startx = 0; for (te = soops->tree.first; te; te = te->next) { - outliner_draw_tree_element(C, block, scene, ar, soops, te, startx, &starty, te_edit); + outliner_draw_tree_element(C, block, fstyle, scene, ar, soops, te, startx, &starty, te_edit); } } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index ab7b1583275..d17ab33d0fa 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -50,6 +50,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_material.h" +#include "BKE_group.h" #include "ED_object.h" #include "ED_screen.h" @@ -73,22 +74,6 @@ /* This is not used anywhere at the moment */ #if 0 -/* return 1 when levels were opened */ -static int outliner_open_back(SpaceOops *soops, TreeElement *te) -{ - TreeStoreElem *tselem; - int retval = 0; - - for (te = te->parent; te; te = te->parent) { - tselem = TREESTORE(te); - if (tselem->flag & TSE_CLOSED) { - tselem->flag &= ~TSE_CLOSED; - retval = 1; - } - } - return retval; -} - static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *teFind, int *found) { TreeElement *te; @@ -113,7 +98,9 @@ static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *te } #endif -static TreeElement *outliner_dropzone_element(const SpaceOops *soops, TreeElement *te, const float fmval[2], const int children) +static TreeElement *outliner_dropzone_element( + const SpaceOops *soops, TreeElement *te, + const float fmval[2], const bool children) { if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) { /* name and first icon */ @@ -132,7 +119,7 @@ static TreeElement *outliner_dropzone_element(const SpaceOops *soops, TreeElemen } /* Used for drag and drop parenting */ -TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2], const int children) +TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2], const bool children) { TreeElement *te; @@ -601,6 +588,50 @@ void OUTLINER_OT_selected_toggle(wmOperatorType *ot) /* Show Active --------------------------------------------------- */ +static void outliner_set_coordinates_element_recursive(SpaceOops *soops, TreeElement *te, int startx, int *starty) +{ + TreeStoreElem *tselem = TREESTORE(te); + + /* store coord and continue, we need coordinates for elements outside view too */ + te->xs = (float)startx; + te->ys = (float)(*starty); + *starty -= UI_UNIT_Y; + + if (TSELEM_OPEN(tselem, soops)) { + TreeElement *ten; + for (ten = te->subtree.first; ten; ten = ten->next) { + outliner_set_coordinates_element_recursive(soops, ten, startx + UI_UNIT_X, starty); + } + } +} + +/* to retrieve coordinates with redrawing the entire tree */ +static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops) +{ + TreeElement *te; + int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y; + + for (te = soops->tree.first; te; te = te->next) { + outliner_set_coordinates_element_recursive(soops, te, 0, &starty); + } +} + +/* return 1 when levels were opened */ +static int outliner_open_back(TreeElement *te) +{ + TreeStoreElem *tselem; + int retval = 0; + + for (te = te->parent; te; te = te->parent) { + tselem = TREESTORE(te); + if (tselem->flag & TSE_CLOSED) { + tselem->flag &= ~TSE_CLOSED; + retval = 1; + } + } + return retval; +} + static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceOops *so = CTX_wm_space_outliner(C); @@ -617,6 +648,11 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op)) te = outliner_find_id(so, &so->tree, (ID *)OBACT); if (te) { + /* open up tree to active object */ + if (outliner_open_back(te)) { + outliner_set_coordinates(ar, so); + } + /* make te->ys center of view */ ytop = te->ys + BLI_rcti_size_y(&v2d->mask) / 2; if (ytop > 0) ytop = 0; @@ -642,7 +678,7 @@ void OUTLINER_OT_show_active(wmOperatorType *ot) /* identifiers */ ot->name = "Show Active"; ot->idname = "OUTLINER_OT_show_active"; - ot->description = "Adjust the view so that the active Object is shown centered"; + ot->description = "Open up the tree and adjust the view so that the active Object is shown centered"; /* callbacks */ ot->exec = outliner_show_active_exec; @@ -690,37 +726,6 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot) #if 0 -/* recursive helper for function below */ -static void outliner_set_coordinates_element(SpaceOops *soops, TreeElement *te, int startx, int *starty) -{ - TreeStoreElem *tselem = TREESTORE(te); - - /* store coord and continue, we need coordinates for elements outside view too */ - te->xs = (float)startx; - te->ys = (float)(*starty); - *starty -= UI_UNIT_Y; - - if (TSELEM_OPEN(tselem, soops)) { - TreeElement *ten; - for (ten = te->subtree.first; ten; ten = ten->next) { - outliner_set_coordinates_element(soops, ten, startx + UI_UNIT_X, starty); - } - } - -} - -/* to retrieve coordinates with redrawing the entire tree */ -static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops) -{ - TreeElement *te; - int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y; - int startx = 0; - - for (te = soops->tree.first; te; te = te->next) { - outliner_set_coordinates_element(soops, te, startx, &starty); - } -} - /* find next element that has this name */ static TreeElement *outliner_find_name(SpaceOops *soops, ListBase *lb, char *name, int flags, TreeElement *prev, int *prevFound) @@ -1500,7 +1505,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); /* Find object hovered over */ - te = outliner_dropzone_find(soops, fmval, 1); + te = outliner_dropzone_find(soops, fmval, true); if (te) { RNA_string_set(op->ptr, "parent", te->name); @@ -1715,7 +1720,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); /* Find object hovered over */ - te = outliner_dropzone_find(soops, fmval, 0); + te = outliner_dropzone_find(soops, fmval, false); if (te) { Base *base; @@ -1785,7 +1790,7 @@ static int material_drop_invoke(bContext *C, wmOperator *op, const wmEvent *even UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); /* Find object hovered over */ - te = outliner_dropzone_find(soops, fmval, 1); + te = outliner_dropzone_find(soops, fmval, true); if (te) { RNA_string_set(op->ptr, "object", te->name); @@ -1829,3 +1834,65 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot) RNA_def_string(ot->srna, "material", "Material", MAX_ID_NAME, "Material", "Target Material"); } +static int group_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Main *bmain = CTX_data_main(C); + Group *group = NULL; + Object *ob = NULL; + Scene *scene = CTX_data_scene(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + TreeElement *te = NULL; + char ob_name[MAX_ID_NAME - 2]; + float fmval[2]; + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + /* Find object hovered over */ + te = outliner_dropzone_find(soops, fmval, true); + + if (te) { + group = (Group *)BKE_libblock_find_name(ID_GR, te->name); + + RNA_string_get(op->ptr, "object", ob_name); + ob = (Object *)BKE_libblock_find_name(ID_OB, ob_name); + + if (ELEM(NULL, group, ob)) { + return OPERATOR_CANCELLED; + } + if (BKE_group_object_exists(group, ob)) { + return OPERATOR_FINISHED; + } + + if (BKE_group_object_cyclic_check(bmain, ob, group)) { + BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected"); + return OPERATOR_CANCELLED; + } + + BKE_group_object_add(group, ob, scene, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +void OUTLINER_OT_group_link(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Link Object to Group"; + ot->description = "Link Object to Group in Outliner"; + ot->idname = "OUTLINER_OT_group_link"; + + /* api callbacks */ + ot->invoke = group_link_invoke; + + ot->poll = ED_operator_outliner_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + + /* properties */ + RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object"); +} diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 317d33dd3e2..f0920466b85 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -104,6 +104,7 @@ typedef struct TreeElement { #define TSE_KEYMAP 34 #define TSE_KEYMAP_ITEM 35 #define TSE_ID_BASE 36 +#define TSE_GP_LAYER 37 /* button events */ #define OL_NAMEBUTTON 1 @@ -166,6 +167,7 @@ void outliner_free_tree(ListBase *lb); void outliner_cleanup_tree(struct SpaceOops *soops); TreeElement *outliner_find_tse(struct SpaceOops *soops, TreeStoreElem *tse); +TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem); TreeElement *outliner_find_id(struct SpaceOops *soops, ListBase *lb, struct ID *id); struct ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode); @@ -205,7 +207,7 @@ void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, Tree void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem); -TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const int children); +TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children); /* ...................................................... */ void OUTLINER_OT_item_activate(struct wmOperatorType *ot); @@ -237,6 +239,7 @@ void OUTLINER_OT_parent_drop(struct wmOperatorType *ot); void OUTLINER_OT_parent_clear(struct wmOperatorType *ot); void OUTLINER_OT_scene_drop(struct wmOperatorType *ot); void OUTLINER_OT_material_drop(struct wmOperatorType *ot); +void OUTLINER_OT_group_link(struct wmOperatorType *ot); /* outliner_tools.c ---------------------------------------------- */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 4f13454ef34..d54ae3f22a7 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -77,6 +77,7 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_parent_clear); WM_operatortype_append(OUTLINER_OT_scene_drop); WM_operatortype_append(OUTLINER_OT_material_drop); + WM_operatortype_append(OUTLINER_OT_group_link); } void outliner_keymap(wmKeyConfig *keyconf) diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 23586a6a509..730ee02f448 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -775,7 +775,7 @@ static eOLDrawState tree_element_active_sequence_dup( continue; } -// if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name)) +// if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) // XXX select_single_seq(p, 0); p = p->next; } @@ -873,6 +873,9 @@ eOLDrawState tree_element_type_active( return tree_element_active_sequence_dup(scene, te, tselem, set); case TSE_KEYMAP_ITEM: return tree_element_active_keymap_item(C, te, tselem, set); + case TSE_GP_LAYER: + //return tree_element_active_gplayer(C, scene, te, tselem, set); + break; } return OL_DRAWSEL_NONE; @@ -915,7 +918,7 @@ static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Sp if (tselem->type != TSE_SEQUENCE && tselem->type != TSE_SEQ_STRIP && tselem->type != TSE_SEQUENCE_DUP) tree_element_set_active_object(C, scene, soops, te, (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, - recursive && tselem->type == 0 ); + recursive && tselem->type == 0); if (tselem->type == 0) { // the lib blocks /* editmode? */ diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index d09ed1a100e..bd884039b30 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -499,19 +499,28 @@ static void refreshdrivers_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te /* --------------------------------- */ +typedef enum eOutliner_PropDataOps { + OL_DOP_INVALID = 0, + OL_DOP_SELECT, + OL_DOP_DESELECT, + OL_DOP_HIDE, + OL_DOP_UNHIDE, + OL_DOP_SELECT_LINKED, +} eOutliner_PropDataOps; + static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) { bPoseChannel *pchan = (bPoseChannel *)te->directdata; - if (event == 1) + if (event == OL_DOP_SELECT) pchan->bone->flag |= BONE_SELECTED; - else if (event == 2) + else if (event == OL_DOP_DESELECT) pchan->bone->flag &= ~BONE_SELECTED; - else if (event == 3) { + else if (event == OL_DOP_HIDE) { pchan->bone->flag |= BONE_HIDDEN_P; pchan->bone->flag &= ~BONE_SELECTED; } - else if (event == 4) + else if (event == OL_DOP_UNHIDE) pchan->bone->flag &= ~BONE_HIDDEN_P; } @@ -519,15 +528,15 @@ static void bone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), v { Bone *bone = (Bone *)te->directdata; - if (event == 1) + if (event == OL_DOP_SELECT) bone->flag |= BONE_SELECTED; - else if (event == 2) + else if (event == OL_DOP_DESELECT) bone->flag &= ~BONE_SELECTED; - else if (event == 3) { + else if (event == OL_DOP_HIDE) { bone->flag |= BONE_HIDDEN_P; bone->flag &= ~BONE_SELECTED; } - else if (event == 4) + else if (event == OL_DOP_UNHIDE) bone->flag &= ~BONE_HIDDEN_P; } @@ -535,22 +544,22 @@ static void ebone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), { EditBone *ebone = (EditBone *)te->directdata; - if (event == 1) + if (event == OL_DOP_SELECT) ebone->flag |= BONE_SELECTED; - else if (event == 2) + else if (event == OL_DOP_DESELECT) ebone->flag &= ~BONE_SELECTED; - else if (event == 3) { + else if (event == OL_DOP_HIDE) { ebone->flag |= BONE_HIDDEN_A; ebone->flag &= ~BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL; } - else if (event == 4) + else if (event == OL_DOP_UNHIDE) ebone->flag &= ~BONE_HIDDEN_A; } static void sequence_cb(int event, TreeElement *te, TreeStoreElem *tselem, void *scene_ptr) { Sequence *seq = (Sequence *)te->directdata; - if (event == 1) { + if (event == OL_DOP_SELECT) { Scene *scene = (Scene *)scene_ptr; Editing *ed = BKE_sequencer_editing_get(scene, false); if (BLI_findindex(ed->seqbasep, seq) != -1) { @@ -563,7 +572,7 @@ static void sequence_cb(int event, TreeElement *te, TreeStoreElem *tselem, void static void data_select_linked_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v) { - if (event == 5) { + if (event == OL_DOP_SELECT_LINKED) { if (RNA_struct_is_ID(te->rnaptr.type)) { bContext *C = (bContext *) C_v; ID *id = te->rnaptr.data; @@ -593,6 +602,49 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li } } +static void outline_delete_hierarchy(bContext *C, Scene *scene, Base *base) +{ + Base *child_base; + Object *parent; + + if (!base) { + return; + } + + for (child_base = scene->base.first; child_base; child_base = child_base->next) { + for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent); + if (parent) { + outline_delete_hierarchy(C, scene, child_base); + } + } + + ED_base_object_free_and_unlink(CTX_data_main(C), scene, base); +} + +static void object_delete_hierarchy_cb( + bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem) +{ + Base *base = (Base *)te->directdata; + Object *obedit = scene->obedit; + + if (!base) { + base = BKE_scene_base_find(scene, (Object *)tselem->id); + } + if (base) { + /* Check also library later. */ + for (; obedit && (obedit != base->object); obedit = obedit->parent); + if (obedit == base->object) { + ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); + } + + outline_delete_hierarchy(C, scene, base); + te->directdata = NULL; + tselem->id = NULL; + } + + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); +} + /* **************************************** */ enum { @@ -601,6 +653,7 @@ enum { OL_OP_DESELECT, OL_OP_SELECT_HIERARCHY, OL_OP_DELETE, + OL_OP_DELETE_HIERARCHY, OL_OP_LOCALIZED, /* disabled, see below */ OL_OP_TOGVIS, OL_OP_TOGSEL, @@ -613,6 +666,7 @@ static EnumPropertyItem prop_object_op_types[] = { {OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""}, {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""}, {OL_OP_DELETE, "DELETE", 0, "Delete", ""}, + {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""}, {OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""}, {OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""}, {OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""}, @@ -672,6 +726,16 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) str = "Delete Objects"; WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); } + else if (event == OL_OP_DELETE_HIERARCHY) { + outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_hierarchy_cb); + + /* XXX: See OL_OP_DELETE comment above. */ + outliner_cleanup_tree(soops); + + DAG_relations_tag_update(bmain); + str = "Delete Object Hierarchy"; + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + } else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */ outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb); str = "Localized Objects"; @@ -1196,11 +1260,11 @@ void OUTLINER_OT_animdata_operation(wmOperatorType *ot) /* **************************************** */ static EnumPropertyItem prop_data_op_types[] = { - {1, "SELECT", 0, "Select", ""}, - {2, "DESELECT", 0, "Deselect", ""}, - {3, "HIDE", 0, "Hide", ""}, - {4, "UNHIDE", 0, "Unhide", ""}, - {5, "SELECT_LINKED", 0, "Select Linked", ""}, + {OL_DOP_SELECT, "SELECT", 0, "Select", ""}, + {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""}, + {OL_DOP_HIDE, "HIDE", 0, "Hide", ""}, + {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""}, + {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, {0, NULL, 0, NULL, NULL} }; @@ -1208,7 +1272,7 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op) { SpaceOops *soops = CTX_wm_space_outliner(C); int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - int event; + eOutliner_PropDataOps event; /* check for invalid states */ if (soops == NULL) @@ -1217,7 +1281,7 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op) event = RNA_enum_get(op->ptr, "type"); set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - if (event <= 0) + if (event <= OL_DOP_INVALID) return OPERATOR_CANCELLED; switch (datalevel) { @@ -1253,7 +1317,7 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op) break; case TSE_RNA_STRUCT: - if (event == 5) { + if (event == OL_DOP_SELECT_LINKED) { outliner_do_data_operation(soops, datalevel, event, &soops->tree, data_select_linked_cb, C); } break; diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 4aa36da594b..abc82775c8d 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -38,6 +38,7 @@ #include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_camera_types.h" +#include "DNA_gpencil_types.h" #include "DNA_group_types.h" #include "DNA_key_types.h" #include "DNA_lamp_types.h" @@ -196,7 +197,7 @@ void outliner_cleanup_tree(SpaceOops *soops) } /* Find specific item from the treestore */ -static TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem) +TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem) { TreeElement *te, *tes; for (te = lb->first; te; te = te->next) { @@ -430,6 +431,8 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s // TODO: move this to the front? if (outliner_animdata_test(sce->adt)) outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0); + + outliner_add_element(soops, lb, sce->gpd, te, 0, 0); outliner_add_element(soops, lb, sce->world, te, 0, 0); @@ -451,6 +454,8 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree if (ob->proxy && ob->id.lib == NULL) outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0); + + outliner_add_element(soops, &te->subtree, ob->gpd, te, 0, 0); outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0); @@ -809,6 +814,21 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor } break; } + case ID_GD: + { + bGPdata *gpd = (bGPdata *)id; + bGPDlayer *gpl; + int a = 0; + + if (outliner_animdata_test(gpd->adt)) + outliner_add_element(soops, &te->subtree, gpd, te, TSE_ANIM_DATA, 0); + + // TODO: base element for layers? + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + outliner_add_element(soops, &te->subtree, gpl, te, TSE_GP_LAYER, a); + a++; + } + } } } @@ -856,6 +876,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i else if (type == TSE_ANIM_DATA) { /* pass */ } + else if (type == TSE_GP_LAYER) { + /* pass */ + } else if (type == TSE_ID_BASE) { /* pass */ } @@ -938,6 +961,12 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i } } } + else if (type == TSE_GP_LAYER) { + bGPDlayer *gpl = (bGPDlayer *)idv; + + te->name = gpl->info; + te->directdata = gpl; + } else if (type == TSE_SEQUENCE) { Sequence *seq = (Sequence *) idv; Sequence *p; @@ -1160,7 +1189,7 @@ static int need_add_seq_dup(Sequence *seq) continue; } - if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name)) + if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) return(2); p = p->prev; } @@ -1172,7 +1201,7 @@ static int need_add_seq_dup(Sequence *seq) continue; } - if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name)) + if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) return(0); p = p->next; } @@ -1191,7 +1220,7 @@ static void outliner_add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *t continue; } - if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name)) + if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) /* ch = */ /* UNUSED */ outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index); p = p->next; } @@ -1311,7 +1340,10 @@ static void outliner_sort(SpaceOops *soops, ListBase *lb) TreeElement *te; TreeStoreElem *tselem; int totelem = 0; - + + if (soops->flag & SO_SKIP_SORT_ALPHA) + return; + te = lb->last; if (te == NULL) return; tselem = TREESTORE(te); diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 504d9628d98..30de9c16500 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -98,10 +98,10 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); if (drag->type == WM_DRAG_ID) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; if (GS(id->name) == ID_OB) { /* Ensure item under cursor is valid drop target */ - TreeElement *te = outliner_dropzone_find(soops, fmval, 1); + TreeElement *te = outliner_dropzone_find(soops, fmval, true); if (te && te->idcode == ID_OB && TREESTORE(te)->type == 0) { Scene *scene; @@ -129,7 +129,7 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e static void outliner_parent_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; RNA_string_set(drop->ptr, "child", id->name + 2); } @@ -148,10 +148,10 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent * } if (drag->type == WM_DRAG_ID) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; if (GS(id->name) == ID_OB) { if (((Object *)id)->parent) { - if ((te = outliner_dropzone_find(soops, fmval, 1))) { + if ((te = outliner_dropzone_find(soops, fmval, true))) { TreeStoreElem *tselem = TREESTORE(te); switch (te->idcode) { @@ -171,7 +171,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent * static void outliner_parent_clear_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; RNA_string_set(drop->ptr, "dragged_obj", id->name + 2); /* Set to simple parent clear type. Avoid menus for drag and drop if possible. @@ -188,10 +188,10 @@ static int outliner_scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *ev UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); if (drag->type == WM_DRAG_ID) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; if (GS(id->name) == ID_OB) { /* Ensure item under cursor is valid drop target */ - TreeElement *te = outliner_dropzone_find(soops, fmval, 0); + TreeElement *te = outliner_dropzone_find(soops, fmval, false); return (te && te->idcode == ID_SCE && TREESTORE(te)->type == 0); } } @@ -200,7 +200,7 @@ static int outliner_scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *ev static void outliner_scene_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; RNA_string_set(drop->ptr, "object", id->name + 2); } @@ -213,10 +213,10 @@ static int outliner_material_drop_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 (drag->type == WM_DRAG_ID) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; if (GS(id->name) == ID_MA) { /* Ensure item under cursor is valid drop target */ - TreeElement *te = outliner_dropzone_find(soops, fmval, 1); + TreeElement *te = outliner_dropzone_find(soops, fmval, true); return (te && te->idcode == ID_OB && TREESTORE(te)->type == 0); } } @@ -225,11 +225,35 @@ static int outliner_material_drop_poll(bContext *C, wmDrag *drag, const wmEvent static void outliner_material_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; RNA_string_set(drop->ptr, "material", id->name + 2); } +static int outliner_group_link_poll(bContext *C, wmDrag *drag, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + float fmval[2]; + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + if (drag->type == WM_DRAG_ID) { + ID *id = drag->poin; + if (GS(id->name) == ID_OB) { + /* Ensure item under cursor is valid drop target */ + TreeElement *te = outliner_dropzone_find(soops, fmval, true); + return (te && te->idcode == ID_GR && TREESTORE(te)->type == 0); + } + } + return 0; +} + +static void outliner_group_link_copy(wmDrag *drag, wmDropBox *drop) +{ + ID *id = drag->poin; + RNA_string_set(drop->ptr, "object", id->name + 2); +} + /* region dropbox definition */ static void outliner_dropboxes(void) { @@ -239,6 +263,7 @@ static void outliner_dropboxes(void) WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", outliner_parent_clear_poll, outliner_parent_clear_copy); WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", outliner_scene_drop_poll, outliner_scene_drop_copy); WM_dropbox_add(lb, "OUTLINER_OT_material_drop", outliner_material_drop_poll, outliner_material_drop_copy); + WM_dropbox_add(lb, "OUTLINER_OT_group_link", outliner_group_link_poll, outliner_group_link_copy); } static void outliner_main_area_draw(const bContext *C, ARegion *ar) @@ -362,6 +387,13 @@ static void outliner_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa) break; } break; + case NC_GPENCIL: + switch (wmn->data) { + case ND_DATA: + ED_region_tag_redraw(ar); + break; + } + break; } } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index afb650f8cfd..3be6cd79504 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -70,6 +70,7 @@ #include "WM_api.h" +#include "MEM_guardedalloc.h" /* own include */ #include "sequencer_intern.h" @@ -200,23 +201,25 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc SoundWaveform *waveform; - if (!sound->mutex) - sound->mutex = BLI_mutex_alloc(); + if (!sound->spinlock) { + sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock"); + BLI_spin_init(sound->spinlock); + } - BLI_mutex_lock(sound->mutex); + BLI_spin_lock(sound->spinlock); if (!seq->sound->waveform) { if (!(sound->flags & SOUND_FLAGS_WAVEFORM_LOADING)) { /* prevent sounds from reloading */ seq->sound->flags |= SOUND_FLAGS_WAVEFORM_LOADING; - BLI_mutex_unlock(sound->mutex); + BLI_spin_unlock(sound->spinlock); sequencer_preview_add_sound(C, seq); } else { - BLI_mutex_unlock(sound->mutex); + BLI_spin_unlock(sound->spinlock); } return; /* nothing to draw */ } - BLI_mutex_unlock(sound->mutex); + BLI_spin_unlock(sound->spinlock); waveform = seq->sound->waveform; @@ -467,7 +470,7 @@ static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float } } else if (seq->type == SEQ_TYPE_MOVIECLIP) { - if (seq->clip && strcmp(name, seq->clip->id.name + 2) != 0) { + if (seq->clip && !STREQ(name, seq->clip->id.name + 2)) { str_len = BLI_snprintf(str, sizeof(str), "%s: %s | %d", name, seq->clip->id.name + 2, seq->len); } @@ -477,7 +480,7 @@ static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float } } else if (seq->type == SEQ_TYPE_MASK) { - if (seq->mask && strcmp(name, seq->mask->id.name + 2) != 0) { + if (seq->mask && !STREQ(name, seq->mask->id.name + 2)) { str_len = BLI_snprintf(str, sizeof(str), "%s: %s | %d", name, seq->mask->id.name + 2, seq->len); } @@ -1292,24 +1295,18 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq glEnd(); /* safety border */ - if ((sseq->flag & SEQ_DRAW_SAFE_MARGINS) != 0) { - float fac = 0.1; - - float a = fac * (x2 - x1); - x1 += a; - x2 -= a; - - a = fac * (y2 - y1); - y1 += a; - y2 -= a; - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, x1, y1, x2, y2, 12.0); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - + if (sseq->flag & SEQ_SHOW_SAFE_MARGINS) { + UI_draw_safe_areas( + x1, x2, y1, y2, + scene->safe_areas.title, + scene->safe_areas.action); + + if (sseq->flag & SEQ_SHOW_SAFE_CENTER) { + UI_draw_safe_areas( + x1, x2, y1, y2, + scene->safe_areas.title_center, + scene->safe_areas.action_center); + } } setlinestyle(0); diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 81af6dccc70..8d4a82fc02c 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -37,6 +37,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "BLF_translation.h" @@ -58,12 +59,14 @@ /* for menu/popup icons etc etc*/ +#include "ED_numinput.h" #include "ED_screen.h" #include "ED_transform.h" #include "ED_sequencer.h" #include "ED_space_api.h" #include "UI_view2d.h" +#include "UI_interface.h" /* own include */ @@ -146,11 +149,12 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog struct SeqIndexBuildContext *context = link->data; BKE_sequencer_proxy_rebuild(context, stop, do_update, progress); - } - - if (*stop) { - pj->stop = 1; - fprintf(stderr, "Canceling proxy rebuild on users request...\n"); + + if (*stop) { + pj->stop = 1; + fprintf(stderr, "Canceling proxy rebuild on users request...\n"); + break; + } } } @@ -179,7 +183,8 @@ static void seq_proxy_build_job(const bContext *C) struct SeqIndexBuildContext *context; LinkData *link; Sequence *seq; - + GSet *file_list; + if (ed == NULL) { return; } @@ -200,16 +205,19 @@ static void seq_proxy_build_job(const bContext *C) WM_jobs_callbacks(wm_job, proxy_startjob, NULL, NULL, proxy_endjob); } + file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list"); SEQP_BEGIN (ed, seq) { if ((seq->flag & SELECT)) { - context = BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq); + context = BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq, file_list); link = BLI_genericNodeN(context); BLI_addtail(&pj->queue, link); } } SEQ_END + BLI_gset_free(file_list, MEM_freeN); + if (!WM_jobs_is_running(wm_job)) { G.is_break = false; WM_jobs_start(CTX_wm_manager(C), wm_job); @@ -987,13 +995,13 @@ static void UNUSED_FUNCTION(seq_remap_paths) (Scene *scene) // XXX if (0 == sbutton(to, 0, sizeof(to)-1, "To: ")) // return; - if (strcmp(to, from) == 0) + if (STREQ(to, from)) return; SEQP_BEGIN (ed, seq) { if (seq->flag & SELECT) { - if (strncmp(seq->strip->dir, from, strlen(from)) == 0) { + if (STREQLEN(seq->strip->dir, from, strlen(from))) { printf("found %s\n", seq->strip->dir); /* strip off the beginning */ @@ -1262,6 +1270,7 @@ typedef struct SlipData { bool slow; int slow_offset; /* offset at the point where offset was turned on */ void *draw_handle; + NumInput num_input; } SlipData; static void transseq_backup(TransSeq *ts, Sequence *seq) @@ -1375,6 +1384,13 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve data->trim = MEM_mallocN(num_seq * sizeof(bool), "trimdata_trim"); data->num_seq = num_seq; + initNumInput(&data->num_input); + data->num_input.idx_max = 0; + data->num_input.val_flag[0] |= NUM_NO_FRACTION; + data->num_input.unit_sys = USER_UNIT_NONE; + data->num_input.unit_type[0] = 0; + + slip_add_sequences_rec(ed->seqbasep, data->seq_array, data->trim, 0, true); for (i = 0; i < num_seq; i++) { @@ -1500,47 +1516,83 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op) } } + +static void sequencer_slip_update_header(Scene *scene, ScrArea *sa, SlipData *data, int offset) +{ +#define HEADER_LENGTH 40 + char msg[HEADER_LENGTH]; + + if (sa) { + if (hasNumInput(&data->num_input)) { + char num_str[NUM_STR_REP_LEN]; + outputNumInput(&data->num_input, num_str, &scene->unit); + BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %s", num_str); + } + else { + BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %d", offset); + } + } + + ED_area_headerprint(sa, msg); + +#undef HEADER_LENGTH +} + static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = CTX_data_scene(C); SlipData *data = (SlipData *)op->customdata; ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); + const bool has_numInput = hasNumInput(&data->num_input); + bool handled = true; + + /* Modal numinput active, try to handle numeric inputs first... */ + if (event->val == KM_PRESS && has_numInput && handleNumInput(C, &data->num_input, event)) { + float offset; + applyNumInput(&data->num_input, &offset); + + sequencer_slip_update_header(scene, sa, data, (int)offset); + + RNA_int_set(op->ptr, "offset", offset); + + if (sequencer_slip_recursively(scene, data, offset)) { + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + } + + return OPERATOR_RUNNING_MODAL; + } switch (event->type) { case MOUSEMOVE: { - float mouseloc[2]; - int offset; - int mouse_x; - View2D *v2d = UI_view2d_fromcontext(C); - - if (data->slow) { - mouse_x = event->mval[0] - data->slow_offset; - mouse_x *= 0.1f; - mouse_x += data->slow_offset; - } - else { - mouse_x = event->mval[0]; - } + if (!has_numInput) { + float mouseloc[2]; + int offset; + int mouse_x; + View2D *v2d = UI_view2d_fromcontext(C); + + if (data->slow) { + mouse_x = event->mval[0] - data->slow_offset; + mouse_x *= 0.1f; + mouse_x += data->slow_offset; + } + else { + mouse_x = event->mval[0]; + } - /* choose the side based on which side of the playhead the mouse is on */ - UI_view2d_region_to_view(v2d, mouse_x, 0, &mouseloc[0], &mouseloc[1]); - offset = mouseloc[0] - data->init_mouseloc[0]; + /* choose the side based on which side of the playhead the mouse is on */ + UI_view2d_region_to_view(v2d, mouse_x, 0, &mouseloc[0], &mouseloc[1]); + offset = mouseloc[0] - data->init_mouseloc[0]; - RNA_int_set(op->ptr, "offset", offset); + sequencer_slip_update_header(scene, sa, data, offset); - if (sa) { -#define HEADER_LENGTH 40 - char msg[HEADER_LENGTH]; - BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %d", offset); -#undef HEADER_LENGTH - ED_area_headerprint(sa, msg); - } + RNA_int_set(op->ptr, "offset", offset); - if (sequencer_slip_recursively(scene, data, offset)) { - WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + if (sequencer_slip_recursively(scene, data, offset)) { + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + } } break; } @@ -1597,19 +1649,36 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even case RIGHTSHIFTKEY: case LEFTSHIFTKEY: - if (event->val == KM_PRESS) { - data->slow = true; - data->slow_offset = event->mval[0]; - } - else if (event->val == KM_RELEASE) { - data->slow = false; + if (!has_numInput) { + if (event->val == KM_PRESS) { + data->slow = true; + data->slow_offset = event->mval[0]; + } + else if (event->val == KM_RELEASE) { + data->slow = false; + } } break; default: + handled = false; break; } + /* Modal numinput inactive, try to handle numeric inputs last... */ + if (!handled && event->val == KM_PRESS && handleNumInput(C, &data->num_input, event)) { + float offset; + applyNumInput(&data->num_input, &offset); + + sequencer_slip_update_header(scene, sa, data, (int)offset); + + RNA_int_set(op->ptr, "offset", offset); + + if (sequencer_slip_recursively(scene, data, offset)) { + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + } + } + return OPERATOR_RUNNING_MODAL; } @@ -3360,18 +3429,21 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); Editing *ed = BKE_sequencer_editing_get(scene, false); Sequence *seq; - + GSet *file_list; + if (ed == NULL) { return OPERATOR_CANCELLED; } + file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list"); + SEQP_BEGIN(ed, seq) { if ((seq->flag & SELECT)) { struct SeqIndexBuildContext *context; short stop = 0, do_update; float progress; - context = BKE_sequencer_proxy_rebuild_context(bmain, scene, seq); + context = BKE_sequencer_proxy_rebuild_context(bmain, scene, seq, file_list); BKE_sequencer_proxy_rebuild(context, &stop, &do_update, &progress); BKE_sequencer_proxy_rebuild_finish(context, 0); BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); @@ -3379,6 +3451,8 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) } SEQ_END + BLI_gset_free(file_list, MEM_freeN); + return OPERATOR_FINISHED; } @@ -3397,6 +3471,88 @@ void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; } +static int sequencer_enable_proxies_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 5 * UI_UNIT_Y); +} + +static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Editing *ed = BKE_sequencer_editing_get(scene, false); + Sequence *seq; + bool proxy_25 = RNA_boolean_get(op->ptr, "proxy_25"); + bool proxy_50 = RNA_boolean_get(op->ptr, "proxy_50"); + bool proxy_75 = RNA_boolean_get(op->ptr, "proxy_75"); + bool proxy_100 = RNA_boolean_get(op->ptr, "proxy_100"); + bool override = RNA_boolean_get(op->ptr, "override"); + bool turnon = true; + + if (ed == NULL || !(proxy_25 || proxy_50 || proxy_75 || proxy_100)) { + turnon = false; + } + + SEQP_BEGIN(ed, seq) + { + if ((seq->flag & SELECT)) { + if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, SEQ_TYPE_MULTICAM)) { + BKE_sequencer_proxy_set(seq, turnon); + + if (proxy_25) + seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_25; + else + seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_25; + + if (proxy_50) + seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_50; + else + seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_50; + + if (proxy_75) + seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_75; + else + seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_75; + + if (proxy_100) + seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_100; + else + seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_100; + + if (!override) + seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING; + else + seq->strip->proxy->build_flags &= ~SEQ_PROXY_SKIP_EXISTING; + } + } + } + SEQ_END + + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_enable_proxies(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Selected Strip Proxies"; + ot->idname = "SEQUENCER_OT_enable_proxies"; + ot->description = "Enable selected proxies on all selected Movie strips"; + + /* api callbacks */ + ot->invoke = sequencer_enable_proxies_invoke; + ot->exec = sequencer_enable_proxies_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER; + + RNA_def_boolean(ot->srna, "proxy_25", false, "25%", ""); + RNA_def_boolean(ot->srna, "proxy_50", false, "50%", ""); + RNA_def_boolean(ot->srna, "proxy_75", false, "75%", ""); + RNA_def_boolean(ot->srna, "proxy_100", false, "100%", ""); + RNA_def_boolean(ot->srna, "override", false, "Override", ""); +} + /* change ops */ static EnumPropertyItem prop_change_effect_input_types[] = { diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 5f1c9317fd9..461c72961c2 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -131,6 +131,7 @@ void SEQUENCER_OT_copy(struct wmOperatorType *ot); void SEQUENCER_OT_paste(struct wmOperatorType *ot); void SEQUENCER_OT_rebuild_proxy(struct wmOperatorType *ot); +void SEQUENCER_OT_enable_proxies(struct wmOperatorType *ot); /* preview specific operators */ void SEQUENCER_OT_view_all_preview(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c index 9b5ef18f7cd..33a8a1c5b41 100644 --- a/source/blender/editors/space_sequencer/sequencer_ops.c +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -88,6 +88,7 @@ void sequencer_operatortypes(void) WM_operatortype_append(SEQUENCER_OT_view_ghost_border); WM_operatortype_append(SEQUENCER_OT_rebuild_proxy); + WM_operatortype_append(SEQUENCER_OT_enable_proxies); WM_operatortype_append(SEQUENCER_OT_change_effect_input); WM_operatortype_append(SEQUENCER_OT_change_effect_type); WM_operatortype_append(SEQUENCER_OT_change_path); diff --git a/source/blender/editors/space_sequencer/sequencer_preview.c b/source/blender/editors/space_sequencer/sequencer_preview.c index da00b0ff6e1..c8834d394f5 100644 --- a/source/blender/editors/space_sequencer/sequencer_preview.c +++ b/source/blender/editors/space_sequencer/sequencer_preview.c @@ -95,9 +95,9 @@ static void preview_startjob(void *data, short *stop, short *do_update, float *p sound = previewjb->sound; /* make sure we cleanup the loading flag! */ - BLI_mutex_lock(sound->mutex); + BLI_spin_lock(sound->spinlock); sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING; - BLI_mutex_unlock(sound->mutex); + BLI_spin_unlock(sound->spinlock); BLI_mutex_lock(pj->mutex); previewjb = previewjb->next; @@ -117,7 +117,7 @@ static void preview_startjob(void *data, short *stop, short *do_update, float *p BLI_freelinkN(&pj->previews, previewjb); previewjb = preview_next; pj->processed++; - *progress = (pj->total > 0) ? (float)pj->processed / (float)pj->total : 1.0; + *progress = (pj->total > 0) ? (float)pj->processed / (float)pj->total : 1.0f; *do_update = true; BLI_mutex_unlock(pj->mutex); } diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index 6792bbe0577..4fbe0c6a241 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -996,7 +996,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq) if (SEQ_HAS_PATH(actseq) && dir) { SEQP_BEGIN (ed, seq) { - if (SEQ_HAS_PATH(seq) && seq->strip && strcmp(seq->strip->dir, dir) == 0) { + if (SEQ_HAS_PATH(seq) && seq->strip && STREQ(seq->strip->dir, dir)) { seq->flag |= SELECT; changed = true; } diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 6231f02907a..7be356dd2ec 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -504,6 +504,13 @@ static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa break; } break; + case NC_ANIMATION: + switch (wmn->data) { + case ND_KEYFRAME: + ED_region_tag_redraw(ar); + break; + } + break; case NC_SPACE: if (wmn->data == ND_SPACE_SEQUENCER) ED_region_tag_redraw(ar); @@ -599,6 +606,16 @@ static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED case ND_MARKERS: case ND_SEQUENCER: case ND_RENDER_OPTIONS: + case ND_DRAW_RENDER_VIEWPORT: + ED_region_tag_redraw(ar); + break; + } + break; + case NC_ANIMATION: + switch (wmn->data) { + case ND_KEYFRAME: + /* Otherwise, often prevents seing immediately effects of keyframe editing... */ + BKE_sequencer_cache_cleanup(); ED_region_tag_redraw(ar); break; } diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c index 99e1606c9bd..1637ae14892 100644 --- a/source/blender/editors/space_text/text_autocomplete.c +++ b/source/blender/editors/space_text/text_autocomplete.c @@ -183,7 +183,7 @@ static GHash *text_autocomplete_build(Text *text) const int choice_len = i_end - i_start; if ((choice_len > seek_len) && - (seek_len == 0 || strncmp(seek, str_sub, seek_len) == 0) && + (seek_len == 0 || STREQLEN(seek, str_sub, seek_len)) && (seek != str_sub)) { // printf("Adding: %s\n", s); @@ -207,18 +207,16 @@ static GHash *text_autocomplete_build(Text *text) } { - GHashIterator *iter = BLI_ghashIterator_new(gh); + GHashIterator gh_iter; /* get the formatter for highlighting */ TextFormatType *tft; tft = ED_text_format_get(text); - for (; !BLI_ghashIterator_done(iter); BLI_ghashIterator_step(iter)) { - const char *s = BLI_ghashIterator_getValue(iter); + GHASH_ITER (gh_iter, gh) { + const char *s = BLI_ghashIterator_getValue(&gh_iter); texttool_suggest_add(s, tft->format_identifier(s)); } - BLI_ghashIterator_free(iter); - } } diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 31662c02966..462b619f497 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -549,7 +549,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar) full_update |= drawcache->tabnumber != st->tabnumber; /* word-wrapping option was toggled */ full_update |= drawcache->lheight != st->lheight_dpi; /* word-wrapping option was toggled */ full_update |= drawcache->cwidth != st->cwidth; /* word-wrapping option was toggled */ - full_update |= strncmp(drawcache->text_id, txt->id.name, MAX_ID_NAME); /* text datablock was changed */ + full_update |= !STREQLEN(drawcache->text_id, txt->id.name, MAX_ID_NAME); /* text datablock was changed */ if (st->wordwrap) { /* update line heights */ @@ -1447,7 +1447,6 @@ void draw_text_main(SpaceText *st, ARegion *ar) /* draw other stuff */ draw_brackets(st, ar); - glTranslatef(GLA_PIXEL_OFS, GLA_PIXEL_OFS, 0.0f); /* XXX scroll requires exact pixel space */ draw_textscroll(st, &scroll, &back); draw_documentation(st, ar); draw_suggestion_list(st, ar); diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 1cf0316aa06..ad8050a50e8 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -2537,10 +2537,14 @@ static void text_cursor_set_to_pos(SpaceText *st, ARegion *ar, int x, int y, con y -= txt_get_span(text->lines.first, *linep) - st->top; if (y > 0) { - while (y-- != 0) if ((*linep)->next) *linep = (*linep)->next; + while (y-- != 0) { + if ((*linep)->next) *linep = (*linep)->next; + } } else if (y < 0) { - while (y++ != 0) if ((*linep)->prev) *linep = (*linep)->prev; + while (y++ != 0) { + if ((*linep)->prev) *linep = (*linep)->prev; + } } @@ -2919,7 +2923,7 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode) if (mode != TEXT_FIND && txt_has_sel(text)) { tmp = txt_sel_to_buf(text); - if (flags & ST_MATCH_CASE) found = strcmp(st->findstr, tmp) == 0; + if (flags & ST_MATCH_CASE) found = STREQ(st->findstr, tmp); else found = BLI_strcasecmp(st->findstr, tmp) == 0; if (found) { diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 820d1d68f8d..e2c195fd544 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -58,6 +58,7 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "UI_interface.h" #include "ED_space_api.h" #include "ED_markers.h" @@ -90,13 +91,12 @@ static void time_draw_sfra_efra(Scene *scene, View2D *v2d) fdrawline((float)PEFRA, v2d->cur.ymin, (float)PEFRA, v2d->cur.ymax); } -#define CACHE_DRAW_HEIGHT 3.0f - static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene) { PTCacheID *pid; ListBase pidlist; SpaceTimeCache *stc = stime->caches.first; + const float cache_draw_height = (4.0f * UI_DPI_FAC * U.pixelsize); float yoffs = 0.f; if (!(stime->cache_display & TIME_CACHE_DISPLAY) || (!ob)) @@ -172,7 +172,7 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene) glPushMatrix(); glTranslatef(0.0, (float)V2D_SCROLL_HEIGHT + yoffs, 0.0); - glScalef(1.0, CACHE_DRAW_HEIGHT, 0.0); + glScalef(1.0, cache_draw_height, 0.0); switch (pid->type) { case PTCACHE_TYPE_SOFTBODY: @@ -227,7 +227,7 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene) glPopMatrix(); - yoffs += CACHE_DRAW_HEIGHT; + yoffs += cache_draw_height; stc = stc->next; } @@ -292,6 +292,8 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel) bDopeSheet ads = {NULL}; DLRBT_Tree keys; ActKeyColumn *ak; + float ymin = v2d->tot.ymin; + float ymax = v2d->tot.ymax * 0.6f + ymin * 0.4f; /* init binarytree-list for getting keyframes */ BLI_dlrbTree_init(&keys); @@ -299,7 +301,7 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel) /* init dopesheet settings */ if (onlysel) ads.filterflag |= ADS_FILTER_ONLYSEL; - + /* populate tree with keyframe nodes */ switch (GS(id->name)) { case ID_SCE: @@ -326,8 +328,8 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel) (ak) && (ak->cfra <= v2d->cur.xmax); ak = ak->next) { - glVertex2f(ak->cfra, v2d->tot.ymin); - glVertex2f(ak->cfra, v2d->tot.ymax); + glVertex2f(ak->cfra, ymin); + glVertex2f(ak->cfra, ymax); } glEnd(); // GL_LINES diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index 320267a4a7c..ab69e67361d 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -44,6 +44,7 @@ set(SRC drawarmature.c drawmesh.c drawobject.c + drawsimdebug.c drawvolume.c space_view3d.c view3d_buttons.c diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index 691da78f26b..f33f074e6c5 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -1619,7 +1619,7 @@ static void draw_pose_dofs(Object *ob) for (a = -16; a <= 16; a++) { /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */ float fac = ((float)a) / 16.0f * 0.5f; - phi = (float)(0.5 * M_PI) + fac * (pchan->limitmax[0] - pchan->limitmin[0]); + phi = (float)M_PI_2 + fac * (pchan->limitmax[0] - pchan->limitmin[0]); i = (a == -16) ? 2 : 3; corner[i][0] = 0.0f; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 1cbc8e5567c..add9b41a91f 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -733,7 +733,7 @@ void drawcircball(int mode, const float cent[3], float rad, float tmat[4][4]) } /* circle for object centers, special_color is for library or ob users */ -static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, int special_color) +static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, bool special_color) { const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f; float verts[CIRCLE_RESOL][3]; @@ -741,6 +741,8 @@ static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], /* using gldepthfunc guarantees that it does write z values, * but not checks for it, so centers remain visible independent order of drawing */ if (v3d->zbuf) glDepthFunc(GL_ALWAYS); + /* write to near buffer always */ + glDepthRange(0.0, 0.0); glEnable(GL_BLEND); if (special_color) { @@ -770,6 +772,7 @@ static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], /* finish up */ glDisableClientState(GL_VERTEX_ARRAY); + glDepthRange(0.0, 1.0); glDisable(GL_BLEND); if (v3d->zbuf) glDepthFunc(GL_LEQUAL); @@ -4329,8 +4332,8 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3 ListBase *lb = NULL; DispList *dl; Curve *cu; - const short render_only = (v3d->flag2 & V3D_RENDER_OVERRIDE); - const short solid = (dt > OB_WIRE); + const bool render_only = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0; + const bool solid = (dt > OB_WIRE); if (drawCurveDerivedMesh(scene, v3d, rv3d, base, dt) == false) { return false; @@ -5145,7 +5148,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv cache = psys->pathcache; for (a = 0, pa = psys->particles; a < totpart; a++, pa++) { path = cache[a]; - if (path->steps > 0) { + if (path->segments > 0) { glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); if (1) { //ob_dt > OB_WIRE) { @@ -5157,7 +5160,136 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv } } - glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1); + glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1); + } + } + + if (part->type == PART_HAIR) { + if (part->draw & PART_DRAW_GUIDE_HAIRS) { + DerivedMesh *hair_dm = psys->hair_out_dm; + + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + for (a = 0, pa = psys->particles; a < totpart; a++, pa++) { + if (pa->totkey > 1) { + HairKey *hkey = pa->hair; + + glVertexPointer(3, GL_FLOAT, sizeof(HairKey), hkey->world_co); + + // XXX use proper theme color here +// UI_ThemeColor(TH_NORMAL); + glColor3f(0.58f, 0.67f, 1.0f); + + glDrawArrays(GL_LINE_STRIP, 0, pa->totkey); + } + } + + if (hair_dm) { + MVert *mvert = hair_dm->getVertArray(hair_dm); + int i; + + glColor3f(0.9f, 0.4f, 0.4f); + + glBegin(GL_LINES); + for (a = 0, pa = psys->particles; a < totpart; a++, pa++) { + for (i = 1; i < pa->totkey; ++i) { + float v1[3], v2[3]; + + copy_v3_v3(v1, mvert[pa->hair_index + i - 1].co); + copy_v3_v3(v2, mvert[pa->hair_index + i].co); + + mul_m4_v3(ob->obmat, v1); + mul_m4_v3(ob->obmat, v2); + + glVertex3fv(v1); + glVertex3fv(v2); + } + } + glEnd(); + } + + glEnable(GL_LIGHTING); + glEnable(GL_COLOR_MATERIAL); + glEnableClientState(GL_NORMAL_ARRAY); + if ((dflag & DRAW_CONSTCOLOR) == 0) + if (part->draw_col == PART_DRAW_COL_MAT) + glEnableClientState(GL_COLOR_ARRAY); + } + + if (part->draw & PART_DRAW_HAIR_GRID) { + ClothModifierData *clmd = psys->clmd; + if (clmd) { + float *a = clmd->hair_grid_min; + float *b = clmd->hair_grid_max; + int *res = clmd->hair_grid_res; + int i; + + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + if (select) + UI_ThemeColor(TH_ACTIVE); + else + UI_ThemeColor(TH_WIRE); + glBegin(GL_LINES); + glVertex3f(a[0], a[1], a[2]); glVertex3f(b[0], a[1], a[2]); + glVertex3f(b[0], a[1], a[2]); glVertex3f(b[0], b[1], a[2]); + glVertex3f(b[0], b[1], a[2]); glVertex3f(a[0], b[1], a[2]); + glVertex3f(a[0], b[1], a[2]); glVertex3f(a[0], a[1], a[2]); + + glVertex3f(a[0], a[1], b[2]); glVertex3f(b[0], a[1], b[2]); + glVertex3f(b[0], a[1], b[2]); glVertex3f(b[0], b[1], b[2]); + glVertex3f(b[0], b[1], b[2]); glVertex3f(a[0], b[1], b[2]); + glVertex3f(a[0], b[1], b[2]); glVertex3f(a[0], a[1], b[2]); + + glVertex3f(a[0], a[1], a[2]); glVertex3f(a[0], a[1], b[2]); + glVertex3f(b[0], a[1], a[2]); glVertex3f(b[0], a[1], b[2]); + glVertex3f(a[0], b[1], a[2]); glVertex3f(a[0], b[1], b[2]); + glVertex3f(b[0], b[1], a[2]); glVertex3f(b[0], b[1], b[2]); + glEnd(); + + if (select) + UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -100); + else + UI_ThemeColorShadeAlpha(TH_WIRE, 0, -100); + glEnable(GL_BLEND); + glBegin(GL_LINES); + for (i = 1; i < res[0]-1; ++i) { + float f = interpf(b[0], a[0], (float)i / (float)(res[0]-1)); + glVertex3f(f, a[1], a[2]); glVertex3f(f, b[1], a[2]); + glVertex3f(f, b[1], a[2]); glVertex3f(f, b[1], b[2]); + glVertex3f(f, b[1], b[2]); glVertex3f(f, a[1], b[2]); + glVertex3f(f, a[1], b[2]); glVertex3f(f, a[1], a[2]); + } + for (i = 1; i < res[1]-1; ++i) { + float f = interpf(b[1], a[1], (float)i / (float)(res[1]-1)); + glVertex3f(a[0], f, a[2]); glVertex3f(b[0], f, a[2]); + glVertex3f(b[0], f, a[2]); glVertex3f(b[0], f, b[2]); + glVertex3f(b[0], f, b[2]); glVertex3f(a[0], f, b[2]); + glVertex3f(a[0], f, b[2]); glVertex3f(a[0], f, a[2]); + } + for (i = 1; i < res[2]-1; ++i) { + float f = interpf(b[2], a[2], (float)i / (float)(res[2]-1)); + glVertex3f(a[0], a[1], f); glVertex3f(b[0], a[1], f); + glVertex3f(b[0], a[1], f); glVertex3f(b[0], b[1], f); + glVertex3f(b[0], b[1], f); glVertex3f(a[0], b[1], f); + glVertex3f(a[0], b[1], f); glVertex3f(a[0], a[1], f); + } + glEnd(); + glDisable(GL_BLEND); + + glEnable(GL_LIGHTING); + glEnable(GL_COLOR_MATERIAL); + glEnableClientState(GL_NORMAL_ARRAY); + if ((dflag & DRAW_CONSTCOLOR) == 0) + if (part->draw_col == PART_DRAW_COL_MAT) + glEnableClientState(GL_COLOR_ARRAY); + } } } @@ -5176,7 +5308,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv } } - glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1); + glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1); } @@ -5328,7 +5460,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) PTCacheEditKey *key; ParticleEditSettings *pset = PE_settings(scene); int i, k, totpoint = edit->totpoint, timed = pset->flag & PE_FADE_TIME ? pset->fade_frames : 0; - int steps = 1; + int totkeys = 1; float sel_col[3]; float nosel_col[3]; float *pathcol = NULL, *pcol; @@ -5347,10 +5479,10 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) UI_GetThemeColor3fv(TH_VERTEX, nosel_col); /* draw paths */ - steps = (*edit->pathcache)->steps + 1; + totkeys = (*edit->pathcache)->segments + 1; glEnable(GL_BLEND); - pathcol = MEM_callocN(steps * 4 * sizeof(float), "particle path color data"); + pathcol = MEM_callocN(totkeys * 4 * sizeof(float), "particle path color data"); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); @@ -5370,7 +5502,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); if (point->flag & PEP_HIDE) { - for (k = 0, pcol = pathcol; k < steps; k++, pcol += 4) { + for (k = 0, pcol = pathcol; k < totkeys; k++, pcol += 4) { copy_v3_v3(pcol, path->col); pcol[3] = 0.25f; } @@ -5378,7 +5510,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) glColorPointer(4, GL_FLOAT, 4 * sizeof(float), pathcol); } else if (timed) { - for (k = 0, pcol = pathcol, pkey = path; k < steps; k++, pkey++, pcol += 4) { + for (k = 0, pcol = pathcol, pkey = path; k < totkeys; k++, pkey++, pcol += 4) { copy_v3_v3(pcol, pkey->col); pcol[3] = 1.0f - fabsf((float)(CFRA) -pkey->time) / (float)pset->fade_frames; } @@ -5388,7 +5520,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) else glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col); - glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1); + glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1); } if (pathcol) { MEM_freeN(pathcol); pathcol = pcol = NULL; } @@ -7727,7 +7859,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short if (render_override) { /* don't draw */ } - else if ((scene->basact) == base) + else if (is_obact) do_draw_center = ACTIVE; else if (base->flag & SELECT) do_draw_center = SELECT; diff --git a/source/blender/editors/space_view3d/drawsimdebug.c b/source/blender/editors/space_view3d/drawsimdebug.c new file mode 100644 index 00000000000..6113bfd4143 --- /dev/null +++ b/source/blender/editors/space_view3d/drawsimdebug.c @@ -0,0 +1,173 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Lukas Toenne + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/drawsimdebug.c + * \ingroup spview3d + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" +#include "DNA_object_types.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" +#include "BLI_ghash.h" + +#include "BKE_effect.h" +#include "BKE_global.h" +#include "BKE_modifier.h" + +#include "view3d_intern.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "UI_resources.h" + +static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4]) +{ + GHashIterator iter; + + /**** dots ****/ + + glPointSize(3.0f); + glBegin(GL_POINTS); + for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { + SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); + if (elem->type != SIM_DEBUG_ELEM_DOT) + continue; + + glColor3f(elem->color[0], elem->color[1], elem->color[2]); + glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); + } + glEnd(); + glPointSize(1.0f); + + /**** circles ****/ + + { + float circle[16][2] = { + {0.000000, 1.000000}, {0.382683, 0.923880}, {0.707107, 0.707107}, {0.923880, 0.382683}, + {1.000000, -0.000000}, {0.923880, -0.382683}, {0.707107, -0.707107}, {0.382683, -0.923880}, + {-0.000000, -1.000000}, {-0.382683, -0.923880}, {-0.707107, -0.707107}, {-0.923879, -0.382684}, + {-1.000000, 0.000000}, {-0.923879, 0.382684}, {-0.707107, 0.707107}, {-0.382683, 0.923880} }; + for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { + SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); + float radius = elem->v2[0]; + float co[3]; + int i; + + if (elem->type != SIM_DEBUG_ELEM_CIRCLE) + continue; + + glColor3f(elem->color[0], elem->color[1], elem->color[2]); + glBegin(GL_LINE_LOOP); + for (i = 0; i < 16; ++i) { + co[0] = radius * circle[i][0]; + co[1] = radius * circle[i][1]; + co[2] = 0.0f; + mul_mat3_m4_v3(imat, co); + add_v3_v3(co, elem->v1); + + glVertex3f(co[0], co[1], co[2]); + } + glEnd(); + } + } + + /**** lines ****/ + + glBegin(GL_LINES); + for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { + SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); + if (elem->type != SIM_DEBUG_ELEM_LINE) + continue; + + glColor3f(elem->color[0], elem->color[1], elem->color[2]); + glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); + glVertex3f(elem->v2[0], elem->v2[1], elem->v2[2]); + } + glEnd(); + + /**** vectors ****/ + + glPointSize(2.0f); + glBegin(GL_POINTS); + for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { + SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); + if (elem->type != SIM_DEBUG_ELEM_VECTOR) + continue; + + glColor3f(elem->color[0], elem->color[1], elem->color[2]); + glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); + } + glEnd(); + glPointSize(1.0f); + + glBegin(GL_LINES); + for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { + SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); + float t[3]; + if (elem->type != SIM_DEBUG_ELEM_VECTOR) + continue; + + glColor3f(elem->color[0], elem->color[1], elem->color[2]); + glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); + add_v3_v3v3(t, elem->v1, elem->v2); + glVertex3f(t[0], t[1], t[2]); + } + glEnd(); +} + +void draw_sim_debug_data(Scene *UNUSED(scene), View3D *UNUSED(v3d), ARegion *ar) +{ + RegionView3D *rv3d = ar->regiondata; + /*Object *ob = base->object;*/ + float imat[4][4]; + + if (!_sim_debug_data) + return; + + invert_m4_m4(imat, rv3d->viewmatob); + +// glDepthMask(GL_FALSE); +// glEnable(GL_BLEND); + + glPushMatrix(); + + glLoadMatrixf(rv3d->viewmat); + draw_sim_debug_elements(_sim_debug_data, imat); + + glPopMatrix(); + +// glDepthMask(GL_TRUE); +// glDisable(GL_BLEND); +} diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 55d5273b198..25085368dac 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -564,7 +564,7 @@ static void view3d_main_area_exit(wmWindowManager *wm, ARegion *ar) static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_ID) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; if (GS(id->name) == ID_OB) return 1; } @@ -574,7 +574,7 @@ static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_ID) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; if (GS(id->name) == ID_GR) return 1; } @@ -584,7 +584,7 @@ static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEve static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_ID) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; if (GS(id->name) == ID_MA) return 1; } @@ -594,7 +594,7 @@ static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_ID) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; if (GS(id->name) == ID_IM) return 1; } @@ -641,14 +641,14 @@ static int view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; RNA_string_set(drop->ptr, "name", id->name + 2); } static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; drop->opcontext = WM_OP_EXEC_DEFAULT; RNA_string_set(drop->ptr, "name", id->name + 2); @@ -656,14 +656,14 @@ static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop) static void view3d_id_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; RNA_string_set(drop->ptr, "name", id->name + 2); } static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; if (id) { RNA_string_set(drop->ptr, "name", id->name + 2); @@ -817,6 +817,16 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN case ND_WORLD: /* handled by space_view3d_listener() for v3d access */ break; + case ND_DRAW_RENDER_VIEWPORT: + { + if (v3d->camera && (scene == wmn->reference)) { + RegionView3D *rv3d = ar->regiondata; + if (rv3d->persp == RV3D_CAMOB) { + ED_region_tag_redraw(ar); + } + } + break; + } } if (wmn->action == NA_EDITED) ED_region_tag_redraw(ar); @@ -856,6 +866,20 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN break; } break; + case NC_CAMERA: + switch (wmn->data) { + case ND_DRAW_RENDER_VIEWPORT: + { + if (v3d->camera && (v3d->camera->data == wmn->reference)) { + RegionView3D *rv3d = ar->regiondata; + if (rv3d->persp == RV3D_CAMOB) { + ED_region_tag_redraw(ar); + } + } + break; + } + } + break; case NC_GROUP: /* all group ops for now */ ED_region_tag_redraw(ar); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 65721d52dff..929929c7dd0 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -162,15 +162,15 @@ static void view3d_draw_clipping(RegionView3D *rv3d) /* fill in zero alpha for rendering & re-projection [#31530] */ unsigned char col[4]; - UI_GetThemeColorShade3ubv(TH_BACK, -8, col); - col[3] = 0; + UI_GetThemeColor4ubv(TH_V3D_CLIPPING_BORDER, col); glColor4ubv(col); + glEnable(GL_BLEND); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, bb->vec); glDrawElements(GL_QUADS, sizeof(clipping_index) / sizeof(unsigned int), GL_UNSIGNED_INT, clipping_index); glDisableClientState(GL_VERTEX_ARRAY); - + glDisable(GL_BLEND); } } @@ -586,20 +586,26 @@ static void draw_view_axis(RegionView3D *rv3d, rcti *rect) float ydisp = 0.0; /* vertical displacement to allow obj info text */ int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */ float vec[3]; - char axis_text[2] = "x"; float dx, dy; - int i; - + + int axis_order[3] = {0, 1, 2}; + int axis_i; + startx += rect->xmin; starty += rect->ymin; - + + axis_sort_v3(rv3d->viewinv[2], axis_order); + /* thickness of lines is proportional to k */ glLineWidth(2); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - for (i = 0; i < 3; i++) { + for (axis_i = 0; axis_i < 3; axis_i++) { + int i = axis_order[axis_i]; + const char axis_text[2] = {'x' + i, '\0'}; + zero_v3(vec); vec[i] = 1.0f; mul_qt_v3(rv3d->viewquat, vec); @@ -616,8 +622,6 @@ static void draw_view_axis(RegionView3D *rv3d, rcti *rect) BLF_draw_default_ascii(startx + dx + 2, starty + dy + ydisp + 2, 0.0f, axis_text, 1); } - axis_text[0]++; - /* BLF_draw_default disables blending */ glEnable(GL_BLEND); } @@ -1066,14 +1070,13 @@ static void drawviewborder_triangle(float x1, float x2, float y1, float y2, cons static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) { - float hmargin, vmargin; float x1, x2, y1, y2; float x1i, x2i, y1i, y2i; rctf viewborder; Camera *ca = NULL; RegionView3D *rv3d = ar->regiondata; - + if (v3d->camera == NULL) return; if (v3d->camera->type == OB_CAMERA) @@ -1225,17 +1228,20 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) drawviewborder_triangle(x1, x2, y1, y2, 1, 'B'); } - if (ca->flag & CAM_SHOWTITLESAFE) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - - hmargin = 0.1f * (x2 - x1); - vmargin = 0.05f * (y2 - y1); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, x1 + hmargin, y1 + vmargin, x2 - hmargin, y2 - vmargin, 2.0f); + if (ca->flag & CAM_SHOW_SAFE_MARGINS) { + UI_draw_safe_areas( + x1, x2, y1, y2, + scene->safe_areas.title, + scene->safe_areas.action); - hmargin = 0.035f * (x2 - x1); - vmargin = 0.035f * (y2 - y1); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, x1 + hmargin, y1 + vmargin, x2 - hmargin, y2 - vmargin, 2.0f); + if (ca->flag & CAM_SHOW_SAFE_CENTER) { + UI_draw_safe_areas( + x1, x2, y1, y2, + scene->safe_areas.title_center, + scene->safe_areas.action_center); + } } + if (ca->flag & CAM_SHOWSENSOR) { /* determine sensor fit, and get sensor x/y, for auto fit we * assume and square sensor and only use sensor_x */ @@ -1279,8 +1285,9 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) /* camera name - draw in highlighted text color */ if (ca && (ca->flag & CAM_SHOWNAME)) { UI_ThemeColor(TH_TEXT_HI); - BLF_draw_default(x1i, y1i - 15, 0.0f, v3d->camera->id.name + 2, sizeof(v3d->camera->id.name) - 2); - UI_ThemeColor(TH_WIRE); + BLF_draw_default( + x1i, y1i - (0.7f * U.widget_unit), 0.0f, + v3d->camera->id.name + 2, sizeof(v3d->camera->id.name) - 2); } } @@ -1608,7 +1615,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, { float image_aspect[2]; float fac, asp, zoomx, zoomy; - float x1, y1, x2, y2; + float x1, y1, x2, y2, centx, centy; ImBuf *ibuf = NULL, *freeibuf, *releaseibuf; void *lock; @@ -1714,6 +1721,9 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, y2 += yof_scale; } + centx = (x1 + x2) / 2.0f; + centy = (y1 + y2) / 2.0f; + /* aspect correction */ if (bgpic->flag & V3D_BGPIC_CAMERA_ASPECT) { /* apply aspect from clip */ @@ -1731,16 +1741,14 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, if ((asp_src > asp_dst) == ((bgpic->flag & V3D_BGPIC_CAMERA_CROP) != 0)) { /* fit X */ const float div = asp_src / asp_dst; - const float cent = (x1 + x2) / 2.0f; - x1 = ((x1 - cent) * div) + cent; - x2 = ((x2 - cent) * div) + cent; + x1 = ((x1 - centx) * div) + centx; + x2 = ((x2 - centx) * div) + centx; } else { /* fit Y */ const float div = asp_dst / asp_src; - const float cent = (y1 + y2) / 2.0f; - y1 = ((y1 - cent) * div) + cent; - y2 = ((y2 - cent) * div) + cent; + y1 = ((y1 - centy) * div) + centy; + y2 = ((y2 - centy) * div) + centy; } } } @@ -1767,6 +1775,9 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, y1 = sco[1] + asp * fac * (bgpic->yof - bgpic->size); x2 = sco[0] + fac * (bgpic->xof + bgpic->size); y2 = sco[1] + asp * fac * (bgpic->yof + bgpic->size); + + centx = (x1 + x2) / 2.0f; + centy = (y1 + y2) / 2.0f; } /* complete clip? */ @@ -1817,6 +1828,19 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, glPushMatrix(); ED_region_pixelspace(ar); + glTranslatef(centx, centy, 0.0); + if (rv3d->persp != RV3D_CAMOB) { + glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f); + } + + if (bgpic->flag & V3D_BGPIC_FLIP_X) { + zoomx *= -1.0f; + x1 = x2; + } + if (bgpic->flag & V3D_BGPIC_FLIP_Y) { + zoomy *= -1.0f; + y1 = y2; + } glPixelZoom(zoomx, zoomy); glColor4f(1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend); @@ -1824,7 +1848,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, * glaDrawPixelsSafe in some cases, which will end up in missing * alpha transparency for the background image (sergey) */ - glaDrawPixelsTex(x1, y1, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect); + glaDrawPixelsTex(x1 - centx, y1 - centy, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect); glPixelZoom(1.0, 1.0); glPixelTransferf(GL_ALPHA_SCALE, 1.0f); @@ -2566,6 +2590,7 @@ CustomDataMask ED_view3d_screen_datamask(bScreen *screen) void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) { RegionView3D *rv3d = ar->regiondata; + rctf cameraborder; /* setup window matrices */ if (winmat) @@ -2583,7 +2608,23 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); invert_m4_m4(rv3d->persinv, rv3d->persmat); invert_m4_m4(rv3d->viewinv, rv3d->viewmat); + + /* calculate GLSL view dependent values */ + /* store window coordinates scaling/offset */ + if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false); + rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder); + rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder); + + rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx; + rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy; + } + else { + rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f; + rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f; + } + /* calculate pixelsize factor once, is used for lamps and obcenters */ { /* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])' @@ -2815,15 +2856,15 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar, bool { /* clear background */ if (scene->world && ((v3d->flag3 & V3D_SHOW_WORLD) || force)) { - float alpha = (force) ? 1.0f : 0.0; + float alpha = (force) ? 1.0f : 0.0f; bool glsl = GPU_glsl_support() && BKE_scene_use_new_shading_nodes(scene) && scene->world->nodetree && scene->world->use_nodes; if (glsl) { RegionView3D *rv3d = ar->regiondata; GPUMaterial *gpumat = GPU_material_world(scene, scene->world); - + /* calculate full shader for background */ - GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, (v3d->scenelock != 0)); + GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0)); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_ALWAYS); @@ -3082,15 +3123,6 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx, G.f &= ~G_RENDER_OGL; } -/* get a color used for offscreen sky, returns color in sRGB space */ -void ED_view3d_offscreen_sky_color_get(Scene *scene, float sky_color[3]) -{ - if (scene->world) - linearrgb_to_srgb_v3_v3(sky_color, &scene->world->horr); - else - UI_GetThemeColor3fv(TH_BACK, sky_color); -} - /* utility func for ED_view3d_draw_offscreen */ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey, unsigned int flag, bool draw_background, int alpha_mode, char err_out[256]) @@ -3573,9 +3605,13 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar) /* draw viewport using opengl */ if (v3d->drawtype != OB_RENDER || !view3d_main_area_do_render_draw(scene) || clip_border) { view3d_main_area_draw_objects(C, scene, v3d, ar, &grid_unit); + #ifdef DEBUG_DRAW bl_debug_draw(); #endif + if (G.debug & G_DEBUG_SIMDATA) + draw_sim_debug_data(scene, v3d, ar); + ED_region_pixelspace(ar); } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index aab307babe8..e6f61fb4aca 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -1034,7 +1034,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y) * - of rotation is linearly proportional * - to the distance that the mouse is * - dragged. */ - phi = si * (float)(M_PI / 2.0); + phi = si * (float)M_PI_2; q1[0] = cosf(phi); mul_v3_fl(q1 + 1, sinf(phi)); @@ -3373,7 +3373,8 @@ void VIEW3D_OT_render_border(wmOperatorType *ot) /* rna */ WM_operator_properties_border(ot); - prop = 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", false, "Camera Only", + "Set render border for camera view and final render only"); RNA_def_property_flag(prop, PROP_HIDDEN); } @@ -5003,8 +5004,9 @@ BGpic *ED_view3D_background_image_new(View3D *v3d) { BGpic *bgpic = MEM_callocN(sizeof(BGpic), "Background Image"); - bgpic->size = 5.0; - bgpic->blend = 0.5; + bgpic->rotation = 0.0f; + bgpic->size = 5.0f; + bgpic->blend = 0.5f; bgpic->iuser.fie_ima = 2; bgpic->iuser.ok = 1; bgpic->view = 0; /* 0 for all */ diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index d3a9f5ca967..25dbc8830fe 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -48,9 +48,11 @@ struct bMotionPath; struct bPoseChannel; struct bScreen; struct Mesh; +struct SimDebugData; struct wmNDOFMotionData; struct wmOperatorType; struct wmWindowManager; +struct wmKeyConfig; /* drawing flags: */ enum { @@ -177,6 +179,9 @@ void draw_mesh_paint_weight_edges(RegionView3D *rv3d, struct DerivedMesh *dm, void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d, struct Object *ob, struct DerivedMesh *dm, const int draw_flags); +/* drawsimdebug.c */ +void draw_sim_debug_data(Scene *scene, View3D *v3d, ARegion *ar); + /* view3d_draw.c */ void view3d_main_area_draw(const struct bContext *C, struct ARegion *ar); void ED_view3d_draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, bool alphaoverride); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 5df348408df..0457f5f2d52 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -344,8 +344,8 @@ void view3d_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_all", NDOF_MOTION, 0, KM_CTRL | KM_SHIFT, 0); kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0); RNA_boolean_set(kmi->ptr, "use_all_regions", false); - RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CCW, KM_PRESS, 0, 0)->ptr, "angle", M_PI / -2); - RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CW, KM_PRESS, 0, 0)->ptr, "angle", M_PI / 2); + RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CCW, KM_PRESS, 0, 0)->ptr, "angle", -M_PI_2); + RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CW, KM_PRESS, 0, 0)->ptr, "angle", M_PI_2); RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT); diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c index f127f375a9f..af24a99a6f2 100644 --- a/source/blender/editors/space_view3d/view3d_toolbar.c +++ b/source/blender/editors/space_view3d/view3d_toolbar.c @@ -216,7 +216,7 @@ static void view3d_panel_tool_shelf(const bContext *C, Panel *pa) CustomTool *ct; for (ct = st->toolshelf.first; ct; ct = ct->next) { - if (0 == strncmp(context, ct->context, OP_MAX_TYPENAME)) { + if (STREQLEN(context, ct->context, OP_MAX_TYPENAME)) { col = uiLayoutColumn(pa->layout, true); uiItemFullO(col, ct->opname, NULL, ICON_NONE, NULL, WM_OP_INVOKE_REGION_WIN, 0); } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index b727b96c8cc..14bbdebd138 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -93,8 +93,8 @@ #define MAX_INFO_LEN 256 static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg); -static int doEdgeSlide(TransInfo *t, float perc); -static int doVertSlide(TransInfo *t, float perc); +static void doEdgeSlide(TransInfo *t, float perc); +static void doVertSlide(TransInfo *t, float perc); static void drawEdgeSlide(const struct bContext *C, TransInfo *t); static void drawVertSlide(const struct bContext *C, TransInfo *t); @@ -671,8 +671,11 @@ static void viewRedrawPost(bContext *C, TransInfo *t) WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); /* redraw UV editor */ - if (t->mode == TFM_EDGE_SLIDE && (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) + if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) && + (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) + { WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); + } /* XXX temp, first hack to get auto-render in compositor work (ton) */ WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM_DONE, CTX_data_scene(C)); @@ -969,6 +972,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) { char cmode = constraintModeToChar(t); bool handled = false; + const int modifiers_prev = t->modifiers; t->redraw |= handleMouseInput(t, &t->mouse, event); @@ -1495,6 +1499,13 @@ int transformEvent(TransInfo *t, const wmEvent *event) } } + /* if we change snap options, get the unsnapped values back */ + if ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) != + (modifiers_prev & (MOD_SNAP | MOD_SNAP_INVERT))) + { + applyMouseInput(t, &t->mouse, t->mval, t->values); + } + /* Per transform event, if present */ if (t->handleEvent && (!handled || @@ -3129,7 +3140,7 @@ static void initResize(TransInfo *t) t->num.unit_type[2] = B_UNIT_NONE; } -static void headerResize(TransInfo *t, float vec[3], char str[MAX_INFO_LEN]) +static void headerResize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN]) { char tvec[NUM_STR_REP_LEN * 3]; size_t ofs = 0; @@ -4102,7 +4113,7 @@ static void initTranslation(TransInfo *t) } } -static void headerTranslation(TransInfo *t, float vec[3], char str[MAX_INFO_LEN]) +static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN]) { size_t ofs = 0; char tvec[NUM_STR_REP_LEN * 3]; @@ -4195,7 +4206,7 @@ static void headerTranslation(TransInfo *t, float vec[3], char str[MAX_INFO_LEN] } } -static void applyTranslationValue(TransInfo *t, float vec[3]) +static void applyTranslationValue(TransInfo *t, const float vec[3]) { TransData *td = t->data; float tvec[3]; @@ -4932,7 +4943,7 @@ static void initBoneSize(TransInfo *t) t->num.unit_type[2] = B_UNIT_NONE; } -static void headerBoneSize(TransInfo *t, float vec[3], char str[MAX_INFO_LEN]) +static void headerBoneSize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN]) { char tvec[NUM_STR_REP_LEN * 3]; if (hasNumInput(&t->num)) { @@ -5102,6 +5113,85 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) } /** \} */ +/* -------------------------------------------------------------------- */ +/* Original Data Store */ + +/** \name Orig-Data Store Utility Functions + * \{ */ + +static void slide_origdata_init_flag( + TransInfo *t, SlideOrigData *sod) +{ + BMEditMesh *em = BKE_editmesh_from_object(t->obedit); + BMesh *bm = em->bm; + + if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) && + /* don't do this at all for non-basis shape keys, too easy to + * accidentally break uv maps or vertex colors then */ + (bm->shapenr <= 1)) + { + sod->use_origfaces = true; + } + else { + sod->use_origfaces = false; + } +} + +static void slide_origdata_init_data( + TransInfo *t, SlideOrigData *sod) +{ + if (sod->use_origfaces) { + BMEditMesh *em = BKE_editmesh_from_object(t->obedit); + BMesh *bm = em->bm; + + sod->origfaces = BLI_ghash_ptr_new(__func__); + sod->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default); + /* we need to have matching customdata */ + BM_mesh_copy_init_customdata(sod->bm_origfaces, bm, NULL); + } +} + +static void slide_origdata_create_date( + TransInfo *t, SlideOrigData *sod, + BMVert **v_pt, unsigned int v_stride, unsigned int v_num) +{ + if (sod->use_origfaces) { + BMEditMesh *em = BKE_editmesh_from_object(t->obedit); + BMesh *bm = em->bm; + + unsigned int i; + for (i = 0; i < v_num; i++, v_pt = (void *)(((char *)v_pt) + v_stride)) { + BMIter fiter; + BMFace *f; + BMVert *v = *v_pt; + + BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { + if (!BLI_ghash_haskey(sod->origfaces, f)) { + BMFace *f_copy = BM_face_copy(sod->bm_origfaces, bm, f, true, true); + BLI_ghash_insert(sod->origfaces, f, f_copy); + } + } + } + } +} + +static void slide_origdata_free_date( + SlideOrigData *sod) +{ + if (sod->use_origfaces) { + if (sod->bm_origfaces) { + BM_mesh_free(sod->bm_origfaces); + sod->bm_origfaces = NULL; + } + + if (sod->origfaces) { + BLI_ghash_free(sod->origfaces, NULL, NULL); + sod->origfaces = NULL; + } + } +} + +/** \} */ /* -------------------------------------------------------------------- */ /* Transform (Edge Slide) */ @@ -5360,16 +5450,7 @@ static bool createEdgeSlideVerts(TransInfo *t) rv3d = t->ar ? t->ar->regiondata : NULL; } - if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) && - /* don't do this at all for non-basis shape keys, too easy to - * accidentally break uv maps or vertex colors then */ - (bm->shapenr <= 1)) - { - sld->use_origfaces = true; - } - else { - sld->use_origfaces = false; - } + slide_origdata_init_flag(t, &sld->orig_data); sld->is_proportional = true; sld->curr_sv_index = 0; @@ -5761,30 +5842,12 @@ static bool createEdgeSlideVerts(TransInfo *t) } bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); - - if (sld->use_origfaces) { - sld->origfaces = BLI_ghash_ptr_new(__func__); - sld->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default); - /* we need to have matching customdata */ - BM_mesh_copy_init_customdata(sld->bm_origfaces, bm, NULL); - } + slide_origdata_init_data(t, &sld->orig_data); + slide_origdata_create_date(t, &sld->orig_data, &sld->sv->v, sizeof(*sld->sv), sld->totsv); /*create copies of faces for customdata projection*/ sv_array = sld->sv; for (i = 0; i < sld->totsv; i++, sv_array++) { - BMIter fiter; - BMFace *f; - - - if (sld->use_origfaces) { - BM_ITER_ELEM (f, &fiter, sv_array->v, BM_FACES_OF_VERT) { - if (!BLI_ghash_haskey(sld->origfaces, f)) { - BMFace *f_copy = BM_face_copy(sld->bm_origfaces, bm, f, true, true); - BLI_ghash_insert(sld->origfaces, f, f_copy); - } - } - } - /* switch a/b if loop direction is different from global direction */ l_nr = sv_array->loop_nr; if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) { @@ -5828,11 +5891,12 @@ static bool createEdgeSlideVerts(TransInfo *t) void projectEdgeSlideData(TransInfo *t, bool is_final) { EdgeSlideData *sld = t->customData; + SlideOrigData *sod = &sld->orig_data; TransDataEdgeSlideVert *sv; BMEditMesh *em = sld->em; int i; - if (sld->use_origfaces == false) { + if (sod->use_origfaces == false) { return; } @@ -5844,7 +5908,7 @@ void projectEdgeSlideData(TransInfo *t, bool is_final) BMFace *f_copy; /* the copy of 'f' */ BMFace *f_copy_flip; /* the copy of 'f' or detect if we need to flip to the shorter side. */ - f_copy = BLI_ghash_lookup(sld->origfaces, l->f); + f_copy = BLI_ghash_lookup(sod->origfaces, l->f); /* project onto copied projection face */ f_copy_flip = f_copy; @@ -5858,12 +5922,12 @@ void projectEdgeSlideData(TransInfo *t, bool is_final) if (sld->perc < 0.0f) { if (BM_vert_in_face(sv->v_b, l_ed_sel->radial_next->f)) { - f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_ed_sel->radial_next->f); + f_copy_flip = BLI_ghash_lookup(sod->origfaces, l_ed_sel->radial_next->f); } } else if (sld->perc > 0.0f) { if (BM_vert_in_face(sv->v_a, l_ed_sel->radial_next->f)) { - f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_ed_sel->radial_next->f); + f_copy_flip = BLI_ghash_lookup(sod->origfaces, l_ed_sel->radial_next->f); } } @@ -5949,7 +6013,7 @@ void projectEdgeSlideData(TransInfo *t, bool is_final) l_adj = l; } - f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_adj->f); + f_copy_flip = BLI_ghash_lookup(sod->origfaces, l_adj->f); } } } @@ -5966,34 +6030,23 @@ void projectEdgeSlideData(TransInfo *t, bool is_final) } /* make sure face-attributes are correct (e.g. MTexPoly) */ - BM_elem_attrs_copy(sld->bm_origfaces, em->bm, f_copy, l->f); + BM_elem_attrs_copy(sod->bm_origfaces, em->bm, f_copy, l->f); } } } void freeEdgeSlideTempFaces(EdgeSlideData *sld) { - if (sld->use_origfaces) { - if (sld->bm_origfaces) { - BM_mesh_free(sld->bm_origfaces); - sld->bm_origfaces = NULL; - } - - if (sld->origfaces) { - BLI_ghash_free(sld->origfaces, NULL, NULL); - sld->origfaces = NULL; - } - } + slide_origdata_free_date(&sld->orig_data); } - void freeEdgeSlideVerts(TransInfo *t) { EdgeSlideData *sld = t->customData; if (!sld) return; - + freeEdgeSlideTempFaces(sld); bmesh_edit_end(sld->em->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); @@ -6167,7 +6220,7 @@ static void drawEdgeSlide(const struct bContext *C, TransInfo *t) } } -static int doEdgeSlide(TransInfo *t, float perc) +static void doEdgeSlide(TransInfo *t, float perc) { EdgeSlideData *sld = t->customData; TransDataEdgeSlideVert *svlist = sld->sv, *sv; @@ -6224,8 +6277,6 @@ static int doEdgeSlide(TransInfo *t, float perc) } projectEdgeSlideData(t, 0); - - return 1; } static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) @@ -6390,6 +6441,8 @@ static bool createVertSlideVerts(TransInfo *t) rv3d = ar ? ar->regiondata : NULL; } + slide_origdata_init_flag(t, &sld->orig_data); + sld->is_proportional = true; sld->curr_sv_index = 0; sld->flipped_vtx = false; @@ -6485,6 +6538,10 @@ static bool createVertSlideVerts(TransInfo *t) sld->sv = sv_array; sld->totsv = j; + bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); + slide_origdata_init_data(t, &sld->orig_data); + slide_origdata_create_date(t, &sld->orig_data, &sld->sv->v, sizeof(*sld->sv), sld->totsv); + sld->em = em; sld->perc = 0.0f; @@ -6499,6 +6556,53 @@ static bool createVertSlideVerts(TransInfo *t) return true; } +void projectVertSlideData(TransInfo *t, bool is_final) +{ + VertSlideData *sld = t->customData; + SlideOrigData *sod = &sld->orig_data; + TransDataVertSlideVert *sv; + BMEditMesh *em = sld->em; + int i; + + if (sod->use_origfaces == false) { + return; + } + + for (i = 0, sv = sld->sv; i < sld->totsv; sv++, i++) { + BMIter fiter; + BMLoop *l; + + BM_ITER_ELEM (l, &fiter, sv->v, BM_LOOPS_OF_VERT) { + BMFace *f_copy; /* the copy of 'f' */ + BMFace *f_copy_flip; /* the copy of 'f' or detect if we need to flip to the shorter side. */ + + f_copy = BLI_ghash_lookup(sod->origfaces, l->f); + + /* project onto copied projection face */ + f_copy_flip = f_copy; + + /* only loop data, no vertex data since that contains shape keys, + * and we do not want to mess up other shape keys */ + BM_loop_interp_from_face(em->bm, l, f_copy_flip, false, false); + + if (is_final) { + BM_loop_interp_multires(em->bm, l, f_copy_flip); + if (f_copy != f_copy_flip) { + BM_loop_interp_multires(em->bm, l, f_copy); + } + } + + /* make sure face-attributes are correct (e.g. MTexPoly) */ + BM_elem_attrs_copy(sod->bm_origfaces, em->bm, f_copy, l->f); + } + } +} + +void freeVertSlideTempFaces(VertSlideData *sld) +{ + slide_origdata_free_date(&sld->orig_data); +} + void freeVertSlideVerts(TransInfo *t) { VertSlideData *sld = t->customData; @@ -6506,6 +6610,9 @@ void freeVertSlideVerts(TransInfo *t) if (!sld) return; + freeVertSlideTempFaces(sld); + + bmesh_edit_end(sld->em->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES); if (sld->totsv > 0) { TransDataVertSlideVert *sv = sld->sv; @@ -6702,7 +6809,7 @@ static void drawVertSlide(const struct bContext *C, TransInfo *t) } } -static int doVertSlide(TransInfo *t, float perc) +static void doVertSlide(TransInfo *t, float perc) { VertSlideData *sld = t->customData; TransDataVertSlideVert *svlist = sld->sv, *sv; @@ -6742,7 +6849,7 @@ static int doVertSlide(TransInfo *t, float perc) } } - return 1; + projectVertSlideData(t, false); } static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2])) @@ -7117,7 +7224,7 @@ static void initSeqSlide(TransInfo *t) t->num.unit_type[1] = B_UNIT_NONE; } -static void headerSeqSlide(TransInfo *t, float val[2], char str[MAX_INFO_LEN]) +static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_LEN]) { char tvec[NUM_STR_REP_LEN * 3]; size_t ofs = 0; @@ -7516,7 +7623,7 @@ static void initTimeSlide(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; } -static void headerTimeSlide(TransInfo *t, float sval, char str[MAX_INFO_LEN]) +static void headerTimeSlide(TransInfo *t, const float sval, char str[MAX_INFO_LEN]) { char tvec[NUM_STR_REP_LEN * 3]; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 0d824be862e..2330ec6e79e 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -213,18 +213,23 @@ typedef struct TransDataEdgeSlideVert { int loop_nr; } TransDataEdgeSlideVert; + +/* store original data so we can correct UV's and similar when sliding */ +typedef struct SlideOrigData { + /* flag that is set when origfaces is initialized */ + bool use_origfaces; + struct GHash *origfaces; + struct BMesh *bm_origfaces; +} SlideOrigData; + typedef struct EdgeSlideData { TransDataEdgeSlideVert *sv; int totsv; - - struct GHash *origfaces; int mval_start[2], mval_end[2]; struct BMEditMesh *em; - /* flag that is set when origfaces is initialized */ - bool use_origfaces; - struct BMesh *bm_origfaces; + SlideOrigData orig_data; float perc; @@ -251,6 +256,8 @@ typedef struct VertSlideData { struct BMEditMesh *em; + SlideOrigData orig_data; + float perc; bool is_proportional; @@ -699,7 +706,9 @@ void freeEdgeSlideTempFaces(EdgeSlideData *sld); void freeEdgeSlideVerts(TransInfo *t); void projectEdgeSlideData(TransInfo *t, bool is_final); +void freeVertSlideTempFaces(VertSlideData *sld); void freeVertSlideVerts(TransInfo *t); +void projectVertSlideData(TransInfo *t, bool is_final); /* TODO. transform_queries.c */ diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index d8f17315c01..ccb81c7342b 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -208,7 +208,7 @@ static void axisProjection(TransInfo *t, const float axis[3], const float in[3], viewAxisCorrectCenter(t, t_con_center); angle = fabsf(angle_v3v3(axis, t->viewinv[2])); - if (angle > (float)M_PI / 2.0f) { + if (angle > (float)M_PI_2) { angle = (float)M_PI - angle; } angle = RAD2DEGF(angle); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index c1350b1f076..42f7087d4a7 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -5354,7 +5354,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o /* only if bone name matches too... * NOTE: this will do constraints too, but those are ok to do here too? */ - if (pchanName && strcmp(pchanName, pchan->name) == 0) + if (pchanName && STREQ(pchanName, pchan->name)) insert_keyframe(reports, id, act, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag); if (pchanName) MEM_freeN(pchanName); @@ -5597,6 +5597,12 @@ void special_aftertrans_update(bContext *C, TransInfo *t) * during cleanup - psy-fi */ freeEdgeSlideTempFaces(sld); } + else if (t->mode == TFM_VERT_SLIDE) { + /* as above */ + VertSlideData *sld = t->customData; + projectVertSlideData(t, true); + freeVertSlideTempFaces(sld); + } if (t->obedit->type == OB_MESH) { special_aftertrans_update__mesh(C, t); @@ -7321,6 +7327,11 @@ static void createTransGPencil(bContext *C, TransInfo *t) bGPDstroke *gps; for (gps = gpf->strokes.first; gps; gps = gps->next) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + if (propedit) { /* Proportional Editing... */ if (propedit_connected) { @@ -7424,6 +7435,11 @@ static void createTransGPencil(bContext *C, TransInfo *t) TransData *tail = td; bool stroke_ok; + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + /* What we need to include depends on proportional editing settings... */ if (propedit) { if (propedit_connected) { diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index fcf789546e8..3000b3e00bc 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1874,9 +1874,12 @@ void calculatePropRatio(TransInfo *t) TransData *td = t->data; int i; float dist; - short connected = t->flag & T_PROP_CONNECTED; + const bool connected = (t->flag & T_PROP_CONNECTED) != 0; + + t->proptext[0] = '\0'; if (t->flag & T_PROP_EDIT) { + const char *pet_id = NULL; for (i = 0; i < t->total; i++, td++) { if (td->flag & TD_SELECTED) { td->factor = 1.0f; @@ -1937,6 +1940,9 @@ void calculatePropRatio(TransInfo *t) case PROP_RANDOM: td->factor = BLI_frand() * dist; break; + case PROP_INVSQUARE: + td->factor = dist * (2.0f - dist); + break; default: td->factor = 1; break; @@ -1945,35 +1951,40 @@ void calculatePropRatio(TransInfo *t) } switch (t->prop_mode) { case PROP_SHARP: - strcpy(t->proptext, IFACE_("(Sharp)")); + pet_id = N_("(Sharp)"); break; case PROP_SMOOTH: - strcpy(t->proptext, IFACE_("(Smooth)")); + pet_id = N_("(Smooth)"); break; case PROP_ROOT: - strcpy(t->proptext, IFACE_("(Root)")); + pet_id = N_("(Root)"); break; case PROP_LIN: - strcpy(t->proptext, IFACE_("(Linear)")); + pet_id = N_("(Linear)"); break; case PROP_CONST: - strcpy(t->proptext, IFACE_("(Constant)")); + pet_id = N_("(Constant)"); break; case PROP_SPHERE: - strcpy(t->proptext, IFACE_("(Sphere)")); + pet_id = N_("(Sphere)"); break; case PROP_RANDOM: - strcpy(t->proptext, IFACE_("(Random)")); + pet_id = N_("(Random)"); + break; + case PROP_INVSQUARE: + pet_id = N_("(InvSquare)"); break; default: - t->proptext[0] = '\0'; break; } + + if (pet_id) { + BLI_strncpy(t->proptext, IFACE_(pet_id), sizeof(t->proptext)); + } } else { for (i = 0; i < t->total; i++, td++) { td->factor = 1.0; } - t->proptext[0] = '\0'; } } diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index f2869843dd5..38190d407ab 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -177,7 +177,7 @@ static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], con mul_qt_v3(quat, gmat[0]); /* Y-axis */ - axis_angle_to_quat(quat, axis, M_PI / 2.0); + axis_angle_to_quat(quat, axis, M_PI_2); copy_v3_v3(gmat[1], gmat[0]); mul_qt_v3(quat, gmat[1]); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 25dee50a192..1498e2894d4 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -868,7 +868,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot) RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f); - Transform_Properties(ot, P_MIRROR | P_SNAP); + Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV); } static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot) diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 32d4f2e5a15..438eb1f3864 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -231,7 +231,7 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha BLI_split_file_part(abs_name, fi, sizeof(fi)); BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi); - if (strcmp(abs_name, local_name) != 0) { + if (!STREQ(abs_name, local_name)) { switch (checkPackedFile(local_name, pf)) { case PF_NOFILE: BLI_snprintf(line, sizeof(line), IFACE_("Create %s"), local_name); diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c index 2428ee21367..7f5edb5ea9e 100644 --- a/source/blender/editors/util/editmode_undo.c +++ b/source/blender/editors/util/editmode_undo.c @@ -206,7 +206,7 @@ static void undo_clean_stack(bContext *C) /* for when objects are converted, renamed, or global undo changes pointers... */ if (uel->type == obedit->type) { - if (strcmp(uel->id.name, obedit->id.name) == 0) { + if (STREQ(uel->id.name, obedit->id.name)) { if (uel->validate_undo == NULL) is_valid = true; else if (uel->validate_undo(uel->undodata, editdata)) @@ -305,7 +305,7 @@ void undo_editmode_name(bContext *C, const char *undoname) UndoElem *uel; for (uel = undobase.last; uel; uel = uel->prev) { - if (strcmp(undoname, uel->name) == 0) + if (STREQ(undoname, uel->name)) break; } if (uel && uel->prev) { @@ -321,7 +321,7 @@ int undo_editmode_valid(const char *undoname) UndoElem *uel; for (uel = undobase.last; uel; uel = uel->prev) { - if (strcmp(undoname, uel->name) == 0) + if (STREQ(undoname, uel->name)) break; } return uel != NULL; diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index fac57490b44..ab882a388ad 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -580,7 +580,7 @@ static int undo_history_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } else if (undosys == UNDOSYSTEM_IMAPAINT) { - ED_undo_paint_step_num(C, UNDO_PAINT_IMAGE, item ); + ED_undo_paint_step_num(C, UNDO_PAINT_IMAGE, item); } else { ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true); diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index 569fe1c326d..00615f9bef7 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -2672,8 +2672,8 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) } for (i = 0; i < ninterior; i++) { - sys->lambdaPlanar[i] += nlGetVariable(0, i); - sys->lambdaLength[i] += nlGetVariable(0, ninterior + i); + sys->lambdaPlanar[i] += (float)nlGetVariable(0, i); + sys->lambdaLength[i] += (float)nlGetVariable(0, ninterior + i); } } @@ -4561,7 +4561,7 @@ void param_pack(ParamHandle *handle, float margin, bool do_rotate) box->index = i; /* warning this index skips PCHART_NOPACK boxes */ if (margin > 0.0f) - area += sqrtf(box->w * box->h); + area += (double)sqrtf(box->w * box->h); } if (margin > 0.0f) { diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index c5931cf2943..4cb1f8943f9 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -1601,7 +1601,7 @@ static int stitch_init(bContext *C, wmOperator *op) BMFace *efa; BMLoop *l; BMIter iter, liter; - GHashIterator *ghi; + GHashIterator gh_iter; UvEdge *all_edges; StitchState *state; Scene *scene = CTX_data_scene(C); @@ -1748,14 +1748,11 @@ static int stitch_init(bContext *C, wmOperator *op) } } - - ghi = BLI_ghashIterator_new(edge_hash); total_edges = BLI_ghash_size(edge_hash); state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges"); /* I assume any system will be able to at least allocate an iterator :p */ if (!edges) { - BLI_ghashIterator_free(ghi); state_delete(state); return 0; } @@ -1763,12 +1760,12 @@ static int stitch_init(bContext *C, wmOperator *op) state->total_separate_edges = total_edges; /* fill the edges with data */ - for (i = 0, BLI_ghashIterator_init(ghi, edge_hash); !BLI_ghashIterator_done(ghi); BLI_ghashIterator_step(ghi)) { - edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi)); + i = 0; + GHASH_ITER (gh_iter, edge_hash) { + edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter)); } /* cleanup temporary stuff */ - BLI_ghashIterator_free(ghi); MEM_freeN(all_edges); BLI_ghash_free(edge_hash, NULL, NULL); diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index b5e27ab0cf6..793f84b05ec 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -1130,7 +1130,7 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel) ParamHandle *handle; const bool fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0; - const bool correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) != 0; + const bool correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0; bool use_subsurf; modifier_unwrap_state(obedit, scene, &use_subsurf); |