diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b84970dad2..de01be1d299 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -866,7 +866,7 @@ endif() # linux only, not cached set(WITH_BINRELOC OFF) -# MAXOSX only, set to avoid uninitialized +# MACOSX only, set to avoid uninitialized set(EXETYPE "") # C/C++ flags @@ -1572,7 +1572,7 @@ if(WITH_CXX11) if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") # TODO(sergey): Do we want c++11 or gnu-c++11 here? set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - elseif(MSVC14 OR MSVC12) + elseif(MSVC) # Nothing special is needed, C++11 features are available by default. else() message(FATAL_ERROR "Compiler ${CMAKE_C_COMPILER_ID} is not supported for C++11 build yet") diff --git a/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst b/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst index d8cc5e45e83..c5729fd5b19 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst @@ -405,7 +405,7 @@ base class --- :class:`SCA_IObject` .. note:: - This attribute is experemental and may be removed (but probably wont be). + This attribute is experimental and may be removed (but probably wont be). .. note:: @@ -419,7 +419,7 @@ base class --- :class:`SCA_IObject` .. note:: - This attribute is experemental and may be removed (but probably wont be). + This attribute is experimental and may be removed (but probably wont be). .. note:: @@ -453,7 +453,7 @@ base class --- :class:`SCA_IObject` .. attribute:: childrenRecursive - all children of this object including childrens children, (read-only). + all children of this object including children's children, (read-only). :type: :class:`CListValue` of :class:`KX_GameObject`'s @@ -536,7 +536,7 @@ base class --- :class:`SCA_IObject` .. method:: getAxisVect(vect) - Returns the axis vector rotates by the objects worldspace orientation. + Returns the axis vector rotates by the object's worldspace orientation. This is the equivalent of multiplying the vector by the orientation matrix. :arg vect: a vector to align the axis. @@ -596,7 +596,7 @@ base class --- :class:`SCA_IObject` Gets the game object's linear velocity. - This method returns the game object's velocity through it's centre of mass, ie no angular velocity component. + This method returns the game object's velocity through it's center of mass, ie no angular velocity component. :arg local: * False: you get the "global" velocity ie: relative to world orientation. @@ -609,7 +609,7 @@ base class --- :class:`SCA_IObject` Sets the game object's linear velocity. - This method sets game object's velocity through it's centre of mass, + This method sets game object's velocity through it's center of mass, ie no angular velocity component. This requires a dynamic object. @@ -814,7 +814,7 @@ base class --- :class:`SCA_IObject` # do something pass - The face paremeter determines the orientation of the normal. + The face parameter determines the orientation of the normal. * 0 => hit normal is always oriented towards the ray origin (as if you casted the ray from outside) * 1 => hit normal is the real face normal (only for mesh object, otherwise face has no effect) @@ -911,7 +911,7 @@ base class --- :class:`SCA_IObject` .. note:: - The gameObject argument has an advantage that it can convert from a mesh with modifiers applied (such as subsurf). + The gameObject argument has an advantage that it can convert from a mesh with modifiers applied (such as the Subdivision Surface modifier). .. warning:: @@ -919,7 +919,7 @@ base class --- :class:`SCA_IObject` .. warning:: - If the object is a part of a combound object it will fail (parent or child) + If the object is a part of a compound object it will fail (parent or child) .. warning:: diff --git a/doc/python_api/rst/info_api_reference.rst b/doc/python_api/rst/info_api_reference.rst index 43469fc0cb7..5ef5866c44a 100644 --- a/doc/python_api/rst/info_api_reference.rst +++ b/doc/python_api/rst/info_api_reference.rst @@ -204,7 +204,7 @@ Lets say we want to access the texture of a brush via Python, to adjust its ``co - Start in the default scene and enable 'Sculpt' mode from the 3D-View header. - From the toolbar expand the **Texture** panel and add a new texture. - *Notice the texture button its self doesn't have very useful links (you can check the tool-tips).* + *Notice the texture button its self doesn't have very useful links (you can check the tooltips).* - The contrast setting isn't exposed in the sculpt toolbar, so view the texture in the properties panel... - In the properties button select the Texture context. diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py index f00f5d97c5e..d3460383fe7 100644 --- a/release/scripts/startup/bl_operators/image.py +++ b/release/scripts/startup/bl_operators/image.py @@ -82,8 +82,8 @@ class EditExternally(Operator): import traceback traceback.print_exc() self.report({'ERROR'}, - "Image editor not found, " - "please specify in User Preferences > File") + "Image editor could not be launched, please ensure that " + "the path in User Preferences > File is valid, and Blender has rights to launch it") return {'CANCELLED'} diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index e5b6a94c1ab..075a6f870fa 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -1180,11 +1180,18 @@ class USERPREF_PT_input(Panel): col.separator() col.label(text="NDOF Device:") sub = col.column(align=True) - sub.prop(inputs, "ndof_sensitivity", text="NDOF Sensitivity") - sub.prop(inputs, "ndof_orbit_sensitivity", text="NDOF Orbit Sensitivity") - sub.prop(inputs, "ndof_deadzone", text="NDOF Deadzone") + sub.prop(inputs, "ndof_sensitivity", text="Pan Sensitivity") + sub.prop(inputs, "ndof_orbit_sensitivity", text="Orbit Sensitivity") + sub.prop(inputs, "ndof_deadzone", text="Deadzone") + + sub.separator() + col.label(text="Navigation Style:") sub = col.column(align=True) sub.row().prop(inputs, "ndof_view_navigate_method", expand=True) + + sub.separator() + col.label(text="Rotation Style:") + sub = col.column(align=True) sub.row().prop(inputs, "ndof_view_rotate_method", expand=True) row.separator() diff --git a/release/scripts/templates_py/addon_add_object.py b/release/scripts/templates_py/addon_add_object.py index 8e57d7ef8f8..d294838d3a2 100644 --- a/release/scripts/templates_py/addon_add_object.py +++ b/release/scripts/templates_py/addon_add_object.py @@ -69,9 +69,9 @@ def add_object_button(self, context): # This allows you to right click on a button and link to the manual def add_object_manual_map(): - url_manual_prefix = "http://wiki.blender.org/index.php/Doc:2.6/Manual/" + url_manual_prefix = "https://www.blender.org/manual/" url_manual_mapping = ( - ("bpy.ops.mesh.add_object", "Modeling/Objects"), + ("bpy.ops.mesh.add_object", "editors/3dview/object"), ) return url_manual_prefix, url_manual_mapping diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index f20885b1e8f..d5a395ffc4b 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -167,6 +167,10 @@ static const char *force_device = NULL; #ifdef WITH_JACK static void sound_sync_callback(void *data, int mode, float time) { + // Ugly: Blender doesn't like it when the animation is played back during rendering + if (G.is_rendering) + return; + struct Main *bmain = (struct Main *)data; struct Scene *scene; @@ -693,6 +697,10 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene) float BKE_sound_sync_scene(struct Scene *scene) { + // Ugly: Blender doesn't like it when the animation is played back during rendering + if (G.is_rendering) + return NAN_FLT; + if (scene->playback_handle) { if (scene->audio.flag & AUDIO_SYNC) return AUD_getSynchronizerPosition(scene->playback_handle); @@ -704,6 +712,10 @@ float BKE_sound_sync_scene(struct Scene *scene) int BKE_sound_scene_playing(struct Scene *scene) { + // Ugly: Blender doesn't like it when the animation is played back during rendering + if (G.is_rendering) + return -1; + if (scene->audio.flag & AUDIO_SYNC) return AUD_isSynchronizerPlaying(); else diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index fbecffc1270..f5beda0f13e 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -123,13 +123,13 @@ MINLINE void mul_v4_fl(float r[4], float f); MINLINE void mul_v4_v4fl(float r[3], const float a[3], float f); MINLINE void mul_v2_v2_cw(float r[2], const float mat[2], const float vec[2]); MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2]); -MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3]) ATTR_WARN_UNUSED_RESULT; -MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; -MINLINE float dot_m3_v3_row_y(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; -MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; -MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT; -MINLINE float dot_m4_v3_row_y(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT; -MINLINE float dot_m4_v3_row_z(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float dot_m3_v3_row_x(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float dot_m3_v3_row_y(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float dot_m3_v3_row_z(float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float dot_m4_v3_row_x(float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float dot_m4_v3_row_y(float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float dot_m4_v3_row_z(float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE void madd_v2_v2fl(float r[2], const float a[2], float f); MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f); @@ -171,7 +171,7 @@ MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]); MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3]); -MINLINE void star_m3_v3(float rmat[3][3], const float a[3]); +MINLINE void star_m3_v3(float rmat[3][3], float a[3]); /*********************************** Length **********************************/ diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 38947e139ff..46d963ee268 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -3763,6 +3763,9 @@ void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3]) /***************************** View & Projection *****************************/ +/** + * Matches `glOrtho` result. + */ void orthographic_m4(float matrix[4][4], const float left, const float right, const float bottom, const float top, const float nearClip, const float farClip) { @@ -3783,6 +3786,9 @@ void orthographic_m4(float matrix[4][4], const float left, const float right, co matrix[3][2] = -(farClip + nearClip) / Zdelta; } +/** + * Matches `glFrustum` result. + */ void perspective_m4(float mat[4][4], const float left, const float right, const float bottom, const float top, const float nearClip, const float farClip) { diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index dbc46ffc233..ee5e8651bd3 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -479,8 +479,19 @@ MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2]) r[1] = mat[1] * vec[0] + (+mat[0]) * vec[1]; } -/* note: could add a matrix inline */ -MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3]) +/** + * Convenience function to get the projected depth of a position. + * This avoids creating a temporary 4D vector and multiplying it - only for the 4th component. + * + * Matches logic for: + * + * \code{.c} + * float co_4d[4] = {co[0], co[1], co[2], 1.0}; + * mul_m4_v4(mat, co_4d); + * return co_4d[3]; + * \endcode + */ +MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3]) { return (mat[0][3] * co[0]) + (mat[1][3] * co[1]) + @@ -490,15 +501,15 @@ MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3]) /** * Has the effect of #mul_m3_v3(), on a single axis. */ -MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3]) +MINLINE float dot_m3_v3_row_x(float M[3][3], const float a[3]) { return M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2]; } -MINLINE float dot_m3_v3_row_y(const float M[3][3], const float a[3]) +MINLINE float dot_m3_v3_row_y(float M[3][3], const float a[3]) { return M[0][1] * a[0] + M[1][1] * a[1] + M[2][1] * a[2]; } -MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3]) +MINLINE float dot_m3_v3_row_z(float M[3][3], const float a[3]) { return M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2]; } @@ -507,15 +518,15 @@ MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3]) * Has the effect of #mul_mat3_m4_v3(), on a single axis. * (no adding translation) */ -MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3]) +MINLINE float dot_m4_v3_row_x(float M[4][4], const float a[3]) { return M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2]; } -MINLINE float dot_m4_v3_row_y(const float M[4][4], const float a[3]) +MINLINE float dot_m4_v3_row_y(float M[4][4], const float a[3]) { return M[0][1] * a[0] + M[1][1] * a[1] + M[2][1] * a[2]; } -MINLINE float dot_m4_v3_row_z(const float M[4][4], const float a[3]) +MINLINE float dot_m4_v3_row_z(float M[4][4], const float a[3]) { return M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2]; } @@ -745,7 +756,7 @@ MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const f n[2] += (v_prev[0] - v_curr[0]) * (v_prev[1] + v_curr[1]); } -MINLINE void star_m3_v3(float rmat[3][3], const float a[3]) +MINLINE void star_m3_v3(float rmat[3][3], float a[3]) { rmat[0][0] = rmat[1][1] = rmat[2][2] = 0.0; rmat[0][1] = -a[2]; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index d3576a12b9c..0e1861abcf1 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -8385,6 +8385,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) static void do_versions_after_linking(Main *main) { + UNUSED_VARS(main); // printf("%s for %s (%s), %d.%d\n", __func__, main->curlib ? main->curlib->name : main->name, // main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile); } @@ -9811,9 +9812,15 @@ static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Libra if (active_lay) { ob->lay = active_lay; } + if (flag & FILE_AUTOSELECT) { + /* Note that link_object_postprocess() already checks for FILE_AUTOSELECT flag, + * but it will miss objects from non-instanciated groups... */ + ob->flag |= SELECT; + /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */ + } - base->lay = ob->lay; base->object = ob; + base->lay = ob->lay; base->flag = ob->flag; CLAMP_MIN(ob->id.us, 0); diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 8340be81aa8..05169a2a976 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -57,6 +57,7 @@ #define BEVEL_EPSILON_ANG DEG2RADF(2.0f) #define BEVEL_SMALL_ANG DEG2RADF(10.0f) #define BEVEL_MAX_ADJUST_PCT 10.0f +#define BEVEL_MAX_AUTO_ADJUST_PCT 300.0f /* happens far too often, uncomment for development */ // #define BEVEL_ASSERT_PROJECT @@ -323,15 +324,33 @@ static bool edge_half_offset_changed(EdgeHalf *e) e->offset_r != e->offset_r_spec; } -static bool any_edge_half_offset_changed(BevVert *bv) +static float adjusted_rel_change(float val, float spec) +{ + float relchg; + + relchg = 0.0f; + if (val != spec) { + if (spec == 0) + relchg = 1000.0f; /* arbitrary large value */ + else + relchg = fabsf((val - spec) / spec); + } + return relchg; +} + +static float max_edge_half_offset_rel_change(BevVert *bv) { int i; + float max_rel_change; + EdgeHalf *e; + max_rel_change = 0.0f; for (i = 0; i < bv->edgecount; i++) { - if (edge_half_offset_changed(&bv->edges[i])) - return true; + e = &bv->edges[i]; + max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_l, e->offset_l_spec)); + max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_r, e->offset_r_spec)); } - return false; + return max_rel_change; } /* Return the next EdgeHalf after from_e that is beveled. @@ -1951,6 +1970,7 @@ static void adjust_offsets(BevelParams *bp) GHashIterator giter; EdgeHalf *e, *efirst, *eother; GSQueue *q; + float max_rel_adj; BLI_assert(!bp->vertex_only); GHASH_ITER(giter, bp->vert_hash) { @@ -1966,7 +1986,7 @@ static void adjust_offsets(BevelParams *bp) searchi = -1; GHASH_ITER(giter, bp->vert_hash) { bv = BLI_ghashIterator_getValue(&giter); - if (!bv->visited && any_edge_half_offset_changed(bv)) { + if (!bv->visited && max_edge_half_offset_rel_change(bv) > 0.0f) { i = BM_elem_index_get(bv->v); if (!searchbv || i < searchi) { searchbv = bv; @@ -1996,6 +2016,24 @@ static void adjust_offsets(BevelParams *bp) } } BLI_gsqueue_free(q); + + /* Should we auto-limit the error accumulation? Typically, spirals can lead to 100x relative adjustments, + * and somewhat hacky mechanism of using bp->limit_offset to indicate "clamp the adjustments" is not + * obvious to users, who almost certainaly want clamping in this situation. + * The reason not to clamp always is that some models work better without it (e.g., Bent_test in regression + * suite, where relative adjust maximum is about .6). */ + if (!bp->limit_offset) { + max_rel_adj = 0.0f; + GHASH_ITER(giter, bp->vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + max_rel_adj = max_ff(max_rel_adj, max_edge_half_offset_rel_change(bv)); + } + if (max_rel_adj > BEVEL_MAX_AUTO_ADJUST_PCT / 100.0f) { + bp->limit_offset = true; + adjust_offsets(bp); + bp->limit_offset = false; + } + } } /* Do the edges at bv form a "pipe"? diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index 437dd2b2de2..cc77a321a89 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -309,6 +309,28 @@ static void animchan_sync_fcurve(bAnimContext *ac, bAnimListElem *ale, FCurve ** } } +/* perform syncing updates for GPencil Layers */ +static void animchan_sync_gplayer(bAnimContext *UNUSED(ac), bAnimListElem *ale) +{ + bGPDlayer *gpl = (bGPDlayer *)ale->data; + + /* Make sure the selection flags agree with the "active" flag. + * The selection flags are used in the Dopesheet only, whereas + * the active flag is used everywhere else. Hence, we try to + * sync these here so that it all seems to be have as the user + * expects - T50184 + * + * Assume that we only really do this when the active status changes. + * (NOTE: This may prove annoying if it means selection is always lost) + */ + if (gpl->flag & GP_LAYER_ACTIVE) { + gpl->flag |= GP_LAYER_SELECT; + } + else { + gpl->flag &= ~GP_LAYER_SELECT; + } +} + /* ---------------- */ /* Main call to be exported to animation editors */ @@ -343,6 +365,10 @@ void ANIM_sync_animchannels_to_data(const bContext *C) case ANIMTYPE_FCURVE: animchan_sync_fcurve(&ac, ale, &active_fcurve); break; + + case ANIMTYPE_GPLAYER: + animchan_sync_gplayer(&ac, ale); + break; } } diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index a4afa958450..60c4b3593aa 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -60,6 +60,7 @@ void ED_undo_redo(struct bContext *C); void ED_OT_undo(struct wmOperatorType *ot); void ED_OT_undo_push(struct wmOperatorType *ot); void ED_OT_redo(struct wmOperatorType *ot); +void ED_OT_undo_redo(struct wmOperatorType *ot); void ED_OT_undo_history(struct wmOperatorType *ot); int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 80d091c0fdb..940e982d326 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1463,8 +1463,9 @@ void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *pr for (a = 0; item[a].identifier; a++) { if (item[a].value == ivalue) { const char *item_name = name ? name : CTX_IFACE_(RNA_property_translation_context(prop), item[a].name); + const int flag = item_name[0] ? 0 : UI_ITEM_R_ICON_ONLY; - uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name, icon ? icon : item[a].icon); + uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, flag, item_name, icon ? icon : item[a].icon); break; } } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 681b5954512..32b63aca34c 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -4334,6 +4334,7 @@ void ED_operatortypes_screen(void) WM_operatortype_append(ED_OT_undo); WM_operatortype_append(ED_OT_undo_push); WM_operatortype_append(ED_OT_redo); + WM_operatortype_append(ED_OT_undo_redo); WM_operatortype_append(ED_OT_undo_history); WM_operatortype_append(ED_OT_flush_edits); diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 671d6bb083e..83655a2ba9e 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -337,7 +337,7 @@ static void action_channel_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED( } break; case NC_GPENCIL: - if (wmn->action == NA_RENAME) + if (ELEM(wmn->action, NA_RENAME, NA_SELECTED)) ED_region_tag_redraw(ar); break; case NC_ID: @@ -407,10 +407,15 @@ static void action_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn) /* context changes */ switch (wmn->category) { case NC_GPENCIL: - if (wmn->action == NA_EDITED) { - /* only handle this event in GPencil mode for performance considerations */ - if (saction->mode == SACTCONT_GPENCIL) + /* only handle these events in GPencil mode for performance considerations */ + if (saction->mode == SACTCONT_GPENCIL) { + if (wmn->action == NA_EDITED) { ED_area_tag_redraw(sa); + } + else if (wmn->action == NA_SELECTED) { + saction->flag |= SACTION_TEMP_NEEDCHANSYNC; + ED_area_tag_refresh(sa); + } } break; case NC_ANIMATION: diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 6a1c0e7e4bf..324a3cb13b7 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1475,7 +1475,7 @@ static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op)) if (!ima || !iuser || !BKE_image_has_anim(ima)) return OPERATOR_CANCELLED; - struct ImageAnim *anim = ((ImageAnim *)ima->anims.first)->anim; + struct anim *anim = ((ImageAnim *)ima->anims.first)->anim; if (!anim) return OPERATOR_CANCELLED; iuser->frames = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN); diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index b9c8c98b62f..351c7ccec15 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -476,7 +476,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, totedgedata == 1 ? IFACE_("Crease:") : IFACE_("Mean Crease:"), 0, yi -= buth + but_margin, 200, buth, - &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by SubSurf modifier")); + &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by the Subdivision Surface modifier")); } } /* Curve... */ @@ -491,7 +491,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float else if (totcurvedata > 1) { uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"), 0, yi -= buth + but_margin, 200, buth, - &(tfp->ve_median[C_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for SoftBody Goal")); + &(tfp->ve_median[C_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for Soft Body Goal")); uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Radius:"), 0, yi -= buth + but_margin, 200, buth, &(tfp->ve_median[C_RADIUS]), 0.0, 100.0, 1, 3, TIP_("Radius of curve control points")); @@ -509,7 +509,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float else if (totlattdata > 1) { uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"), 0, yi -= buth + but_margin, 200, buth, - &(tfp->ve_median[L_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for SoftBody Goal")); + &(tfp->ve_median[L_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for Soft Body Goal")); } UI_block_align_end(block); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 620bbf03f32..2b53eb71d99 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -4064,6 +4064,9 @@ static int vieworbit_exec(bContext *C, wmOperator *op) mul_qt_qtqt(quat_new, rv3d->viewquat, quat_mul); + /* avoid precision loss over time */ + normalize_qt(quat_new); + if (view_opposite != RV3D_VIEW_USER) { rv3d->view = view_opposite; /* avoid float in-precision, just get a new orientation */ @@ -4130,6 +4133,10 @@ static void view_roll_angle(ARegion *ar, float quat[4], const float orig_quat[4] axis_angle_normalized_to_quat(quat_mul, dvec, angle); mul_qt_qtqt(quat, orig_quat, quat_mul); + + /* avoid precision loss over time */ + normalize_qt(quat); + rv3d->view = RV3D_VIEW_USER; } diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index 4a9311416b3..fab5b7e821f 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -327,6 +327,13 @@ static int ed_redo_exec(bContext *C, wmOperator *UNUSED(op)) return ed_undo_step(C, -1, NULL); } +static int ed_undo_redo_exec(bContext *C, wmOperator *UNUSED(op)) +{ + wmOperator *last_op = WM_operator_last_redo(C); + const int ret = ED_undo_operator_repeat(C, last_op); + return ret ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} + /* ********************** */ @@ -369,6 +376,17 @@ void ED_OT_redo(wmOperatorType *ot) ot->poll = ED_operator_screenactive; } +void ED_OT_undo_redo(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Undo and Redo"; + ot->description = "Undo and redo previous action"; + ot->idname = "ED_OT_undo_redo"; + + /* api callbacks */ + ot->exec = ed_undo_redo_exec; + ot->poll = ED_operator_screenactive; +} /* ui callbacks should call this rather than calling WM_operator_repeat() themselves */ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op) diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 8e4ba4c0afa..d8080002818 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -1222,7 +1222,7 @@ static int unwrap_exec(bContext *C, wmOperator *op) * pass operator for warning append */ modifier_unwrap_state(obedit, scene, &use_subsurf_final); if (use_subsurf != use_subsurf_final) - BKE_report(op->reports, RPT_INFO, "Subsurf modifier needs to be first to work with unwrap"); + BKE_report(op->reports, RPT_INFO, "Subdivision Surface modifier needs to be first to work with unwrap"); /* execute unwrap */ ED_unwrap_lscm(scene, obedit, true); @@ -1259,7 +1259,7 @@ void UV_OT_unwrap(wmOperatorType *ot) RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect", "Map UVs taking image aspect ratio into account"); RNA_def_boolean(ot->srna, "use_subsurf_data", 0, "Use Subsurf Modifier", - "Map UVs taking vertex position after subsurf into account"); + "Map UVs taking vertex position after Subdivision Surface modifier has been applied"); RNA_def_float_factor(ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f); } diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp index 2af4447e4dc..223bc607e21 100644 --- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp +++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp @@ -433,8 +433,8 @@ static void prepare(Render *re, SceneRenderLayer *srl) cout << "Crease angle : " << controller->getCreaseAngle() << endl; cout << "Sphere radius : " << controller->getSphereRadius() << endl; cout << "Face smoothness : " << (controller->getFaceSmoothness() ? "enabled" : "disabled") << endl; - cout << "Redges and valleys : " << (controller->getComputeRidgesAndValleysFlag() ? "enabled" : "disabled") << - endl; + cout << "Ridges and valleys : " << + (controller->getComputeRidgesAndValleysFlag() ? "enabled" : "disabled") << endl; cout << "Suggestive contours : " << (controller->getComputeSuggestiveContoursFlag() ? "enabled" : "disabled") << endl; cout << "Suggestive contour Kr derivative epsilon : " << diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.cpp b/source/blender/freestyle/intern/geometry/GeomUtils.cpp index 3eb92c559fe..cd7c1b83a4e 100644 --- a/source/blender/freestyle/intern/geometry/GeomUtils.cpp +++ b/source/blender/freestyle/intern/geometry/GeomUtils.cpp @@ -470,6 +470,8 @@ bool intersectRayTriangle(const Vec3r& orig, const Vec3r& dir, const Vec3r& v0, } // Intersection between plane and ray, adapted from Graphics Gems, Didier Badouel +// The plane is represented by a set of points P implicitly defined as dot(norm, P) + d = 0. +// The ray is represented as r(t) = orig + dir * t. intersection_test intersectRayPlane(const Vec3r& orig, const Vec3r& dir, const Vec3r& norm, const real d, real& t, const real epsilon) { diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp index 380bb0dd3ca..794c782bb73 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp +++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp @@ -57,7 +57,7 @@ using namespace std; template static void findOccludee(FEdge *fe, G& /*grid*/, I& occluders, real epsilon, WFace **oaWFace, - Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector& faceVertices) + Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edgeDir, vector& faceVertices) { WFace *face = NULL; if (fe->isSmooth()) { @@ -125,7 +125,7 @@ static void findOccludee(FEdge *fe, G& /*grid*/, I& occluders, real epsilon, WFa // check whether the edge and the polygon plane are coincident: //------------------------------------------------------------- //first let us compute the plane equation. - if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, p->getNormal(), d, t, epsilon)) + if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, p->getNormal(), d, t, epsilon)) { #if LOGGING if (_global.debug & G_DEBUG_FREESTYLE) { @@ -172,10 +172,11 @@ template static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge * /*ve*/, WFace **oaFace) { Vec3r A; - Vec3r edge; + Vec3r edgeDir; Vec3r origin; A = Vec3r(((fe)->vertexA()->point3D() + (fe)->vertexB()->point3D()) / 2.0); - edge = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D()); + edgeDir = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D()); + edgeDir.normalize(); origin = Vec3r((fe)->vertexA()->point3D()); Vec3r u; if (grid.orthographicProjection()) { @@ -199,7 +200,7 @@ static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge * /*ve*/, WF } I occluders(grid, A, epsilon); - findOccludee(fe, grid, occluders, epsilon, oaFace, u, A, origin, edge, faceVertices); + findOccludee(fe, grid, occluders, epsilon, oaFace, u, A, origin, edgeDir, faceVertices); } // computeVisibility takes a pointer to foundOccluders, instead of using a reference, @@ -211,11 +212,12 @@ static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon, int qi = 0; Vec3r center; - Vec3r edge; + Vec3r edgeDir; Vec3r origin; center = fe->center3d(); - edge = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D()); + edgeDir = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D()); + edgeDir.normalize(); origin = Vec3r(fe->vertexA()->point3D()); Vec3r vp; @@ -337,7 +339,7 @@ static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon, // check whether the edge and the polygon plane are coincident: //------------------------------------------------------------- //first let us compute the plane equation. - if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, p->getNormal(), d, t, epsilon)) { + if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, p->getNormal(), d, t, epsilon)) { #if LOGGING if (_global.debug & G_DEBUG_FREESTYLE) { cout << "\t\tRejecting occluder for target coincidence." << endl; @@ -391,7 +393,7 @@ static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon, } // Find occludee - findOccludee(fe, grid, occluders, epsilon, oaWFace, u, center, origin, edge, faceVertices); + findOccludee(fe, grid, occluders, epsilon, oaWFace, u, center, origin, edgeDir, faceVertices); return qi; } @@ -1788,7 +1790,7 @@ void ViewMapBuilder::ComputeVeryFastRayCastingVisibility(ViewMap *ioViewMap, rea } void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp, - Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector& faceVertices) + Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edgeDir, vector& faceVertices) { WFace *face = NULL; if (fe->isSmooth()) { @@ -1856,7 +1858,7 @@ void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3 continue; } else { - if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, normal, d, t, epsilon)) + if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, normal, d, t, epsilon)) continue; } if ((*p)->rayIntersect(A, v, t, t_u, t_v)) { @@ -1883,10 +1885,11 @@ void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3 OccludersSet occluders; Vec3r A; - Vec3r edge; + Vec3r edgeDir; Vec3r origin; A = Vec3r(((fe)->vertexA()->point3D() + (fe)->vertexB()->point3D()) / 2.0); - edge = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D()); + edgeDir = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D()); + edgeDir.normalize(); origin = Vec3r((fe)->vertexA()->point3D()); Vec3r u; if (_orthographicProjection) { @@ -1910,7 +1913,7 @@ void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3 if (face) face->RetrieveVertexList(faceVertices); - return FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, A, origin, edge, faceVertices); + return FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, A, origin, edgeDir, faceVertices); } int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real epsilon, set& oOccluders, @@ -1920,11 +1923,12 @@ int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real eps int qi = 0; Vec3r center; - Vec3r edge; + Vec3r edgeDir; Vec3r origin; center = fe->center3d(); - edge = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D()); + edgeDir = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D()); + edgeDir.normalize(); origin = Vec3r(fe->vertexA()->point3D()); // Is the edge outside the view frustum ? Vec3r gridOrigin(iGrid->getOrigin()); @@ -2062,7 +2066,7 @@ int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real eps //------------------------------------------------------------- //first let us compute the plane equation. - if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, normal, d, t, epsilon)) { + if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, normal, d, t, epsilon)) { #if LOGGING if (_global.debug & G_DEBUG_FREESTYLE) { cout << "\t\tRejecting occluder for target coincidence." << endl; @@ -2099,7 +2103,7 @@ int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real eps } // Find occludee - FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, center, origin, edge, faceVertices); + FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, center, origin, edgeDir, faceVertices); return qi; } diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h index 36497bf8d22..440ae93c7df 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h +++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h @@ -250,7 +250,7 @@ protected: // FIXME void FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp); void FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp, - Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector& faceVertices); + Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edgeDir, vector& faceVertices); #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:ViewMapBuilder") diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 69ee671901a..41a73cfc528 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -1276,13 +1276,13 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_ACTIVE); RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencilLayer_active_set"); RNA_def_property_ui_text(prop, "Active", "Set active layer for editing"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL); #endif prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_SELECT); RNA_def_property_ui_text(prop, "Select", "Layer is selected for editing in the Dope Sheet"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, "rna_GPencil_update"); /* XXX keep this option? */ prop = RNA_def_property(srna, "show_points", PROP_BOOLEAN, PROP_NONE); @@ -1370,14 +1370,15 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_layer_get", "rna_GPencil_active_layer_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Active Layer", "Active grease pencil layer"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL); prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_funcs(prop, "rna_GPencil_active_layer_index_get", "rna_GPencil_active_layer_index_set", "rna_GPencil_active_layer_index_range"); RNA_def_property_ui_text(prop, "Active Layer Index", "Index of active grease pencil layer"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL); } static void rna_def_gpencil_palettecolor(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 673f7acbd6a..244820f5a49 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -116,6 +116,13 @@ #endif +static void rna_idname_validate(const char *name, char *r_name) +{ + BLI_strncpy(r_name, name, MAX_ID_NAME - 2); + BLI_utf8_invalid_strip(r_name, strlen(r_name)); +} + + static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink) { ID *id = id_ptr->data; @@ -137,14 +144,20 @@ static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ static Camera *rna_Main_cameras_new(Main *bmain, const char *name) { - ID *id = BKE_camera_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + ID *id = BKE_camera_add(bmain, safe_name); id_us_min(id); return (Camera *)id; } static Scene *rna_Main_scenes_new(Main *bmain, const char *name) { - return BKE_scene_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + return BKE_scene_add(bmain, safe_name); } static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr, int do_unlink) { @@ -180,6 +193,9 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char *name, ID *data) { + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + Object *ob; int type = OB_EMPTY; if (data) { @@ -223,7 +239,7 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char id_us_plus(data); } - ob = BKE_object_add_only_object(bmain, type, name); + ob = BKE_object_add_only_object(bmain, type, safe_name); id_us_min(&ob->id); ob->data = data; @@ -234,7 +250,10 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char static Material *rna_Main_materials_new(Main *bmain, const char *name) { - ID *id = (ID *)BKE_material_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + ID *id = (ID *)BKE_material_add(bmain, safe_name); id_us_min(id); return (Material *)id; } @@ -245,20 +264,27 @@ static EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), Point } static struct bNodeTree *rna_Main_nodetree_new(Main *bmain, const char *name, int type) { + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + bNodeTreeType *typeinfo = rna_node_tree_type_from_enum(type); if (typeinfo) { - bNodeTree *ntree = ntreeAddTree(bmain, name, typeinfo->idname); + bNodeTree *ntree = ntreeAddTree(bmain, safe_name, typeinfo->idname); id_us_min(&ntree->id); return ntree; } - else + else { return NULL; + } } static Mesh *rna_Main_meshes_new(Main *bmain, const char *name) { - Mesh *me = BKE_mesh_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Mesh *me = BKE_mesh_add(bmain, safe_name); id_us_min(&me->id); return me; } @@ -286,7 +312,10 @@ Mesh *rna_Main_meshes_new_from_object( static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type) { - Lamp *lamp = BKE_lamp_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Lamp *lamp = BKE_lamp_add(bmain, safe_name); lamp->type = type; id_us_min(&lamp->id); return lamp; @@ -294,8 +323,11 @@ static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type) static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer, int stereo3d) { + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + float color[4] = {0.0, 0.0, 0.0, 1.0}; - Image *image = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, float_buffer, 0, color, stereo3d); + Image *image = BKE_image_add_generated(bmain, width, height, safe_name, alpha ? 32 : 24, float_buffer, 0, color, stereo3d); id_us_min(&image->id); return image; } @@ -322,21 +354,30 @@ static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char static Lattice *rna_Main_lattices_new(Main *bmain, const char *name) { - Lattice *lt = BKE_lattice_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Lattice *lt = BKE_lattice_add(bmain, safe_name); id_us_min(<->id); return lt; } static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type) { - Curve *cu = BKE_curve_add(bmain, name, type); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Curve *cu = BKE_curve_add(bmain, safe_name, type); id_us_min(&cu->id); return cu; } static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name) { - MetaBall *mb = BKE_mball_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + MetaBall *mb = BKE_mball_add(bmain, safe_name); id_us_min(&mb->id); return mb; } @@ -364,7 +405,10 @@ static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char * static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type) { - Tex *tex = BKE_texture_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Tex *tex = BKE_texture_add(bmain, safe_name); BKE_texture_type_set(tex, type); id_us_min(&tex->id); return tex; @@ -372,26 +416,38 @@ static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type) static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode) { - Brush *brush = BKE_brush_add(bmain, name, mode); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Brush *brush = BKE_brush_add(bmain, safe_name, mode); id_us_min(&brush->id); return brush; } static World *rna_Main_worlds_new(Main *bmain, const char *name) { - World *world = add_world(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + World *world = add_world(bmain, safe_name); id_us_min(&world->id); return world; } static Group *rna_Main_groups_new(Main *bmain, const char *name) { - return BKE_group_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + return BKE_group_add(bmain, safe_name); } static Speaker *rna_Main_speakers_new(Main *bmain, const char *name) { - Speaker *speaker = BKE_speaker_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Speaker *speaker = BKE_speaker_add(bmain, safe_name); id_us_min(&speaker->id); return speaker; } @@ -413,7 +469,10 @@ static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_exi static Text *rna_Main_texts_new(Main *bmain, const char *name) { - return BKE_text_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + return BKE_text_add(bmain, safe_name); } static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *filepath, int is_internal) @@ -432,28 +491,40 @@ static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *f static bArmature *rna_Main_armatures_new(Main *bmain, const char *name) { - bArmature *arm = BKE_armature_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + bArmature *arm = BKE_armature_add(bmain, safe_name); id_us_min(&arm->id); return arm; } static bAction *rna_Main_actions_new(Main *bmain, const char *name) { - bAction *act = add_empty_action(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + bAction *act = add_empty_action(bmain, safe_name); id_fake_user_clear(&act->id); return act; } static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name) { - ParticleSettings *part = psys_new_settings(name, bmain); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + ParticleSettings *part = psys_new_settings(safe_name, bmain); id_us_min(&part->id); return part; } static Palette *rna_Main_palettes_new(Main *bmain, const char *name) { - Palette *palette = BKE_palette_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Palette *palette = BKE_palette_add(bmain, safe_name); id_us_min(&palette->id); return (Palette *)palette; } @@ -481,16 +552,18 @@ static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, cons static Mask *rna_Main_mask_new(Main *bmain, const char *name) { - Mask *mask; + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); - mask = BKE_mask_new(bmain, name); - - return mask; + return BKE_mask_new(bmain, safe_name); } static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name) { - FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, safe_name); id_us_min(&linestyle->id); return linestyle; } diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 3dc58442851..ad5f320625c 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1962,7 +1962,7 @@ static void rna_def_medge(BlenderRNA *brna) prop = RNA_def_property(srna, "crease", PROP_FLOAT, PROP_NONE); RNA_def_property_float_funcs(prop, "rna_MEdge_crease_get", "rna_MEdge_crease_set", NULL); - RNA_def_property_ui_text(prop, "Crease", "Weight used by the Subsurf modifier for creasing"); + RNA_def_property_ui_text(prop, "Crease", "Weight used by the Subdivision Surface modifier for creasing"); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "bevel_weight", PROP_FLOAT, PROP_NONE); @@ -1987,7 +1987,7 @@ static void rna_def_medge(BlenderRNA *brna) prop = RNA_def_property(srna, "use_edge_sharp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SHARP); - RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the EdgeSplit modifier"); + RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the Edge Split modifier"); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "is_loose", PROP_BOOLEAN, PROP_NONE); @@ -3560,7 +3560,7 @@ static void rna_def_mesh(BlenderRNA *brna) prop = RNA_def_property(srna, "show_edge_crease", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWCREASES); - RNA_def_property_ui_text(prop, "Draw Creases", "Display creases created for subsurf weighting"); + RNA_def_property_ui_text(prop, "Draw Creases", "Display creases created for Subdivision Surface modifier"); RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); prop = RNA_def_property(srna, "show_edge_bevel_weight", PROP_BOOLEAN, PROP_NONE); @@ -3575,7 +3575,7 @@ static void rna_def_mesh(BlenderRNA *brna) prop = RNA_def_property(srna, "show_edge_sharp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWSHARP); - RNA_def_property_ui_text(prop, "Draw Sharp", "Display sharp edges, used with the EdgeSplit modifier"); + RNA_def_property_ui_text(prop, "Draw Sharp", "Display sharp edges, used with the Edge Split modifier"); RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); prop = RNA_def_property(srna, "show_freestyle_edge_marks", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index ae444acc432..3e6d8441363 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1674,7 +1674,7 @@ static void rna_def_filter_video(StructRNA *srna) prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_FILTERY); - RNA_def_property_ui_text(prop, "De-Interlace", "For video movies to remove fields"); + RNA_def_property_ui_text(prop, "Deinterlace", "Remove fields from video movies"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update_reopen_files"); prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index beb1d890ba9..e68e67586e9 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -3287,7 +3287,7 @@ static void rna_def_userdef_walk_navigation(BlenderRNA *brna) prop = RNA_def_property(srna, "use_mouse_reverse", PROP_BOOLEAN, PROP_BOOLEAN); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_WALK_MOUSE_REVERSE); - RNA_def_property_ui_text(prop, "Reverse Mouse", "Reverse the mouse look"); + RNA_def_property_ui_text(prop, "Reverse Mouse", "Reverse the vertical movement of the mouse"); } static void rna_def_userdef_view(BlenderRNA *brna) @@ -4332,7 +4332,7 @@ static void rna_def_userdef_input(BlenderRNA *brna) prop = RNA_def_property(srna, "ndof_deadzone", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Deadzone", "Deadzone of the 3D Mouse"); + RNA_def_property_ui_text(prop, "Deadzone", "Threshold of initial movement needed from the device's rest position"); RNA_def_property_update(prop, 0, "rna_userdef_ndof_deadzone_update"); prop = RNA_def_property(srna, "ndof_pan_yz_swap_axis", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 92931eb8090..5fbe1ab971a 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -36,12 +36,15 @@ #include "DNA_scene_types.h" #include "DNA_anim_types.h" + #include "ED_keyframing.h" +#include "ED_keyframes_edit.h" #include "BKE_report.h" #include "BKE_context.h" #include "BKE_animsys.h" #include "BKE_fcurve.h" +#include "BKE_idcode.h" #include "RNA_access.h" #include "RNA_enum_types.h" @@ -223,9 +226,47 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb { return NULL; } - else { - short result; + else if (self->ptr.type == &RNA_NlaStrip) { + /* Handle special properties for NLA Strips, whose F-Curves are stored on the + * strips themselves. These are stored separately or else the properties will + * not have any effect. + */ ReportList reports; + short result = 0; + + PointerRNA ptr = self->ptr; + PropertyRNA *prop = NULL; + const char *prop_name; + + BKE_reports_init(&reports, RPT_STORE); + + /* Retrieve the property identifier from the full path, since we can't get it any other way */ + prop_name = strrchr(path_full, '.'); + if ((prop_name >= path_full) && + (prop_name + 1 < path_full + strlen(path_full))) + { + prop = RNA_struct_find_property(&ptr, prop_name + 1); + } + + if (prop) { + NlaStrip *strip = (NlaStrip *)ptr.data; + FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); + + result = insert_keyframe_direct(&reports, ptr, prop, fcu, cfra, keytype, index); + } + else { + BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full); + } + MEM_freeN((void *)path_full); + + if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) + return NULL; + + return PyBool_FromLong(result); + } + else { + ReportList reports; + short result; BKE_reports_init(&reports, RPT_STORE); @@ -272,6 +313,67 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb { return NULL; } + else if (self->ptr.type == &RNA_NlaStrip) { + /* Handle special properties for NLA Strips, whose F-Curves are stored on the + * strips themselves. These are stored separately or else the properties will + * not have any effect. + */ + ReportList reports; + short result = 0; + + PointerRNA ptr = self->ptr; + PropertyRNA *prop = NULL; + const char *prop_name; + + BKE_reports_init(&reports, RPT_STORE); + + /* Retrieve the property identifier from the full path, since we can't get it any other way */ + prop_name = strrchr(path_full, '.'); + if ((prop_name >= path_full) && + (prop_name + 1 < path_full + strlen(path_full))) + { + prop = RNA_struct_find_property(&ptr, prop_name + 1); + } + + if (prop) { + ID *id = ptr.id.data; + NlaStrip *strip = (NlaStrip *)ptr.data; + FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); + + BLI_assert(fcu != NULL); /* NOTE: This should be true, or else we wouldn't be able to get here */ + + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf(&reports, RPT_WARNING, + "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'", + strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2); + } + else { + /* remove the keyframe directly + * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve, + * and delete_keyframe() expects the FCurve to be part of an action + */ + bool found = false; + int i; + + /* try to find index of beztriple to get rid of */ + i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); + if (found) { + /* delete the key at the index (will sanity check + do recalc afterwards) */ + delete_fcurve_key(fcu, i, 1); + result = true; + } + } + } + else { + BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full); + } + MEM_freeN((void *)path_full); + + if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) + return NULL; + + return PyBool_FromLong(result); + } else { short result; ReportList reports;