Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2013-03-03 19:07:49 +0400
committerTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>2013-03-03 19:07:49 +0400
commit66a2b848972d47a033f617a40f9a9044756d1d32 (patch)
treebf30f5bc13e9c0b4f52aacead676a2c07cbb331a /source/blender
parent0c5dfc8a639b04e1767852121b9dee7cd5bb050f (diff)
parent4774357b594c5cd5a38b21df131b539a197c101b (diff)
Merged changes in the trunk up to revision 54992.
Resolved conflicts: release/scripts/startup/bl_ui/space_view3d.py
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_depsgraph.h178
-rw-r--r--source/blender/blenkernel/BKE_report.h2
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h1
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h3
-rw-r--r--source/blender/blenkernel/depsgraph_private.h32
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c2
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c557
-rw-r--r--source/blender/blenkernel/intern/fcurve.c101
-rw-r--r--source/blender/blenkernel/intern/mask.c2
-rw-r--r--source/blender/blenkernel/intern/mesh.c20
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c6
-rw-r--r--source/blender/blenkernel/intern/modifier.c4
-rw-r--r--source/blender/blenkernel/intern/movieclip.c16
-rw-r--r--source/blender/blenkernel/intern/node.c7
-rw-r--r--source/blender/blenkernel/intern/pbvh.c16
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c5
-rw-r--r--source/blender/blenkernel/intern/pointcache.c2
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c42
-rw-r--r--source/blender/blenkernel/intern/scene.c53
-rw-r--r--source/blender/blenkernel/intern/seqmodifier.c8
-rw-r--r--source/blender/blenkernel/intern/sequencer.c34
-rw-r--r--source/blender/blenkernel/intern/text.c1
-rw-r--r--source/blender/blenkernel/intern/tracking.c119
-rw-r--r--source/blender/blenlib/BLI_math_geom.h5
-rw-r--r--source/blender/blenlib/BLI_utildefines.h3
-rw-r--r--source/blender/blenlib/intern/math_geom.c18
-rw-r--r--source/blender/blenlib/intern/threads.c8
-rw-r--r--source/blender/blenloader/intern/readfile.c31
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators_inline.h20
-rw-r--r--source/blender/bmesh/operators/bmo_hull.c5
-rw-r--r--source/blender/collada/ArmatureImporter.cpp4
-rw-r--r--source/blender/collada/ArmatureImporter.h3
-rw-r--r--source/blender/collada/CMakeLists.txt2
-rw-r--r--source/blender/collada/ControllerExporter.cpp57
-rw-r--r--source/blender/collada/DocumentImporter.cpp5
-rw-r--r--source/blender/collada/ExportSettings.h1
-rw-r--r--source/blender/collada/GeometryExporter.cpp230
-rw-r--r--source/blender/collada/GeometryExporter.h10
-rw-r--r--source/blender/collada/MeshImporter.cpp560
-rw-r--r--source/blender/collada/MeshImporter.h48
-rw-r--r--source/blender/collada/SConscript4
-rw-r--r--source/blender/collada/TransformReader.cpp44
-rw-r--r--source/blender/collada/collada.cpp2
-rw-r--r--source/blender/collada/collada.h1
-rw-r--r--source/blender/collada/collada_utils.cpp43
-rw-r--r--source/blender/collada/collada_utils.h22
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cpp12
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.h2
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c16
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c4
-rw-r--r--source/blender/editors/armature/CMakeLists.txt19
-rw-r--r--source/blender/editors/armature/armature_add.c849
-rw-r--r--source/blender/editors/armature/armature_edit.c1245
-rw-r--r--source/blender/editors/armature/armature_intern.h38
-rw-r--r--source/blender/editors/armature/armature_naming.c368
-rw-r--r--source/blender/editors/armature/armature_ops.c8
-rw-r--r--source/blender/editors/armature/armature_relations.c774
-rw-r--r--source/blender/editors/armature/armature_select.c940
-rw-r--r--source/blender/editors/armature/armature_skinning.c441
-rw-r--r--source/blender/editors/armature/armature_utils.c671
-rw-r--r--source/blender/editors/armature/editarmature.c6197
-rw-r--r--source/blender/editors/armature/editarmature_generate.c11
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c13
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c9
-rw-r--r--source/blender/editors/armature/meshlaplacian.c8
-rw-r--r--source/blender/editors/armature/pose_edit.c1180
-rw-r--r--source/blender/editors/armature/pose_group.c523
-rw-r--r--source/blender/editors/armature/pose_lib.c (renamed from source/blender/editors/armature/poselib.c)10
-rw-r--r--source/blender/editors/armature/pose_select.c853
-rw-r--r--source/blender/editors/armature/pose_slide.c (renamed from source/blender/editors/armature/poseSlide.c)12
-rw-r--r--source/blender/editors/armature/pose_transform.c879
-rw-r--r--source/blender/editors/armature/pose_utils.c (renamed from source/blender/editors/armature/poseUtils.c)13
-rw-r--r--source/blender/editors/armature/poseobject.c2364
-rw-r--r--source/blender/editors/armature/reeb.c15
-rw-r--r--source/blender/editors/curve/CMakeLists.txt5
-rw-r--r--source/blender/editors/curve/SConscript9
-rw-r--r--source/blender/editors/curve/editcurve.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c3
-rw-r--r--source/blender/editors/include/ED_armature.h2
-rw-r--r--source/blender/editors/include/ED_view3d.h14
-rw-r--r--source/blender/editors/include/UI_interface.h1
-rw-r--r--source/blender/editors/interface/interface.c75
-rw-r--r--source/blender/editors/interface/interface_handlers.c292
-rw-r--r--source/blender/editors/interface/interface_intern.h11
-rw-r--r--source/blender/editors/interface/interface_layout.c4
-rw-r--r--source/blender/editors/interface/interface_ops.c218
-rw-r--r--source/blender/editors/interface/interface_templates.c3
-rw-r--r--source/blender/editors/interface/interface_widgets.c2
-rw-r--r--source/blender/editors/interface/view2d_ops.c7
-rw-r--r--source/blender/editors/io/CMakeLists.txt4
-rw-r--r--source/blender/editors/io/SConscript3
-rw-r--r--source/blender/editors/io/io_collada.c11
-rw-r--r--source/blender/editors/mesh/editface.c14
-rw-r--r--source/blender/editors/mesh/editmesh_select.c46
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c3
-rw-r--r--source/blender/editors/mesh/meshtools.c6
-rw-r--r--source/blender/editors/object/object_add.c85
-rw-r--r--source/blender/editors/object/object_constraint.c12
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/object/object_select.c4
-rw-r--r--source/blender/editors/object/object_transform.c2
-rw-r--r--source/blender/editors/object/object_vgroup.c8
-rw-r--r--source/blender/editors/physics/physics_pointcache.c26
-rw-r--r--source/blender/editors/screen/area.c8
-rw-r--r--source/blender/editors/screen/screen_ops.c10
-rw-r--r--source/blender/editors/screen/screendump.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h2
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c44
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c2
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c4
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c2
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c2
-rw-r--r--source/blender/editors/space_file/file_ops.c9
-rw-r--r--source/blender/editors/space_file/fsmenu.h2
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c39
-rw-r--r--source/blender/editors/space_image/image_buttons.c22
-rw-r--r--source/blender/editors/space_image/image_intern.h2
-rw-r--r--source/blender/editors/space_image/image_ops.c8
-rw-r--r--source/blender/editors/space_image/space_image.c2
-rw-r--r--source/blender/editors/space_info/info_ops.c10
-rw-r--r--source/blender/editors/space_info/info_stats.c18
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c12
-rw-r--r--source/blender/editors/space_nla/nla_edit.c4
-rw-r--r--source/blender/editors/space_node/drawnode.c7
-rw-r--r--source/blender/editors/space_node/node_add.c1
-rw-r--r--source/blender/editors/space_node/node_group.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c71
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c9
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c2
-rw-r--r--source/blender/editors/space_text/text_format.c2
-rw-r--r--source/blender/editors/space_text/text_header.c25
-rw-r--r--source/blender/editors/space_text/text_ops.c26
-rw-r--r--source/blender/editors/space_view3d/drawobject.c17
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c31
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c324
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c17
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h4
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c36
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c6
-rw-r--r--source/blender/editors/transform/transform.c27
-rw-r--r--source/blender/editors/transform/transform.h3
-rw-r--r--source/blender/editors/transform/transform_conversions.c2
-rw-r--r--source/blender/editors/transform/transform_manipulator.c310
-rw-r--r--source/blender/editors/transform/transform_ops.c4
-rw-r--r--source/blender/editors/util/ed_util.c22
-rw-r--r--source/blender/editors/util/undo.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c24
-rw-r--r--source/blender/gpu/CMakeLists.txt5
-rw-r--r--source/blender/gpu/GPU_extensions.h32
-rw-r--r--source/blender/gpu/SConscript4
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c8
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c44
-rw-r--r--source/blender/gpu/intern/gpu_fixed_material.c191
-rw-r--r--source/blender/gpu/intern/gpu_material.c2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fixed_fragment.glsl169
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fixed_vertex.glsl48
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex.glsl6
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp6
-rw-r--r--source/blender/imbuf/intern/colormanagement.c41
-rw-r--r--source/blender/imbuf/intern/filetype.c5
-rw-r--r--source/blender/imbuf/intern/imageprocess.c6
-rw-r--r--source/blender/imbuf/intern/jp2.c2
-rw-r--r--source/blender/makesdna/DNA_action_types.h6
-rw-r--r--source/blender/makesdna/DNA_actuator_types.h6
-rw-r--r--source/blender/makesdna/DNA_anim_types.h11
-rw-r--r--source/blender/makesdna/DNA_controller_types.h5
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h4
-rw-r--r--source/blender/makesdna/DNA_defs.h2
-rw-r--r--source/blender/makesdna/DNA_group_types.h4
-rw-r--r--source/blender/makesdna/DNA_image_types.h4
-rw-r--r--source/blender/makesdna/DNA_key_types.h4
-rw-r--r--source/blender/makesdna/DNA_mask_types.h3
-rw-r--r--source/blender/makesdna/DNA_node_types.h3
-rw-r--r--source/blender/makesdna/DNA_property_types.h5
-rw-r--r--source/blender/makesdna/DNA_rigidbody_types.h4
-rw-r--r--source/blender/makesdna/DNA_sensor_types.h4
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h10
-rw-r--r--source/blender/makesdna/DNA_space_types.h9
-rw-r--r--source/blender/makesdna/DNA_text_types.h5
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h4
-rw-r--r--source/blender/makesdna/DNA_vfont_types.h5
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt3
-rw-r--r--source/blender/makesrna/intern/rna_access.c12
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c7
-rw-r--r--source/blender/makesrna/intern/rna_particle.c2
-rw-r--r--source/blender/makesrna/intern/rna_render.c6
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c19
-rw-r--r--source/blender/makesrna/intern/rna_scene.c13
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_space.c30
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c3
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c227
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c2
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c5
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c1
-rw-r--r--source/blender/nodes/intern/node_exec.c5
-rw-r--r--source/blender/python/intern/bpy_rna.c33
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c3
-rw-r--r--source/blender/render/CMakeLists.txt3
-rw-r--r--source/blender/render/intern/raytrace/reorganize.h3
-rw-r--r--source/blender/render/intern/source/occlusion.c416
-rw-r--r--source/blender/render/intern/source/pipeline.c2
-rw-r--r--source/blender/windowmanager/WM_api.h2
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c19
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c11
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c7
214 files changed, 11643 insertions, 11780 deletions
diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h
index 4cdfc1cba95..6baf20aeb2c 100644
--- a/source/blender/blenkernel/BKE_depsgraph.h
+++ b/source/blender/blenkernel/BKE_depsgraph.h
@@ -30,114 +30,94 @@
* \ingroup bke
*/
+/* Dependency Graph
+ *
+ * The dependency graph tracks relations between datablocks, and is used to
+ * determine which datablocks need to be update based on dependencies and
+ * visibility.
+ *
+ * It does not itself execute changes in objects, but rather sorts the objects
+ * in the appropriate order and sets flags indicating they should be updated.
+ */
+
#ifdef __cplusplus
extern "C" {
#endif
-// #define DEPS_DEBUG
-
-struct DagForest;
-struct DagNode;
-struct DagNodeQueue;
-struct GHash;
struct ID;
struct Main;
struct Object;
struct Scene;
-/* **** DAG relation types *** */
-
-/* scene link to object */
-#define DAG_RL_SCENE (1 << 0)
-/* object link to data */
-#define DAG_RL_DATA (1 << 1)
-
-/* object changes object (parent, track, constraints) */
-#define DAG_RL_OB_OB (1 << 2)
-/* object changes obdata (hooks, constraints) */
-#define DAG_RL_OB_DATA (1 << 3)
-/* data changes object (vertex parent) */
-#define DAG_RL_DATA_OB (1 << 4)
-/* data changes data (deformers) */
-#define DAG_RL_DATA_DATA (1 << 5)
-
-#define DAG_NO_RELATION (1 << 6)
-
-#define DAG_RL_ALL_BUT_DATA (DAG_RL_SCENE | DAG_RL_OB_OB | DAG_RL_OB_DATA | DAG_RL_DATA_OB | DAG_RL_DATA_DATA)
-#define DAG_RL_ALL (DAG_RL_ALL_BUT_DATA | DAG_RL_DATA)
-
-
-typedef void (*graph_action_func)(void *ob, void **data);
-
-// queues are returned by all BFS & DFS queries
-// opaque type
-void *pop_ob_queue(struct DagNodeQueue *queue);
-int queue_count(struct DagNodeQueue *queue);
-void queue_delete(struct DagNodeQueue *queue);
-
-// queries
-struct DagForest *build_dag(struct Main *bmain, struct Scene *sce, short mask);
-void free_forest(struct DagForest *Dag);
-
-// note :
-// the meanings of the 2 returning values is a bit different :
-// BFS return 1 for cross-edges and back-edges. the latter are considered harmfull, not the former
-// DFS return 1 only for back-edges
-int pre_and_post_BFS(struct DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data);
-int pre_and_post_DFS(struct DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data);
-
-int pre_and_post_source_BFS(struct DagForest *dag, short mask, struct DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data);
-int pre_and_post_source_DFS(struct DagForest *dag, short mask, struct DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data);
-
-struct DagNodeQueue *get_obparents(struct DagForest *dag, void *ob);
-struct DagNodeQueue *get_first_ancestors(struct DagForest *dag, void *ob);
-struct DagNodeQueue *get_all_childs(struct DagForest *dag, void *ob);
-short are_obs_related(struct DagForest *dag, void *ob1, void *ob2);
-int is_acyclic(struct DagForest *dag);
-//int get_cycles(struct DagForest *dag, struct DagNodeQueue **queues, int *count); //
-
-/* ********** API *************** */
-/* Note that the DAG never executes changes in Objects, only sets flags in Objects */
-
-/* clear all dependency graphs, call this when changing relations between objects.
- * the dependency graphs will be rebuilt just before they are used to avoid them
- * getting rebuild many times during operators */
-void DAG_relations_tag_update(struct Main *bmain);
-
-/* (re)-create the dependency graph before using it */
-void DAG_scene_relations_update(struct Main *bmain, struct Scene *sce);
-
-/* force an immediate rebuild of the dependency graph, only needed in rare cases */
-void DAG_scene_relations_rebuild(struct Main *bmain, struct Scene *scene);
-
-/* flag all objects that need recalc because they're animated */
-void DAG_scene_update_flags(struct Main *bmain, struct Scene *sce, unsigned int lay, const short do_time);
-/* flushes all recalc flags in objects down the dependency tree */
-void DAG_scene_flush_update(struct Main *bmain, struct Scene *sce, unsigned int lay, const short do_time);
-/* tag objects for update on file load */
-void DAG_on_visible_update(struct Main *bmain, const short do_time);
-
-/* tag datablock to get updated for the next redraw */
-void DAG_id_tag_update_ex(struct Main *bmain, struct ID *id, short flag);
-void DAG_id_tag_update(struct ID *id, short flag);
-/* flush all tagged updates */
-void DAG_ids_flush_tagged(struct Main *bmain);
-/* check and clear ID recalc flags */
-void DAG_ids_check_recalc(struct Main *bmain, struct Scene *scene, int time);
-void DAG_ids_clear_recalc(struct Main *bmain);
-/* test if any of this id type is tagged for update */
-void DAG_id_type_tag(struct Main *bmain, short idtype);
-int DAG_id_type_tagged(struct Main *bmain, short idtype);
-
-/* (re)-create dependency graph for armature pose */
-void DAG_pose_sort(struct Object *ob);
-
-/* callback for editors module to do updates */
-void DAG_editors_update_cb(void (*id_func)(struct Main *bmain, struct ID *id),
- void (*scene_func)(struct Main *bmain, struct Scene *scene, int updated));
-
-/* debugging */
-void DAG_print_dependencies(struct Main *bmain, struct Scene *scene, struct Object *ob);
+/* Build and Update
+ *
+ * DAG_scene_relations_update will rebuild the dependency graph for a given
+ * scene if needed, and sort objects in the scene.
+ *
+ * DAG_relations_tag_update will clear all dependency graphs and mark them to
+ * be rebuilt later. The graph is not rebuilt immediately to avoid slowdowns
+ * when this function is call multiple times from different operators.
+ *
+ * DAG_scene_relations_rebuild forces an immediaterebuild of the dependency
+ * graph, this is only needed in rare cases
+ */
+
+void DAG_scene_relations_update(struct Main *bmain, struct Scene *sce);
+void DAG_relations_tag_update(struct Main *bmain);
+void DAG_scene_relations_rebuild(struct Main *bmain, struct Scene *scene);
+void DAG_scene_free(struct Scene *sce);
+
+/* Update Tagging
+ *
+ * DAG_scene_update_flags will mark all objects that depend on time (animation,
+ * physics, ..) to be recalculated, used when changing the current frame.
+ *
+ * DAG_on_visible_update will mark all objects that are visible for the first
+ * time to be updated, for example on file load or changing layer visibility.
+ *
+ * DAG_id_tag_update will mark a given datablock to be updated. The flag indicates
+ * a specific subset to be update (only object transform and data for now).
+ *
+ * DAG_id_type_tag marks a particular datablock type as having changing. This does
+ * not cause any updates but is used by external render engines to detect if for
+ * example a datablock was removed. */
+
+void DAG_scene_update_flags(struct Main *bmain, struct Scene *sce, unsigned int lay, const short do_time);
+void DAG_on_visible_update(struct Main *bmain, const short do_time);
+
+void DAG_id_tag_update(struct ID *id, short flag);
+void DAG_id_tag_update_ex(struct Main *bmain, struct ID *id, short flag);
+void DAG_id_type_tag(struct Main *bmain, short idtype);
+int DAG_id_type_tagged(struct Main *bmain, short idtype);
+
+/* Flushing Tags
+ *
+ * DAG_scene_flush_update flushes object recalculation flags immediately to other
+ * dependencies. Do not use outside of depsgraph.c, this will be removed.
+ *
+ * DAG_ids_flush_tagged will flush datablock update flags flags to dependencies,
+ * use this right before updating to mark all the needed datablocks for update.
+ *
+ * DAG_ids_check_recalc and DAG_ids_clear_recalc are used for external render
+ * engines to detect changes. */
+
+void DAG_scene_flush_update(struct Main *bmain, struct Scene *sce, unsigned int lay, const short do_time);
+void DAG_ids_flush_tagged(struct Main *bmain);
+void DAG_ids_check_recalc(struct Main *bmain, struct Scene *scene, int time);
+void DAG_ids_clear_recalc(struct Main *bmain);
+
+/* Armature: sorts the bones according to dependencies between them */
+
+void DAG_pose_sort(struct Object *ob);
+
+/* Editors: callbacks to notify editors of datablock changes */
+
+void DAG_editors_update_cb(void (*id_func)(struct Main *bmain, struct ID *id),
+ void (*scene_func)(struct Main *bmain, struct Scene *scene, int updated));
+
+/* Debugging: print dependency graph for scene or armature object to console */
+
+void DAG_print_dependencies(struct Main *bmain, struct Scene *scene, struct Object *ob);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_report.h b/source/blender/blenkernel/BKE_report.h
index e659954a3ac..4dc16f6266f 100644
--- a/source/blender/blenkernel/BKE_report.h
+++ b/source/blender/blenkernel/BKE_report.h
@@ -34,6 +34,8 @@
extern "C" {
#endif
+#include <stdio.h>
+
#include "DNA_windowmanager_types.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index 12779a697b6..bab961bcbd2 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -91,6 +91,7 @@ void BKE_rigidbody_remove_constraint(struct Scene *scene, struct Object *ob);
void BKE_rigidbody_aftertrans_update(struct Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle);
void BKE_rigidbody_sync_transforms(struct RigidBodyWorld *rbw, struct Object *ob, float ctime);
void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw);
+void BKE_rigidbody_rebuild_world(struct Scene *scene, float ctime);
void BKE_rigidbody_do_simulation(struct Scene *scene, float ctime);
#endif /* __BKE_RIGIDBODY_H__ */
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index eef134a6872..c0ff634671d 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -36,6 +36,7 @@ struct Editing;
struct ImBuf;
struct Main;
struct Mask;
+struct MovieClip;
struct Scene;
struct Sequence;
struct SequenceModifierData;
@@ -322,6 +323,8 @@ void BKE_sequence_base_dupli_recursive(struct Scene *scene, struct Scene *scene_
int BKE_sequence_is_valid_check(struct Sequence *seq);
void BKE_sequencer_clear_scene_in_allseqs(struct Main *bmain, struct Scene *sce);
+void BKE_sequencer_clear_movieclip_in_clipboard(struct MovieClip *clip);
+void BKE_sequencer_clear_mask_in_clipboard(struct Mask *mask);
struct Sequence *BKE_sequence_get_by_name(struct ListBase *seqbase, const char *name, int recursive);
diff --git a/source/blender/blenkernel/depsgraph_private.h b/source/blender/blenkernel/depsgraph_private.h
index 12c111f5f16..ad5369c0820 100644
--- a/source/blender/blenkernel/depsgraph_private.h
+++ b/source/blender/blenkernel/depsgraph_private.h
@@ -34,9 +34,27 @@
#include "DNA_constraint_types.h"
#include "BKE_constraint.h"
+/* **** DAG relation types *** */
+
+/* scene link to object */
+#define DAG_RL_SCENE (1 << 0)
+/* object link to data */
+#define DAG_RL_DATA (1 << 1)
+
+/* object changes object (parent, track, constraints) */
+#define DAG_RL_OB_OB (1 << 2)
+/* object changes obdata (hooks, constraints) */
+#define DAG_RL_OB_DATA (1 << 3)
+/* data changes object (vertex parent) */
+#define DAG_RL_DATA_OB (1 << 4)
+/* data changes data (deformers) */
+#define DAG_RL_DATA_DATA (1 << 5)
+
+#define DAG_NO_RELATION (1 << 6)
+
+#define DAG_RL_ALL_BUT_DATA (DAG_RL_SCENE | DAG_RL_OB_OB | DAG_RL_OB_DATA | DAG_RL_DATA_OB | DAG_RL_DATA_DATA)
+#define DAG_RL_ALL (DAG_RL_ALL_BUT_DATA | DAG_RL_DATA)
-#define DEPSX 5.0f
-#define DEPSY 1.8f
#define DAGQUEUEALLOC 50
@@ -46,8 +64,6 @@ enum {
DAG_BLACK = 2
};
-
-
typedef struct DagAdjList {
struct DagNode *node;
short type;
@@ -108,11 +124,13 @@ void push_queue(DagNodeQueue *queue, DagNode *node);
void push_stack(DagNodeQueue *queue, DagNode *node);
DagNode *pop_queue(DagNodeQueue *queue);
DagNode *get_top_node_queue(DagNodeQueue *queue);
+int queue_count(DagNodeQueue *queue);
+void queue_delete(DagNodeQueue *queue);
// Dag management
-DagForest *getMainDag(void);
-void setMainDag(DagForest *dag);
DagForest *dag_init(void);
+DagForest *build_dag(struct Main *bmain, struct Scene *sce, short mask);
+void free_forest(struct DagForest *Dag);
DagNode *dag_find_node(DagForest *forest, void *fob);
DagNode *dag_add_node(DagForest *forest, void *fob);
DagNode *dag_get_node(DagForest *forest, void *fob);
@@ -126,6 +144,6 @@ DagNodeQueue *graph_dfs(void);
void set_node_xy(DagNode *node, float x, float y);
void graph_print_queue(DagNodeQueue *nqueue);
void graph_print_queue_dist(DagNodeQueue *nqueue);
-void graph_print_adj_list(void);
+void graph_print_adj_list(DagForest *dag);
#endif /* __DEPSGRAPH_PRIVATE_H__ */
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 6b3c95a5cd3..ffd86ea9ce0 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -491,7 +491,7 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob)
CustomData_copy(&dm->edgeData, &tmp.edata, CD_MASK_MESH, CD_DUPLICATE, totedge);
CustomData_copy(&dm->loopData, &tmp.ldata, CD_MASK_MESH, CD_DUPLICATE, totloop);
CustomData_copy(&dm->polyData, &tmp.pdata, CD_MASK_MESH, CD_DUPLICATE, totpoly);
- me->cd_flag = dm->cd_flag;
+ tmp.cd_flag = dm->cd_flag;
if (CustomData_has_layer(&dm->vertData, CD_SHAPEKEY)) {
KeyBlock *kb;
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 8c55ad02dc6..b919b9ffd8f 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -278,22 +278,11 @@ DagNode *pop_queue(DagNodeQueue *queue)
}
}
-void *pop_ob_queue(struct DagNodeQueue *queue)
-{
- return(pop_queue(queue)->ob);
-}
-
DagNode *get_top_node_queue(DagNodeQueue *queue)
{
return queue->first->node;
}
-int queue_count(struct DagNodeQueue *queue)
-{
- return queue->count;
-}
-
-
DagForest *dag_init(void)
{
DagForest *forest;
@@ -1190,539 +1179,6 @@ static void dag_check_cycle(DagForest *dag)
}
}
-/*
- * MainDAG is the DAG of all objects in current scene
- * used only for drawing there is one also in each scene
- */
-static DagForest *MainDag = NULL;
-
-DagForest *getMainDag(void)
-{
- return MainDag;
-}
-
-
-void setMainDag(DagForest *dag)
-{
- MainDag = dag;
-}
-
-
-/*
- * note for BFS/DFS
- * in theory we should sweep the whole array
- * but in our case the first node is the scene
- * and is linked to every other object
- *
- * for general case we will need to add outer loop
- */
-
-/*
- * ToDo : change pos kludge
- */
-
-/* adjust levels for drawing in oops space */
-void graph_bfs(void)
-{
- DagNode *node;
- DagNodeQueue *nqueue;
- int pos[50];
- int i;
- DagAdjList *itA;
- int minheight;
-
- /* fprintf(stderr, "starting BFS\n ------------\n"); */
- nqueue = queue_create(DAGQUEUEALLOC);
- for (i = 0; i < 50; i++)
- pos[i] = 0;
-
- /* Init
- * dagnode.first is always the root (scene)
- */
- node = MainDag->DagNode.first;
- while (node) {
- node->color = DAG_WHITE;
- node->BFS_dist = 9999;
- node->k = 0;
- node = node->next;
- }
-
- node = MainDag->DagNode.first;
- if (node->color == DAG_WHITE) {
- node->color = DAG_GRAY;
- node->BFS_dist = 1;
- push_queue(nqueue, node);
- while (nqueue->count) {
- node = pop_queue(nqueue);
-
- minheight = pos[node->BFS_dist];
- itA = node->child;
- while (itA != NULL) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->color = DAG_GRAY;
- itA->node->BFS_dist = node->BFS_dist + 1;
- itA->node->k = (float) minheight;
- push_queue(nqueue, itA->node);
- }
-
- else {
- fprintf(stderr, "bfs not dag tree edge color :%i\n", itA->node->color);
- }
-
-
- itA = itA->next;
- }
- if (pos[node->BFS_dist] > node->k) {
- pos[node->BFS_dist] += 1;
- node->k = (float) pos[node->BFS_dist];
- }
- else {
- pos[node->BFS_dist] = (int) node->k + 1;
- }
- set_node_xy(node, node->BFS_dist * DEPSX * 2, pos[node->BFS_dist] * DEPSY * 2);
- node->color = DAG_BLACK;
-
- // fprintf(stderr, "BFS node : %20s %i %5.0f %5.0f\n", ((ID *) node->ob)->name, node->BFS_dist, node->x, node->y);
- }
- }
- queue_delete(nqueue);
-}
-
-int pre_and_post_BFS(DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data)
-{
- DagNode *node;
-
- node = dag->DagNode.first;
- return pre_and_post_source_BFS(dag, mask, node, pre_func, post_func, data);
-}
-
-
-int pre_and_post_source_BFS(DagForest *dag, short mask, DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data)
-{
- DagNode *node;
- DagNodeQueue *nqueue;
- DagAdjList *itA;
- int retval = 0;
- /* fprintf(stderr, "starting BFS\n ------------\n"); */
-
- /* Init
- * dagnode.first is always the root (scene)
- */
- node = dag->DagNode.first;
- nqueue = queue_create(DAGQUEUEALLOC);
- while (node) {
- node->color = DAG_WHITE;
- node->BFS_dist = 9999;
- node = node->next;
- }
-
- node = source;
- if (node->color == DAG_WHITE) {
- node->color = DAG_GRAY;
- node->BFS_dist = 1;
- pre_func(node->ob, data);
-
- while (nqueue->count) {
- node = pop_queue(nqueue);
-
- itA = node->child;
- while (itA != NULL) {
- if ((itA->node->color == DAG_WHITE) && (itA->type & mask)) {
- itA->node->color = DAG_GRAY;
- itA->node->BFS_dist = node->BFS_dist + 1;
- push_queue(nqueue, itA->node);
- pre_func(node->ob, data);
- }
-
- else { /* back or cross edge */
- retval = 1;
- }
- itA = itA->next;
- }
- post_func(node->ob, data);
- node->color = DAG_BLACK;
-
- // fprintf(stderr, "BFS node : %20s %i %5.0f %5.0f\n", ((ID *) node->ob)->name, node->BFS_dist, node->x, node->y);
- }
- }
- queue_delete(nqueue);
- return retval;
-}
-
-/* non recursive version of DFS, return queue -- outer loop present to catch odd cases (first level cycles)*/
-DagNodeQueue *graph_dfs(void)
-{
- DagNode *node;
- DagNodeQueue *nqueue;
- DagNodeQueue *retqueue;
- int pos[50];
- int i;
- DagAdjList *itA;
- int time;
- int skip = 0;
- int minheight;
- int maxpos = 0;
- /* int is_cycle = 0; */ /* UNUSED */
- /*
- *fprintf(stderr, "starting DFS\n ------------\n");
- */
- nqueue = queue_create(DAGQUEUEALLOC);
- retqueue = queue_create(MainDag->numNodes);
- for (i = 0; i < 50; i++)
- pos[i] = 0;
-
- /* Init
- * dagnode.first is always the root (scene)
- */
- node = MainDag->DagNode.first;
- while (node) {
- node->color = DAG_WHITE;
- node->DFS_dist = 9999;
- node->DFS_dvtm = node->DFS_fntm = 9999;
- node->k = 0;
- node = node->next;
- }
-
- time = 1;
-
- node = MainDag->DagNode.first;
-
- do {
- if (node->color == DAG_WHITE) {
- node->color = DAG_GRAY;
- node->DFS_dist = 1;
- node->DFS_dvtm = time;
- time++;
- push_stack(nqueue, node);
-
- while (nqueue->count) {
- //graph_print_queue(nqueue);
-
- skip = 0;
- node = get_top_node_queue(nqueue);
-
- minheight = pos[node->DFS_dist];
-
- itA = node->child;
- while (itA != NULL) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->DFS_dvtm = time;
- itA->node->color = DAG_GRAY;
-
- time++;
- itA->node->DFS_dist = node->DFS_dist + 1;
- itA->node->k = (float) minheight;
- push_stack(nqueue, itA->node);
- skip = 1;
- break;
- }
- else {
- if (itA->node->color == DAG_GRAY) { /* back edge */
- fprintf(stderr, "dfs back edge :%15s %15s\n", ((ID *) node->ob)->name, ((ID *) itA->node->ob)->name);
- /* is_cycle = 1; */ /* UNUSED */
- }
- else if (itA->node->color == DAG_BLACK) {
- /* already processed node but we may want later to change distance either to shorter to longer.
- * DFS_dist is the first encounter
- */
-#if 0
- if (node->DFS_dist >= itA->node->DFS_dist)
- itA->node->DFS_dist = node->DFS_dist + 1;
-
- fprintf(stderr, "dfs forward or cross edge :%15s %i-%i %15s %i-%i\n",
- ((ID *) node->ob)->name,
- node->DFS_dvtm,
- node->DFS_fntm,
- ((ID *) itA->node->ob)->name,
- itA->node->DFS_dvtm,
- itA->node->DFS_fntm);
-#endif
- }
- else
- fprintf(stderr, "dfs unknown edge\n");
- }
- itA = itA->next;
- }
-
- if (!skip) {
- node = pop_queue(nqueue);
- node->color = DAG_BLACK;
-
- node->DFS_fntm = time;
- time++;
- if (node->DFS_dist > maxpos)
- maxpos = node->DFS_dist;
- if (pos[node->DFS_dist] > node->k) {
- pos[node->DFS_dist] += 1;
- node->k = (float) pos[node->DFS_dist];
- }
- else {
- pos[node->DFS_dist] = (int) node->k + 1;
- }
- set_node_xy(node, node->DFS_dist * DEPSX * 2, pos[node->DFS_dist] * DEPSY * 2);
-
- // fprintf(stderr, "DFS node : %20s %i %i %i %i\n", ((ID *) node->ob)->name, node->BFS_dist, node->DFS_dist, node->DFS_dvtm, node->DFS_fntm );
-
- push_stack(retqueue, node);
-
- }
- }
- }
- node = node->next;
- } while (node);
-// fprintf(stderr, "i size : %i\n", maxpos);
-
- queue_delete(nqueue);
- return(retqueue);
-}
-
-/* unused */
-int pre_and_post_DFS(DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data)
-{
- DagNode *node;
-
- node = dag->DagNode.first;
- return pre_and_post_source_DFS(dag, mask, node, pre_func, post_func, data);
-}
-
-int pre_and_post_source_DFS(DagForest *dag, short mask, DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data)
-{
- DagNode *node;
- DagNodeQueue *nqueue;
- DagAdjList *itA;
- int time;
- int skip = 0;
- int retval = 0;
- /*
- * fprintf(stderr, "starting DFS\n ------------\n");
- */
- nqueue = queue_create(DAGQUEUEALLOC);
-
- /* Init
- * dagnode.first is always the root (scene)
- */
- node = dag->DagNode.first;
- while (node) {
- node->color = DAG_WHITE;
- node->DFS_dist = 9999;
- node->DFS_dvtm = node->DFS_fntm = 9999;
- node->k = 0;
- node = node->next;
- }
-
- time = 1;
-
- node = source;
- do {
- if (node->color == DAG_WHITE) {
- node->color = DAG_GRAY;
- node->DFS_dist = 1;
- node->DFS_dvtm = time;
- time++;
- push_stack(nqueue, node);
- pre_func(node->ob, data);
-
- while (nqueue->count) {
- skip = 0;
- node = get_top_node_queue(nqueue);
-
- itA = node->child;
- while (itA != NULL) {
- if ((itA->node->color == DAG_WHITE) && (itA->type & mask) ) {
- itA->node->DFS_dvtm = time;
- itA->node->color = DAG_GRAY;
-
- time++;
- itA->node->DFS_dist = node->DFS_dist + 1;
- push_stack(nqueue, itA->node);
- pre_func(node->ob, data);
-
- skip = 1;
- break;
- }
- else {
- if (itA->node->color == DAG_GRAY) { // back edge
- retval = 1;
- }
-// else if (itA->node->color == DAG_BLACK) { // cross or forward
-//
-// }
- }
- itA = itA->next;
- }
-
- if (!skip) {
- node = pop_queue(nqueue);
- node->color = DAG_BLACK;
-
- node->DFS_fntm = time;
- time++;
- post_func(node->ob, data);
- }
- }
- }
- node = node->next;
- } while (node);
- queue_delete(nqueue);
- return(retval);
-}
-
-
-/* used to get the obs owning a datablock */
-DagNodeQueue *get_obparents(struct DagForest *dag, void *ob)
-{
- DagNode *node, *node1;
- DagNodeQueue *nqueue;
- DagAdjList *itA;
-
- node = dag_find_node(dag, ob);
- if (node == NULL) {
- return NULL;
- }
- else if (node->ancestor_count == 1) { /* simple case */
- nqueue = queue_create(1);
- push_queue(nqueue, node);
- }
- else { /* need to go over the whole dag for adj list */
- nqueue = queue_create(node->ancestor_count);
-
- node1 = dag->DagNode.first;
- do {
- if (node1->DFS_fntm > node->DFS_fntm) { /* a parent is finished after child. must check adj list */
- itA = node->child;
- while (itA != NULL) {
- if ((itA->node == node) && (itA->type == DAG_RL_DATA)) {
- push_queue(nqueue, node);
- }
- itA = itA->next;
- }
- }
- node1 = node1->next;
- } while (node1);
- }
- return nqueue;
-}
-
-DagNodeQueue *get_first_ancestors(struct DagForest *dag, void *ob)
-{
- DagNode *node, *node1;
- DagNodeQueue *nqueue;
- DagAdjList *itA;
-
- node = dag_find_node(dag, ob);
-
- /* need to go over the whole dag for adj list */
- nqueue = queue_create(node->ancestor_count);
-
- node1 = dag->DagNode.first;
- do {
- if (node1->DFS_fntm > node->DFS_fntm) {
- itA = node->child;
- while (itA != NULL) {
- if (itA->node == node) {
- push_queue(nqueue, node);
- }
- itA = itA->next;
- }
- }
- node1 = node1->next;
- } while (node1);
-
- return nqueue;
-}
-
-/* standard DFS list */
-DagNodeQueue *get_all_childs(struct DagForest *dag, void *ob)
-{
- DagNode *node;
- DagNodeQueue *nqueue;
- DagNodeQueue *retqueue;
- DagAdjList *itA;
- int time;
- int skip = 0;
-
- nqueue = queue_create(DAGQUEUEALLOC);
- retqueue = queue_create(dag->numNodes); /* was MainDag... why? (ton) */
-
- node = dag->DagNode.first;
- while (node) {
- node->color = DAG_WHITE;
- node = node->next;
- }
-
- time = 1;
-
- node = dag_find_node(dag, ob); /* could be done in loop above (ton) */
- if (node) { /* can be null for newly added objects */
-
- node->color = DAG_GRAY;
- time++;
- push_stack(nqueue, node);
-
- while (nqueue->count) {
-
- skip = 0;
- node = get_top_node_queue(nqueue);
-
- itA = node->child;
- while (itA != NULL) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->DFS_dvtm = time;
- itA->node->color = DAG_GRAY;
-
- time++;
- push_stack(nqueue, itA->node);
- skip = 1;
- break;
- }
- itA = itA->next;
- }
-
- if (!skip) {
- node = pop_queue(nqueue);
- node->color = DAG_BLACK;
-
- time++;
- push_stack(retqueue, node);
- }
- }
- }
- queue_delete(nqueue);
- return(retqueue);
-}
-
-/* unused */
-#if 0
-short are_obs_related(struct DagForest *dag, void *ob1, void *ob2)
-{
- DagNode *node;
- DagAdjList *itA;
-
- node = dag_find_node(dag, ob1);
-
- itA = node->child;
- while (itA != NULL) {
- if (itA->node->ob == ob2) {
- return itA->node->type;
- }
- itA = itA->next;
- }
- return DAG_NO_RELATION;
-}
-#endif
-
-int is_acyclic(DagForest *dag)
-{
- return dag->is_acyclic;
-}
-
-void set_node_xy(DagNode *node, float x, float y)
-{
- node->x = x;
- node->y = y;
-}
-
-
/* debug test functions */
void graph_print_queue(DagNodeQueue *nqueue)
@@ -1757,12 +1213,12 @@ void graph_print_queue_dist(DagNodeQueue *nqueue)
fprintf(stderr, "\n");
}
-void graph_print_adj_list(void)
+void graph_print_adj_list(DagForest *dag)
{
DagNode *node;
DagAdjList *itA;
- node = (getMainDag())->DagNode.first;
+ node = dag->DagNode.first;
while (node) {
fprintf(stderr, "node : %s col: %i", ((ID *) node->ob)->name, node->color);
itA = node->child;
@@ -1973,6 +1429,15 @@ void DAG_scene_relations_update(Main *bmain, Scene *sce)
dag_scene_build(bmain, sce);
}
+void DAG_scene_free(Scene *sce)
+{
+ if (sce->theDag) {
+ free_forest(sce->theDag);
+ MEM_freeN(sce->theDag);
+ sce->theDag = NULL;
+ }
+}
+
static void lib_id_recalc_tag(Main *bmain, ID *id)
{
id->flag |= LIB_ID_RECALC;
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 23f3a3ad3fd..bc396d218df 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -986,9 +986,9 @@ typedef struct DriverVarTypeInfo {
float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
/* allocation of target slots */
- int num_targets; /* number of target slots required */
+ int num_targets; /* number of target slots required */
const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */
- int target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */
+ short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */
} DriverVarTypeInfo;
/* Macro to begin definitions */
@@ -1014,7 +1014,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
ID *id;
- int index;
+ int index = -1;
float value = 0.0f;
/* sanity check */
@@ -1029,6 +1029,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
printf("Error: driver has an invalid target to use\n");
if (G.debug & G_DEBUG) printf("\tpath = %s\n", dtar->rna_path);
driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
return 0.0f;
}
@@ -1039,7 +1040,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
if (RNA_path_resolve_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
if (RNA_property_array_check(prop)) {
/* array */
- if (index < RNA_property_array_length(&ptr, prop)) {
+ if ((index >= 0) && (index < RNA_property_array_length(&ptr, prop))) {
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
value = (float)RNA_property_boolean_get_index(&ptr, prop, index);
@@ -1054,6 +1055,17 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
break;
}
}
+ else {
+ /* out of bounds */
+ if (G.debug & G_DEBUG) {
+ printf("Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)",
+ id->name, dtar->rna_path, index);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
}
else {
/* not an array */
@@ -1074,16 +1086,19 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
break;
}
}
-
}
else {
+ /* path couldn't be resolved */
if (G.debug & G_DEBUG)
printf("Driver Evaluation Error: cannot resolve target for %s -> %s\n", id->name, dtar->rna_path);
driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
return 0.0f;
}
+ /* if we're still here, we should be ok... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
return value;
}
@@ -1122,25 +1137,39 @@ static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
/* evaluate 'rotation difference' driver variable */
static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
{
+ DriverTarget *dtar1 = &dvar->targets[0];
+ DriverTarget *dtar2 = &dvar->targets[1];
bPoseChannel *pchan, *pchan2;
float q1[4], q2[4], quat[4], angle;
/* get pose channels, and check if we've got two */
- pchan = dtar_get_pchan_ptr(driver, &dvar->targets[0]);
- pchan2 = dtar_get_pchan_ptr(driver, &dvar->targets[1]);
+ pchan = dtar_get_pchan_ptr(driver, dtar1);
+ pchan2 = dtar_get_pchan_ptr(driver, dtar2);
if (ELEM(NULL, pchan, pchan2)) {
/* disable this driver, since it doesn't work correctly... */
driver->flag |= DRIVER_FLAG_INVALID;
/* check what the error was */
- if ((pchan == NULL) && (pchan2 == NULL))
+ if ((pchan == NULL) && (pchan2 == NULL)) {
printf("Driver Evaluation Error: Rotational difference failed - first 2 targets invalid\n");
- else if (pchan == NULL)
+
+ dtar1->flag |= DTAR_FLAG_INVALID;
+ dtar2->flag |= DTAR_FLAG_INVALID;
+ }
+ else if (pchan == NULL) {
printf("Driver Evaluation Error: Rotational difference failed - first target not valid PoseChannel\n");
- else if (pchan2 == NULL)
+
+ dtar1->flag |= DTAR_FLAG_INVALID;
+ dtar2->flag &= ~DTAR_FLAG_INVALID;
+ }
+ else if (pchan2 == NULL) {
printf("Driver Evaluation Error: Rotational difference failed - second target not valid PoseChannel\n");
+ dtar1->flag &= ~DTAR_FLAG_INVALID;
+ dtar2->flag |= DTAR_FLAG_INVALID;
+ }
+
/* stop here... */
return 0.0f;
}
@@ -1163,22 +1192,53 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
{
float loc1[3] = {0.0f, 0.0f, 0.0f};
float loc2[3] = {0.0f, 0.0f, 0.0f};
+ short valid_targets = 0;
- /* get two location values */
- /* NOTE: for now, these are all just worldspace */
+ /* Perform two passes
+ *
+ * FIRST PASS - to just check that everything works...
+ * NOTE: we use loops here to reduce code duplication, though in practice,
+ * there can only be 2 items or else we run into some problems later
+ */
DRIVER_TARGETS_USED_LOOPER(dvar)
{
- /* get pointer to loc values to store in */
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
- bPoseChannel *pchan;
- float tmp_loc[3];
/* check if this target has valid data */
if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
/* invalid target, so will not have enough targets */
driver->flag |= DRIVER_FLAG_INVALID;
- return 0.0f;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ }
+ else {
+ /* target seems to be OK now... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ valid_targets++;
}
+ }
+ DRIVER_TARGETS_LOOPER_END
+
+ /* make sure we have enough valid targets to use - all or nothing for now... */
+ if (valid_targets < dvar->num_targets) {
+ if (G.debug & G_DEBUG) {
+ printf("LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)\n",
+ valid_targets, dvar->targets[0].id, dvar->targets[1].id);
+ }
+ return 0.0f;
+ }
+
+
+ /* SECOND PASS: get two location values */
+ /* NOTE: for now, these are all just worldspace */
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ /* get pointer to loc values to store in */
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+ float tmp_loc[3];
+
+ /* after the checks above, the targets should be valid here... */
+ BLI_assert((ob != NULL) && (GS(ob->id.name) != ID_OB));
/* try to get posechannel */
pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
@@ -1264,8 +1324,13 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
/* invalid target, so will not have enough targets */
driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
return 0.0f;
}
+ else {
+ /* target should be valid now */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ }
/* try to get posechannel */
pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
@@ -1458,12 +1523,12 @@ void driver_change_variable_type(DriverVar *dvar, int type)
*/
DRIVER_TARGETS_USED_LOOPER(dvar)
{
- int flags = dvti->target_flags[tarIndex];
+ short flags = dvti->target_flags[tarIndex];
/* store the flags */
dtar->flag = flags;
- /* object ID types only, or idtype not yet initialized*/
+ /* object ID types only, or idtype not yet initialized */
if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0))
dtar->idtype = ID_OB;
}
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 960432d6b3d..87802ab8ee6 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -923,6 +923,8 @@ void BKE_mask_free(Main *bmain, Mask *mask)
SpaceLink *sl;
Scene *scene;
+ BKE_sequencer_clear_mask_in_clipboard(mask);
+
for (scr = bmain->screen.first; scr; scr = scr->id.next) {
for (area = scr->areabase.first; area; area = area->next) {
for (sl = area->spacedata.first; sl; sl = sl->next) {
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index c9c86e6739f..f6f60d03cf7 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -887,12 +887,11 @@ static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, MLoop *alll
int old, MEdge **alledge, int *_totedge)
{
MPoly *mpoly;
- MLoop *mloop;
MFace *mface;
MEdge *medge;
EdgeHash *hash = BLI_edgehash_new();
struct edgesort *edsort, *ed;
- int a, b, totedge = 0, final = 0;
+ int a, totedge = 0, final = 0;
/* we put all edges in array, sort them, and detect doubles that way */
@@ -973,13 +972,16 @@ static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, MLoop *alll
mpoly = allpoly;
for (a = 0; a < totpoly; a++, mpoly++) {
- mloop = allloop + mpoly->loopstart;
- for (b = 0; b < mpoly->totloop; b++) {
- int v1, v2;
-
- v1 = mloop[b].v;
- v2 = ME_POLY_LOOP_NEXT(mloop, mpoly, b)->v;
- mloop[b].e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(hash, v1, v2));
+ MLoop *ml, *ml_next;
+ int i = mpoly->totloop;
+
+ ml_next = allloop + mpoly->loopstart; /* first loop */
+ ml = &ml_next[i - 1]; /* last loop */
+
+ while (i-- != 0) {
+ ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(hash, ml->v, ml_next->v));
+ ml = ml_next;
+ ml_next++;
}
}
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 128b9ae242e..74d3645ea66 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -908,6 +908,12 @@ int BKE_mesh_validate_dm(DerivedMesh *dm)
TRUE, FALSE);
}
+/**
+ * Calculate edges from polygons
+ *
+ * \param mesh The mesh to add edges into
+ * \param update When true create new edges co-exist
+ */
void BKE_mesh_calc_edges(Mesh *mesh, int update)
{
CustomData edata;
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 2aeda614f07..b0566a6495f 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -424,7 +424,9 @@ ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, in
return tmp_md;
}
-/* NOTE: these aren't used anymore */
+/* NOTE: This is to support old files from before Blender supported modifiers,
+ * in some cases versioning code updates these so for new files this will
+ * return an empty list. */
ModifierData *modifiers_getVirtualModifierList(Object *ob)
{
/* Kinda hacky, but should be fine since we are never
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index eceac61ddb6..5519edca7ff 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -75,12 +75,17 @@
#include "BKE_node.h"
#include "BKE_image.h" /* openanim */
#include "BKE_tracking.h"
+#include "BKE_sequencer.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_moviecache.h"
+#ifdef WITH_OPENEXR
+#include "intern/openexr/openexr_multi.h"
+#endif
+
/*********************** movieclip buffer loaders *************************/
static int sequence_guess_offset(const char *full_name, int head_len, unsigned short numlen)
@@ -221,6 +226,15 @@ static ImBuf *movieclip_load_sequence_file(MovieClip *clip, MovieClipUser *user,
/* read ibuf */
ibuf = IMB_loadiffname(name, loadflag, colorspace);
+#ifdef WITH_OPENEXR
+ if (ibuf) {
+ if (ibuf->ftype == OPENEXR && ibuf->userdata) {
+ IMB_exr_close(ibuf->userdata);
+ ibuf->userdata = NULL;
+ }
+ }
+#endif
+
return ibuf;
}
@@ -1281,6 +1295,8 @@ void BKE_movieclip_build_proxy_frame(MovieClip *clip, int clip_flag, struct Movi
void BKE_movieclip_free(MovieClip *clip)
{
+ BKE_sequencer_clear_movieclip_in_clipboard(clip);
+
free_buffers(clip);
BKE_tracking_free(&clip->tracking);
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 86fe47268d6..3dbaab008f8 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -991,6 +991,12 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node)
if (treetype->free_node_cache)
treetype->free_node_cache(ntree, node);
+
+ /* texture node has bad habit of keeping exec data around */
+ if (ntree->type == NTREE_TEXTURE && ntree->execdata) {
+ ntreeTexEndExecTree(ntree->execdata, 1);
+ ntree->execdata = NULL;
+ }
}
/* since it is called while free database, node->id is undefined */
@@ -1040,6 +1046,7 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user)
break;
case NTREE_TEXTURE:
ntreeTexEndExecTree(ntree->execdata, 1);
+ ntree->execdata = NULL;
break;
}
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 483dd2570e2..477ae27394f 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -1057,10 +1057,10 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
node->prim_indices,
node->totprim);
break;
- case PBVH_BMESH:
+ case PBVH_BMESH:
node->draw_buffers =
- GPU_build_bmesh_buffers(bvh->flags &
- PBVH_DYNTOPO_SMOOTH_SHADING);
+ GPU_build_bmesh_buffers(bvh->flags &
+ PBVH_DYNTOPO_SMOOTH_SHADING);
break;
}
@@ -1089,12 +1089,12 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
node->face_vert_indices,
bvh->show_diffuse_color);
break;
- case PBVH_BMESH:
+ case PBVH_BMESH:
GPU_update_bmesh_buffers(node->draw_buffers,
- bvh->bm,
- node->bm_faces,
- node->bm_unique_verts,
- node->bm_other_verts);
+ bvh->bm,
+ node->bm_faces,
+ node->bm_unique_verts,
+ node->bm_other_verts);
break;
}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 666c85d2f6b..386a8b27870 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -412,7 +412,7 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
do {
v = l_iter->v;
if (pbvh_bmesh_node_vert_use_count(bvh, f_node, v) == 1) {
- if (BLI_ghash_lookup(f_node->bm_unique_verts, v)) {
+ if (BLI_ghash_haskey(f_node->bm_unique_verts, v)) {
/* Find a different node that uses 'v' */
PBVHNode *new_node;
@@ -805,7 +805,8 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e, BMVert *v1,
/* Ensure that v1 is in the new face's node */
if (!BLI_ghash_haskey(n->bm_unique_verts, v1) &&
- !BLI_ghash_haskey(n->bm_other_verts, v1)) {
+ !BLI_ghash_haskey(n->bm_other_verts, v1))
+ {
BLI_ghash_insert(n->bm_other_verts, v1, NULL);
}
}
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 27c5e03132e..c8947730ea8 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -3566,7 +3566,7 @@ void BKE_ptcache_update_info(PTCacheID *pid)
BLI_snprintf(cache->info, sizeof(cache->info), IFACE_("%s, cache is outdated!"), mem_info);
}
else if (cache->flag & PTCACHE_FRAMES_SKIPPED) {
- BLI_snprintf(cache->info, sizeof(cache->info), IFACE_("%s, not exact since frame %i."),
+ BLI_snprintf(cache->info, sizeof(cache->info), IFACE_("%s, not exact since frame %i"),
mem_info, cache->last_exact);
}
else {
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 4c6bae122cd..d144ac927a6 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -347,6 +347,7 @@ void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
float capsule_height;
float hull_margin = 0.0f;
bool can_embed = true;
+ bool has_volume;
/* sanity check */
if (rbo == NULL)
@@ -404,11 +405,13 @@ void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
case RB_SHAPE_CONVEXH:
/* try to emged collision margin */
- if (!(rbo->flag & RBO_FLAG_USE_MARGIN))
+ has_volume = (MIN3(size[0], size[1], size[2]) > 0.0f);
+
+ if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && has_volume)
hull_margin = 0.04f;
new_shape = rigidbody_get_shape_convexhull_from_mesh(ob, hull_margin, &can_embed);
if (!(rbo->flag & RBO_FLAG_USE_MARGIN))
- rbo->margin = (can_embed) ? 0.04f : 0.0f; /* RB_TODO ideally we shouldn't directly change the margin here */
+ rbo->margin = (can_embed && has_volume) ? 0.04f : 0.0f; /* RB_TODO ideally we shouldn't directly change the margin here */
break;
case RB_SHAPE_TRIMESH:
new_shape = rigidbody_get_shape_trimesh_from_mesh(ob);
@@ -1217,10 +1220,10 @@ void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
/* ------------------ */
-/* Run RigidBody simulation for the specified physics world */
-void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
+/* Rebuild rigid body world */
+/* NOTE: this needs to be called before frame update to work correctly */
+void BKE_rigidbody_rebuild_world(Scene *scene, float ctime)
{
- float timestep;
RigidBodyWorld *rbw = scene->rigidbody_world;
PointCache *cache;
PTCacheID pid;
@@ -1230,16 +1233,12 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL);
cache = rbw->pointcache;
- rbw->flag &= ~RBW_FLAG_FRAME_UPDATE;
-
/* flag cache as outdated if we don't have a world or number of objects in the simulation has changed */
if (rbw->physics_world == NULL || rbw->numbodies != BLI_countlist(&rbw->group->gobject)) {
cache->flag |= PTCACHE_OUTDATED;
}
- if (ctime <= startframe) {
- rbw->ltime = startframe;
- /* reset and rebuild simulation if necessary */
+ if (ctime <= startframe + 1 && rbw->ltime == startframe) {
if (cache->flag & PTCACHE_OUTDATED) {
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
rigidbody_update_simulation(scene, rbw, true);
@@ -1247,12 +1246,25 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
cache->last_exact = 0;
cache->flag &= ~PTCACHE_REDO_NEEDED;
}
- return;
}
- /* rebuild world if it's outdated on second frame */
- else if (ctime == startframe + 1 && rbw->ltime == startframe && cache->flag & PTCACHE_OUTDATED) {
- BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- rigidbody_update_simulation(scene, rbw, true);
+}
+
+/* Run RigidBody simulation for the specified physics world */
+void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
+{
+ float timestep;
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ PointCache *cache;
+ PTCacheID pid;
+ int startframe, endframe;
+
+ BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw);
+ BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL);
+ cache = rbw->pointcache;
+
+ if (ctime <= startframe) {
+ rbw->ltime = startframe;
+ return;
}
/* make sure we don't go out of cache frame range */
else if (ctime > endframe) {
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index e1e4563e89f..19eea279f79 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -306,6 +306,9 @@ void BKE_scene_free(Scene *sce)
{
Base *base;
+ /* check all sequences */
+ BKE_sequencer_clear_scene_in_allseqs(G.main, sce);
+
base = sce->base.first;
while (base) {
base->object->id.us--;
@@ -385,10 +388,7 @@ void BKE_scene_free(Scene *sce)
sce->toolsettings = NULL;
}
- if (sce->theDag) {
- free_forest(sce->theDag);
- MEM_freeN(sce->theDag);
- }
+ DAG_scene_free(sce);
if (sce->nodetree) {
ntreeFreeTree(sce->nodetree);
@@ -722,9 +722,6 @@ void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce)
if (sce1->set == sce)
sce1->set = NULL;
- /* check all sequences */
- BKE_sequencer_clear_scene_in_allseqs(bmain, sce);
-
/* check render layer nodes in other scenes */
clear_scene_in_nodes(bmain, sce);
@@ -1110,13 +1107,22 @@ static void scene_depsgraph_hack(Scene *scene, Scene *scene_parent)
}
-static void scene_flag_rbw_recursive(Scene *scene)
+static void scene_rebuild_rbw_recursive(Scene *scene, float ctime)
{
if (scene->set)
- scene_flag_rbw_recursive(scene->set);
+ scene_rebuild_rbw_recursive(scene->set, ctime);
if (BKE_scene_check_rigidbody_active(scene))
- scene->rigidbody_world->flag |= RBW_FLAG_FRAME_UPDATE;
+ BKE_rigidbody_rebuild_world(scene, ctime);
+}
+
+static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
+{
+ if (scene->set)
+ scene_do_rb_simulation_recursive(scene->set, ctime);
+
+ if (BKE_scene_check_rigidbody_active(scene))
+ BKE_rigidbody_do_simulation(scene, ctime);
}
static void scene_update_tagged_recursive(Main *bmain, Scene *scene, Scene *scene_parent)
@@ -1130,22 +1136,6 @@ static void scene_update_tagged_recursive(Main *bmain, Scene *scene, Scene *scen
if (scene->set)
scene_update_tagged_recursive(bmain, scene->set, scene_parent);
- /* run rigidbody sim
- * - calculate/read values from cache into RBO's, to get flushed
- * later when objects are evaluated (if they're tagged for eval)
- */
- // XXX: this position may still change, objects not being updated correctly before simulation is run
- // NOTE: current position is so that rigidbody sim affects other objects
- if (BKE_scene_check_rigidbody_active(scene) && scene->rigidbody_world->flag & RBW_FLAG_FRAME_UPDATE) {
- /* we use frame time of parent (this is "scene" itself for top-level of sets recursion),
- * as that is the active scene controlling all timing in file at the moment
- */
- float ctime = BKE_scene_frame_get(scene_parent);
-
- /* however, "scene" contains the rigidbody world needed for eval... */
- BKE_rigidbody_do_simulation(scene, ctime);
- }
-
/* scene objects */
for (base = scene->base.first; base; base = base->next) {
Object *ob = base->object;
@@ -1224,6 +1214,12 @@ void BKE_scene_update_for_newframe(Main *bmain, Scene *sce, unsigned int lay)
{
float ctime = BKE_scene_frame_get(sce);
Scene *sce_iter;
+
+ /* rebuild rigid body worlds before doing the actual frame update
+ * this needs to be done on start frame but animation playback usually starts one frame later
+ * we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive
+ */
+ scene_rebuild_rbw_recursive(sce, ctime);
/* keep this first */
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
@@ -1263,8 +1259,9 @@ void BKE_scene_update_for_newframe(Main *bmain, Scene *sce, unsigned int lay)
tag_main_idcode(bmain, ID_MA, FALSE);
tag_main_idcode(bmain, ID_LA, FALSE);
- /* flag rigid body worlds for update */
- scene_flag_rbw_recursive(sce);
+ /* run rigidbody sim */
+ /* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */
+ scene_do_rb_simulation_recursive(sce, ctime);
/* BKE_object_handle_update() on all objects, groups and sets */
scene_update_tagged_recursive(bmain, sce, sce);
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
index 9ea405ef636..a64a4895e9b 100644
--- a/source/blender/blenkernel/intern/seqmodifier.c
+++ b/source/blender/blenkernel/intern/seqmodifier.c
@@ -237,9 +237,9 @@ static void curves_apply_threaded(int width, int height, unsigned char *rect, fl
rgb_uchar_to_float(t, mask_rect + pixel_index);
- tempc[0] = pixel[0] * (1.0f - t[0]) + result[0] * t[0];
- tempc[1] = pixel[1] * (1.0f - t[1]) + result[1] * t[1];
- tempc[2] = pixel[2] * (1.0f - t[2]) + result[2] * t[2];
+ tempc[0] = tempc[0] * (1.0f - t[0]) + result[0] * t[0];
+ tempc[1] = tempc[1] * (1.0f - t[1]) + result[1] * t[1];
+ tempc[2] = tempc[2] * (1.0f - t[2]) + result[2] * t[2];
}
else {
tempc[0] = result[0];
@@ -438,7 +438,7 @@ static void brightcontrast_apply_threaded(int width, int height, unsigned char *
unsigned char *m = mask_rect + pixel_index;
float t = (float) m[c] / 255.0f;
- v = (float) pixel[c] * (1.0f - t) + v * t;
+ v = (float) pixel[c] / 255.0f * (1.0f - t) + v * t;
}
pixel[c] = FTOCHAR(v);
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 68618287546..613c02c173b 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -815,6 +815,33 @@ void BKE_sequencer_clear_scene_in_allseqs(Main *bmain, Scene *scene)
BKE_sequencer_base_recursive_apply(&scene_iter->ed->seqbase, clear_scene_in_allseqs_cb, scene);
}
}
+
+ /* also clear clipboard */
+ BKE_sequencer_base_recursive_apply(&seqbase_clipboard, clear_scene_in_allseqs_cb, scene);
+}
+
+static int clear_movieclip_in_clipboard_cb(Sequence *seq, void *arg_pt)
+{
+ if (seq->clip == (MovieClip *)arg_pt)
+ seq->clip = NULL;
+ return 1;
+}
+
+void BKE_sequencer_clear_movieclip_in_clipboard(MovieClip *clip)
+{
+ BKE_sequencer_base_recursive_apply(&seqbase_clipboard, clear_movieclip_in_clipboard_cb, clip);
+}
+
+static int clear_mask_in_clipboard_cb(Sequence *seq, void *arg_pt)
+{
+ if (seq->mask == (Mask *)arg_pt)
+ seq->mask = NULL;
+ return 1;
+}
+
+void BKE_sequencer_clear_mask_in_clipboard(Mask *mask)
+{
+ BKE_sequencer_base_recursive_apply(&seqbase_clipboard, clear_mask_in_clipboard_cb, mask);
}
typedef struct SeqUniqueInfo {
@@ -1544,8 +1571,11 @@ static void color_balance_byte_byte(StripColorBalance *cb_, unsigned char *rect,
for (c = 0; c < 3; c++) {
float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
- if (m)
- p[c] = p[c] * (1.0f - (float)m[c] / 255.0f) + t * m[c];
+ if (m) {
+ float m_normal = (float) m[c] / 255.0f;
+
+ p[c] = p[c] * (1.0f - m_normal) + t * m_normal;
+ }
else
p[c] = t;
}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 74c0a76f82d..184984352ba 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -2560,6 +2560,7 @@ int txt_replace_char(Text *text, unsigned int add)
memcpy(text->curl->line + text->curc, ch, add_size);
text->curc += add_size;
+ text->curl->len += add_size - del_size;
txt_pop_sel(text);
txt_make_dirty(text);
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 1a7458f531c..f63a1f2cec0 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -1429,6 +1429,27 @@ void BKE_tracking_camera_get_reconstructed_interpolate(MovieTracking *tracking,
/*********************** Distortion/Undistortion *************************/
+#ifdef WITH_LIBMV
+static void cameraIntrinscisOptionsFromTracking(libmv_cameraIntrinsicsOptions *camera_intrinsics_options,
+ MovieTracking *tracking, int calibration_width, int calibration_height)
+{
+ MovieTrackingCamera *camera = &tracking->camera;
+ float aspy = 1.0f / tracking->camera.pixel_aspect;
+
+ camera_intrinsics_options->focal_length = camera->focal;
+
+ camera_intrinsics_options->principal_point_x = camera->principal[0];
+ camera_intrinsics_options->principal_point_y = camera->principal[1] * aspy;
+
+ camera_intrinsics_options->k1 = camera->k1;
+ camera_intrinsics_options->k2 = camera->k2;
+ camera_intrinsics_options->k3 = camera->k3;
+
+ camera_intrinsics_options->image_width = calibration_width;
+ camera_intrinsics_options->image_height = (double) calibration_height * aspy;
+}
+#endif
+
MovieDistortion *BKE_tracking_distortion_new(void)
{
MovieDistortion *distortion;
@@ -1441,28 +1462,23 @@ MovieDistortion *BKE_tracking_distortion_new(void)
void BKE_tracking_distortion_update(MovieDistortion *distortion, MovieTracking *tracking,
int calibration_width, int calibration_height)
{
- MovieTrackingCamera *camera = &tracking->camera;
- float aspy = 1.0f / tracking->camera.pixel_aspect;
-
#ifdef WITH_LIBMV
+ libmv_cameraIntrinsicsOptions camera_intrinsics_options;
+
+ cameraIntrinscisOptionsFromTracking(&camera_intrinsics_options, tracking,
+ calibration_width, calibration_height);
+
if (!distortion->intrinsics) {
- distortion->intrinsics = libmv_CameraIntrinsicsNew(camera->focal,
- camera->principal[0], camera->principal[1] * aspy,
- camera->k1, camera->k2, camera->k3,
- calibration_width, calibration_height * aspy);
+ distortion->intrinsics = libmv_CameraIntrinsicsNew(&camera_intrinsics_options);
}
else {
- libmv_CameraIntrinsicsUpdate(distortion->intrinsics, camera->focal,
- camera->principal[0], camera->principal[1] * aspy,
- camera->k1, camera->k2, camera->k3,
- calibration_width, calibration_height * aspy);
+ libmv_CameraIntrinsicsUpdate(distortion->intrinsics, &camera_intrinsics_options);
}
#else
(void) distortion;
+ (void) tracking;
(void) calibration_width;
(void) calibration_height;
- (void) camera;
- (void) aspy;
#endif
}
@@ -1543,15 +1559,17 @@ void BKE_tracking_distort_v2(MovieTracking *tracking, const float co[2], float r
MovieTrackingCamera *camera = &tracking->camera;
#ifdef WITH_LIBMV
+ libmv_cameraIntrinsicsOptions camera_intrinsics_options;
double x, y;
float aspy = 1.0f / tracking->camera.pixel_aspect;
+ cameraIntrinscisOptionsFromTracking(&camera_intrinsics_options, tracking, 0, 0);
+
/* normalize coords */
x = (co[0] - camera->principal[0]) / camera->focal;
y = (co[1] - camera->principal[1] * aspy) / camera->focal;
- libmv_applyCameraIntrinsics(camera->focal, camera->principal[0], camera->principal[1] * aspy,
- camera->k1, camera->k2, camera->k3, x, y, &x, &y);
+ libmv_applyCameraIntrinsics(&camera_intrinsics_options, x, y, &x, &y);
/* result is in image coords already */
r_co[0] = x;
@@ -1568,11 +1586,13 @@ void BKE_tracking_undistort_v2(MovieTracking *tracking, const float co[2], float
MovieTrackingCamera *camera = &tracking->camera;
#ifdef WITH_LIBMV
+ libmv_cameraIntrinsicsOptions camera_intrinsics_options;
double x = co[0], y = co[1];
float aspy = 1.0f / tracking->camera.pixel_aspect;
- libmv_InvertIntrinsics(camera->focal, camera->principal[0], camera->principal[1] * aspy,
- camera->k1, camera->k2, camera->k3, x, y, &x, &y);
+ cameraIntrinscisOptionsFromTracking(&camera_intrinsics_options, tracking, 0, 0);
+
+ libmv_InvertIntrinsics(&camera_intrinsics_options, x, y, &x, &y);
r_co[0] = x * camera->focal + camera->principal[0];
r_co[1] = y * camera->focal + camera->principal[1] * aspy;
@@ -2642,6 +2662,8 @@ typedef struct MovieReconstructContext {
float principal_point[2];
float k1, k2, k3;
+ int width, height;
+
float reprojection_error;
TracksMap *tracks_map;
@@ -2702,11 +2724,13 @@ static void reconstruct_retrieve_libmv_intrinscis(MovieReconstructContext *conte
&k1, &k2, &k3, &width, &height);
tracking->camera.focal = focal_length;
- tracking->camera.principal[0] = principal_x;
+ tracking->camera.principal[0] = principal_x;
tracking->camera.principal[1] = principal_y / aspy;
+
tracking->camera.k1 = k1;
tracking->camera.k2 = k2;
+ tracking->camera.k3 = k3;
}
static int reconstruct_retrieve_libmv_tracks(MovieReconstructContext *context, MovieTracking *tracking)
@@ -2840,10 +2864,10 @@ static int reconstruct_refine_intrinsics_get_flags(MovieTracking *tracking, Movi
flags |= LIBMV_REFINE_PRINCIPAL_POINT;
if (refine & REFINE_RADIAL_DISTORTION_K1)
- flags |= REFINE_RADIAL_DISTORTION_K1;
+ flags |= LIBMV_REFINE_RADIAL_DISTORTION_K1;
if (refine & REFINE_RADIAL_DISTORTION_K2)
- flags |= REFINE_RADIAL_DISTORTION_K2;
+ flags |= LIBMV_REFINE_RADIAL_DISTORTION_K2;
return flags;
}
@@ -2914,6 +2938,9 @@ MovieReconstructContext *BKE_tracking_reconstruction_context_new(MovieTracking *
context->principal_point[0] = camera->principal[0];
context->principal_point[1] = camera->principal[1] * aspy;
+ context->width = width;
+ context->height = height;
+
context->k1 = camera->k1;
context->k2 = camera->k2;
context->k3 = camera->k3;
@@ -2996,6 +3023,34 @@ static void reconstruct_update_solve_cb(void *customdata, double progress, const
BLI_snprintf(progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message);
}
+
+static void camraIntrincicsOptionsFromContext(libmv_cameraIntrinsicsOptions *camera_intrinsics_options,
+ MovieReconstructContext *context)
+{
+ camera_intrinsics_options->focal_length = context->focal_length;
+
+ camera_intrinsics_options->principal_point_x = context->principal_point[0];
+ camera_intrinsics_options->principal_point_y = context->principal_point[1];
+
+ camera_intrinsics_options->k1 = context->k1;
+ camera_intrinsics_options->k2 = context->k2;
+ camera_intrinsics_options->k3 = context->k3;
+
+ camera_intrinsics_options->image_width = context->width;
+ camera_intrinsics_options->image_height = context->height;
+}
+
+static void reconstructionOptionsFromContext(libmv_reconstructionOptions *reconstruction_options,
+ MovieReconstructContext *context)
+{
+ reconstruction_options->keyframe1 = context->keyframe1;
+ reconstruction_options->keyframe2 = context->keyframe2;
+
+ reconstruction_options->refine_intrinsics = context->refine_flags;
+
+ reconstruction_options->success_threshold = context->success_threshold;
+ reconstruction_options->use_fallback_reconstruction = context->use_fallback_reconstruction;
+}
#endif
void BKE_tracking_reconstruction_solve(MovieReconstructContext *context, short *stop, short *do_update,
@@ -3006,32 +3061,28 @@ void BKE_tracking_reconstruction_solve(MovieReconstructContext *context, short *
ReconstructProgressData progressdata;
+ libmv_cameraIntrinsicsOptions camera_intrinsics_options;
+ libmv_reconstructionOptions reconstruction_options;
+
progressdata.stop = stop;
progressdata.do_update = do_update;
progressdata.progress = progress;
progressdata.stats_message = stats_message;
progressdata.message_size = message_size;
+ camraIntrincicsOptionsFromContext(&camera_intrinsics_options, context);
+ reconstructionOptionsFromContext(&reconstruction_options, context);
+
if (context->motion_flag & TRACKING_MOTION_MODAL) {
context->reconstruction = libmv_solveModal(context->tracks,
- context->focal_length,
- context->principal_point[0], context->principal_point[1],
- context->k1, context->k2, context->k3,
+ &camera_intrinsics_options,
+ &reconstruction_options,
reconstruct_update_solve_cb, &progressdata);
}
else {
- struct libmv_reconstructionOptions options;
-
- options.success_threshold = context->success_threshold;
- options.use_fallback_reconstruction = context->use_fallback_reconstruction;
-
context->reconstruction = libmv_solveReconstruction(context->tracks,
- context->keyframe1, context->keyframe2,
- context->refine_flags,
- context->focal_length,
- context->principal_point[0], context->principal_point[1],
- context->k1, context->k2, context->k3,
- &options,
+ &camera_intrinsics_options,
+ &reconstruction_options,
reconstruct_update_solve_cb, &progressdata);
}
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index c4e17b1ed48..13f47d94160 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -260,6 +260,11 @@ MINLINE void madd_sh_shfl(float r[9], const float sh[3], const float f);
/********************************* Form Factor *******************************/
+float form_factor_quad(const float p[3], const float n[3],
+ const float q0[3], const float q1[3], const float q2[3], const float q3[3]);
+int form_factor_visible_quad(const float p[3], const float n[3],
+ const float v0[3], const float v1[3], const float v2[3],
+ float q0[3], float q1[3], float q2[3], float q3[3]);
float form_factor_hemi_poly(float p[3], float n[3],
float v1[3], float v2[3], float v3[3], float v4[3]);
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index 95ad786c7c2..bbafd28ddbc 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -399,7 +399,8 @@ typedef bool _BLI_Bool;
# define BLI_assert(a) (void)0
#endif
-#if (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406)) /* gcc4.6+ only */
+/* C++ can't use _Static_assert, expects static_assert() but c++0x only */
+#if (!defined(__cplusplus)) && (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406)) /* gcc4.6+ only */
# define BLI_STATIC_ASSERT(a, msg) _Static_assert(a, msg);
#else
/* TODO msvc, clang */
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index baca7bb8f8a..8f7ecdcfde8 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -3171,9 +3171,9 @@ static void vec_add_dir(float r[3], const float v1[3], const float v2[3], const
r[2] = v1[2] + fac * (v2[2] - v1[2]);
}
-static int ff_visible_quad(const float p[3], const float n[3],
- const float v0[3], const float v1[3], const float v2[3],
- float q0[3], float q1[3], float q2[3], float q3[3])
+int form_factor_visible_quad(const float p[3], const float n[3],
+ const float v0[3], const float v1[3], const float v2[3],
+ float q0[3], float q1[3], float q2[3], float q3[3])
{
static const float epsilon = 1e-6f;
float c, sd[3];
@@ -3532,8 +3532,8 @@ static void ff_normalize(float n[3])
}
}
-static float ff_quad_form_factor(const float p[3], const float n[3],
- const float q0[3], const float q1[3], const float q2[3], const float q3[3])
+float form_factor_quad(const float p[3], const float n[3],
+ const float q0[3], const float q1[3], const float q2[3], const float q3[3])
{
float r0[3], r1[3], r2[3], r3[3], g0[3], g1[3], g2[3], g3[3];
float a1, a2, a3, a4, dot1, dot2, dot3, dot4, result;
@@ -3579,11 +3579,11 @@ float form_factor_hemi_poly(float p[3], float n[3], float v1[3], float v2[3], fl
* covered by a quad or triangle, cosine weighted */
float q0[3], q1[3], q2[3], q3[3], contrib = 0.0f;
- if (ff_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3))
- contrib += ff_quad_form_factor(p, n, q0, q1, q2, q3);
+ if (form_factor_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3))
+ contrib += form_factor_quad(p, n, q0, q1, q2, q3);
- if (v4 && ff_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3))
- contrib += ff_quad_form_factor(p, n, q0, q1, q2, q3);
+ if (v4 && form_factor_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3))
+ contrib += form_factor_quad(p, n, q0, q1, q2, q3);
return contrib;
}
diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c
index 686484ef1db..a74f82ae965 100644
--- a/source/blender/blenlib/intern/threads.c
+++ b/source/blender/blenlib/intern/threads.c
@@ -429,12 +429,16 @@ void BLI_spin_unlock(SpinLock *spin)
#endif
}
+#ifndef __APPLE__
void BLI_spin_end(SpinLock *spin)
{
-#ifndef __APPLE__
pthread_spin_destroy(spin);
-#endif
}
+#else
+void BLI_spin_end(SpinLock *UNUSED(spin))
+{
+}
+#endif
/* Read/Write Mutex Lock */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 44a73fa14a0..b804a751b18 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -7564,6 +7564,23 @@ static void do_version_node_fix_translate_wrapping(void *UNUSED(data), ID *UNUSE
}
}
+static void do_version_node_straight_image_alpha_workaround(void *data, ID *UNUSED(id), bNodeTree *ntree)
+{
+ FileData *fd = (FileData *) data;
+ bNode *node;
+
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_IMAGE) {
+ Image *image = blo_do_versions_newlibadr(fd, ntree->id.lib, node->id);
+
+ if (image) {
+ if ((image->flag & IMA_DO_PREMUL) == 0 && image->alpha_mode == IMA_ALPHA_STRAIGHT)
+ node->custom1 |= CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT;
+ }
+ }
+ }
+}
+
static void do_version_node_fix_internal_links_264(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
{
bNode *node;
@@ -7954,7 +7971,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
prop = BKE_bproperty_object_get(ob, "Text");
if (prop) {
BKE_reportf_wrap(fd->reports, RPT_WARNING,
- TIP_("Game property name conflict in object '%s':\ntext objects reserve the "
+ TIP_("Game property name conflict in object '%s': text objects reserve the "
"['Text'] game property to change their content through logic bricks"),
ob->id.name + 2);
}
@@ -8857,6 +8874,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
Scene *scene;
Image *image, *nimage;
Tex *tex, *otex;
+ bNodeTreeType *ntreetype;
+ bNodeTree *ntree;
for (scene = main->scene.first; scene; scene = scene->id.next) {
Sequence *seq;
@@ -8961,6 +8980,13 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
for (image = main->image.first; image; image = image->id.next)
image->flag &= ~IMA_DONE_TAG;
+
+ ntreetype = ntreeGetType(NTREE_COMPOSIT);
+ if (ntreetype && ntreetype->foreach_nodetree)
+ ntreetype->foreach_nodetree(main, fd, do_version_node_straight_image_alpha_workaround);
+
+ for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ do_version_node_straight_image_alpha_workaround(fd, NULL, ntree);
}
if (main->versionfile < 265 || (main->versionfile == 265 && main->subversionfile < 7)) {
@@ -10450,7 +10476,8 @@ static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, cons
}
else {
/* already linked */
- printf("append: already linked\n");
+ if (G.debug)
+ printf("append: already linked\n");
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
if (id->flag & LIB_INDIRECT) {
id->flag -= LIB_INDIRECT;
diff --git a/source/blender/bmesh/intern/bmesh_iterators_inline.h b/source/blender/bmesh/intern/bmesh_iterators_inline.h
index eef6544be89..faa109617d5 100644
--- a/source/blender/bmesh/intern/bmesh_iterators_inline.h
+++ b/source/blender/bmesh/intern/bmesh_iterators_inline.h
@@ -80,61 +80,61 @@ BLI_INLINE bool BM_iter_init(BMIter *iter, BMesh *bm, const char itype, void *da
BLI_assert(data != NULL);
iter->begin = bmiter__edge_of_vert_begin;
iter->step = bmiter__edge_of_vert_step;
- iter->vdata = data;
+ iter->vdata = (BMVert *)data;
break;
case BM_FACES_OF_VERT:
BLI_assert(data != NULL);
iter->begin = bmiter__face_of_vert_begin;
iter->step = bmiter__face_of_vert_step;
- iter->vdata = data;
+ iter->vdata = (BMVert *)data;
break;
case BM_LOOPS_OF_VERT:
BLI_assert(data != NULL);
iter->begin = bmiter__loop_of_vert_begin;
iter->step = bmiter__loop_of_vert_step;
- iter->vdata = data;
+ iter->vdata = (BMVert *)data;
break;
case BM_VERTS_OF_EDGE:
BLI_assert(data != NULL);
iter->begin = bmiter__vert_of_edge_begin;
iter->step = bmiter__vert_of_edge_step;
- iter->edata = data;
+ iter->edata = (BMEdge *)data;
break;
case BM_FACES_OF_EDGE:
BLI_assert(data != NULL);
iter->begin = bmiter__face_of_edge_begin;
iter->step = bmiter__face_of_edge_step;
- iter->edata = data;
+ iter->edata = (BMEdge *)data;
break;
case BM_VERTS_OF_FACE:
BLI_assert(data != NULL);
iter->begin = bmiter__vert_of_face_begin;
iter->step = bmiter__vert_of_face_step;
- iter->pdata = data;
+ iter->pdata = (BMFace *)data;
break;
case BM_EDGES_OF_FACE:
BLI_assert(data != NULL);
iter->begin = bmiter__edge_of_face_begin;
iter->step = bmiter__edge_of_face_step;
- iter->pdata = data;
+ iter->pdata = (BMFace *)data;
break;
case BM_LOOPS_OF_FACE:
BLI_assert(data != NULL);
iter->begin = bmiter__loop_of_face_begin;
iter->step = bmiter__loop_of_face_step;
- iter->pdata = data;
+ iter->pdata = (BMFace *)data;
break;
case BM_LOOPS_OF_LOOP:
BLI_assert(data != NULL);
iter->begin = bmiter__loops_of_loop_begin;
iter->step = bmiter__loops_of_loop_step;
- iter->ldata = data;
+ iter->ldata = (BMLoop *)data;
break;
case BM_LOOPS_OF_EDGE:
BLI_assert(data != NULL);
iter->begin = bmiter__loops_of_edge_begin;
iter->step = bmiter__loops_of_edge_step;
- iter->edata = data;
+ iter->edata = (BMEdge *)data;
break;
default:
/* should never happen */
diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c
index 5d8689b9da6..5e2404c9919 100644
--- a/source/blender/bmesh/operators/bmo_hull.c
+++ b/source/blender/bmesh/operators/bmo_hull.c
@@ -154,8 +154,9 @@ static void hull_output_triangles(BMesh *bm, GHash *hull_triangles)
const int next = (i == 2 ? 0 : i + 1);
BMEdge *e = BM_edge_exists(t->v[i], t->v[next]);
if (e &&
- BMO_elem_flag_test(bm, e, HULL_FLAG_INPUT) &&
- !BMO_elem_flag_test(bm, e, HULL_FLAG_HOLE)) {
+ BMO_elem_flag_test(bm, e, HULL_FLAG_INPUT) &&
+ !BMO_elem_flag_test(bm, e, HULL_FLAG_HOLE))
+ {
BMO_elem_flag_enable(bm, e, HULL_FLAG_OUTPUT_GEOM);
}
}
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index c270a1e6b20..221a5008f10 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -49,8 +49,8 @@ static const char *bc_get_joint_name(T *node)
return id.size() ? id.c_str() : node->getOriginalId().c_str();
}
-ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, AnimationImporterBase *anim, Scene *sce) :
- TransformReader(conv), scene(sce), empty(NULL), mesh_importer(mesh), anim_importer(anim) {
+ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce) :
+ TransformReader(conv), scene(sce), empty(NULL), mesh_importer(mesh) {
}
ArmatureImporter::~ArmatureImporter()
diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h
index b07edfbf34d..2a8f1a65e21 100644
--- a/source/blender/collada/ArmatureImporter.h
+++ b/source/blender/collada/ArmatureImporter.h
@@ -96,7 +96,6 @@ private:
std::map<COLLADAFW::UniqueId, Object*> unskinned_armature_map;
MeshImporterBase *mesh_importer;
- AnimationImporterBase *anim_importer;
// This is used to store data passed in write_controller_data.
// Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members
@@ -138,7 +137,7 @@ private:
TagsMap uid_tags_map;
public:
- ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, AnimationImporterBase *anim, Scene *sce);
+ ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce);
~ArmatureImporter();
void add_joint(COLLADAFW::Node *node, bool root, Object *parent, Scene *sce);
diff --git a/source/blender/collada/CMakeLists.txt b/source/blender/collada/CMakeLists.txt
index 326ca2b9937..8747d2995f2 100644
--- a/source/blender/collada/CMakeLists.txt
+++ b/source/blender/collada/CMakeLists.txt
@@ -38,7 +38,7 @@ set(INC
../../../intern/guardedalloc
../ikplugin
../../../intern/iksolver/extern
-
+ ../bmesh
)
set(INC_SYS
diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp
index 41693d4d680..6b367b9cea9 100644
--- a/source/blender/collada/ControllerExporter.cpp
+++ b/source/blender/collada/ControllerExporter.cpp
@@ -201,13 +201,12 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
bool use_instantiation = this->export_settings->use_object_instantiation;
Mesh *me;
- if (this->export_settings->apply_modifiers)
- me = bc_to_mesh_apply_modifiers(scene, ob, this->export_settings->export_mesh_type);
- else
- me = (Mesh *)ob->data;
+ me = bc_get_mesh_copy(scene,
+ ob,
+ this->export_settings->export_mesh_type,
+ this->export_settings->apply_modifiers,
+ this->export_settings->triangulate);
- BKE_mesh_tessface_ensure(me);
-
if (!me->dvert) return;
std::string controller_name = id_name(ob_arm);
@@ -239,6 +238,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
joint_index_by_def_index.push_back(-1);
}
+ int oob_counter = 0;
for (i = 0; i < me->totvert; i++) {
MDeformVert *vert = &me->dvert[i];
std::map<int, float> jw;
@@ -248,11 +248,18 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
for (j = 0; j < vert->totweight; j++) {
int idx = vert->dw[j].def_nr;
- if (idx >= 0) {
- int joint_index = joint_index_by_def_index[idx];
- if (joint_index != -1 && vert->dw[j].weight > 0.0f) {
- jw[joint_index] += vert->dw[j].weight;
- sumw += vert->dw[j].weight;
+ if (idx >= joint_index_by_def_index.size()) {
+ // XXX: Maybe better find out where and
+ // why the Out Of Bound indexes get created ?
+ oob_counter += 1;
+ }
+ else {
+ if (idx >= 0) {
+ int joint_index = joint_index_by_def_index[idx];
+ if (joint_index != -1 && vert->dw[j].weight > 0.0f) {
+ jw[joint_index] += vert->dw[j].weight;
+ sumw += vert->dw[j].weight;
+ }
}
}
}
@@ -274,16 +281,18 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
#endif
}
}
+
+ if (oob_counter > 0) {
+ fprintf(stderr, "Ignored %d Vertex weigths which use index to non existing VGroup %ld.\n", oob_counter, joint_index_by_def_index.size());
+ }
}
std::string weights_source_id = add_weights_source(me, controller_id, weights);
add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id);
add_vertex_weights_element(weights_source_id, joints_source_id, vcounts, joints);
- if (this->export_settings->apply_modifiers)
- {
- BKE_libblock_free_us(&(G.main->mesh), me);
- }
+ BKE_libblock_free_us(&(G.main->mesh), me);
+
closeSkin();
closeController();
}
@@ -293,13 +302,11 @@ void ControllerExporter::export_morph_controller(Object *ob, Key *key)
bool use_instantiation = this->export_settings->use_object_instantiation;
Mesh *me;
- if (this->export_settings->apply_modifiers) {
- me = bc_to_mesh_apply_modifiers(scene, ob, this->export_settings->export_mesh_type);
- }
- else {
- me = (Mesh *)ob->data;
- }
- BKE_mesh_tessface_ensure(me);
+ me = bc_get_mesh_copy(scene,
+ ob,
+ this->export_settings->export_mesh_type,
+ this->export_settings->apply_modifiers,
+ this->export_settings->triangulate);
std::string controller_name = id_name(ob) + "-morph";
std::string controller_id = get_controller_id(key, ob);
@@ -320,10 +327,8 @@ void ControllerExporter::export_morph_controller(Object *ob, Key *key)
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, morph_weights_id)));
targets.add();
- if (this->export_settings->apply_modifiers)
- {
- BKE_libblock_free_us(&(G.main->mesh), me);
- }
+ BKE_libblock_free_us(&(G.main->mesh), me);
+
//support for animations
//can also try the base element and param alternative
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 2b906fa9ac2..49db6f033d9 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -104,7 +104,7 @@ DocumentImporter::DocumentImporter(bContext *C, const ImportSettings *import_set
import_settings(import_settings),
mImportStage(General),
mContext(C),
- armature_importer(&unit_converter, &mesh_importer, &anim_importer, CTX_data_scene(C)),
+ armature_importer(&unit_converter, &mesh_importer, CTX_data_scene(C)),
mesh_importer(&unit_converter, &armature_importer, CTX_data_scene(C)),
anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C))
{
@@ -157,7 +157,8 @@ bool DocumentImporter::import()
delete ehandler;
- mesh_importer.bmeshConversion();
+ //XXX No longer needed (geometries are now created as bmesh)
+ //mesh_importer.bmeshConversion();
return true;
}
diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h
index cf45b9b8391..ec71fb2747c 100644
--- a/source/blender/collada/ExportSettings.h
+++ b/source/blender/collada/ExportSettings.h
@@ -45,6 +45,7 @@ public:
bool include_material_textures;
bool use_texture_copies;
+ bool triangulate;
bool use_object_instantiation;
bool sort_by_name;
bool second_life;
diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp
index 4a6c5b43ce2..751628acf53 100644
--- a/source/blender/collada/GeometryExporter.cpp
+++ b/source/blender/collada/GeometryExporter.cpp
@@ -57,7 +57,6 @@ GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSett
{
}
-
void GeometryExporter::exportGeom(Scene *sce)
{
openLibrary();
@@ -77,18 +76,16 @@ void GeometryExporter::operator()(Object *ob)
#endif
bool use_instantiation = this->export_settings->use_object_instantiation;
- Mesh *me;
- if (this->export_settings->apply_modifiers) {
- me = bc_to_mesh_apply_modifiers(mScene, ob, this->export_settings->export_mesh_type);
- }
- else {
- me = (Mesh *)ob->data;
- }
- BKE_mesh_tessface_ensure(me);
+ bool triangulate = this->export_settings->triangulate;
+ Mesh *me = bc_get_mesh_copy( mScene,
+ ob,
+ this->export_settings->export_mesh_type,
+ this->export_settings->apply_modifiers,
+ this->export_settings->triangulate);
std::string geom_id = get_geometry_id(ob, use_instantiation);
std::vector<Normal> nor;
- std::vector<Face> norind;
+ std::vector<BCPolygonNormalsIndices> norind;
// Skip if linked geometry was already exported from another reference
if (use_instantiation &&
@@ -117,12 +114,13 @@ void GeometryExporter::operator()(Object *ob)
bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
// writes <source> for uv coords if mesh has uv coords
- if (has_uvs)
+ if (has_uvs) {
createTexcoordsSource(geom_id, me);
+ }
- if (has_color)
+ if (has_color) {
createVertexColorSource(geom_id, me);
-
+ }
// <vertices>
COLLADASW::Vertices verts(mSW);
@@ -132,7 +130,7 @@ void GeometryExporter::operator()(Object *ob)
input_list.push_back(input);
verts.add();
- createLooseEdgeList(ob, me, geom_id, norind);
+ createLooseEdgeList(ob, me, geom_id);
// Only create Polylists if number of faces > 0
if (me->totface > 0) {
@@ -155,10 +153,6 @@ void GeometryExporter::operator()(Object *ob)
closeGeometry();
- if (this->export_settings->apply_modifiers) {
- BKE_libblock_free_us(&(G.main->mesh), me);
- }
-
if (this->export_settings->include_shapekeys) {
Key * key = BKE_key_from_object(ob);
if (key) {
@@ -171,16 +165,16 @@ void GeometryExporter::operator()(Object *ob)
}
}
}
-#if 0
- dm->release(dm);
-#endif
+
+ BKE_libblock_free_us(&(G.main->mesh), me);
+
}
void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
{
std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
std::vector<Normal> nor;
- std::vector<Face> norind;
+ std::vector<BCPolygonNormalsIndices> norind;
if (exportedGeometry.find(geom_id) != exportedGeometry.end())
{
@@ -207,11 +201,13 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
// writes <source> for uv coords if mesh has uv coords
- if (has_uvs)
+ if (has_uvs) {
createTexcoordsSource(geom_id, me);
+ }
- if (has_color)
+ if (has_color) {
createVertexColorSource(geom_id, me);
+ }
// <vertices>
@@ -245,8 +241,7 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
void GeometryExporter::createLooseEdgeList(Object *ob,
Mesh *me,
- std::string& geom_id,
- std::vector<Face>& norind)
+ std::string& geom_id)
{
MEdge *medges = me->medge;
@@ -302,10 +297,12 @@ void GeometryExporter::createPolylist(short material_index,
Object *ob,
Mesh *me,
std::string& geom_id,
- std::vector<Face>& norind)
+ std::vector<BCPolygonNormalsIndices>& norind)
{
- MFace *mfaces = me->mface;
- int totfaces = me->totface;
+
+ MPoly *mpolys = me->mpoly;
+ MLoop *mloops = me->mloop;
+ int totpolys = me->totpoly;
// <vcount>
int i;
@@ -313,17 +310,12 @@ void GeometryExporter::createPolylist(short material_index,
std::vector<unsigned long> vcount_list;
// count faces with this material
- for (i = 0; i < totfaces; i++) {
- MFace *f = &mfaces[i];
+ for (i = 0; i < totpolys; i++) {
+ MPoly *p = &mpolys[i];
- if (f->mat_nr == material_index) {
+ if (p->mat_nr == material_index) {
faces_in_polylist++;
- if (f->v4 == 0) {
- vcount_list.push_back(3);
- }
- else {
- vcount_list.push_back(4);
- }
+ vcount_list.push_back(p->totloop);
}
}
@@ -385,21 +377,21 @@ void GeometryExporter::createPolylist(short material_index,
// performs the actual writing
polylist.prepareToAppendValues();
-
-
// <p>
int texindex = 0;
- for (i = 0; i < totfaces; i++) {
- MFace *f = &mfaces[i];
-
- if (f->mat_nr == material_index) {
-
- unsigned int *v = &f->v1;
- unsigned int *n = &norind[i].v1;
- for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
- polylist.appendValues(v[j]);
- polylist.appendValues(n[j]);
-
+ unsigned int vi = 0;
+ unsigned int ni = 0;
+ for (i = 0; i < totpolys; i++) {
+ MPoly *p = &mpolys[i];
+ int loop_count = p->totloop;
+
+ if (p->mat_nr == material_index) {
+ MLoop *l = &mloops[p->loopstart];
+ BCPolygonNormalsIndices normal_indices = norind[i];
+
+ for (int j = 0; j < loop_count; j++) {
+ polylist.appendValues(l[j].v);
+ polylist.appendValues(normal_indices[j]);
if (has_uvs)
polylist.appendValues(texindex + j);
@@ -408,14 +400,13 @@ void GeometryExporter::createPolylist(short material_index,
}
}
- texindex += 3;
- if (f->v4 != 0)
- texindex++;
+ texindex += loop_count;
}
polylist.finish();
}
+
// creates <source> for positions
void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
{
@@ -485,6 +476,7 @@ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
source.finish();
}
+
std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int layer_index)
{
char suffix[20];
@@ -495,38 +487,21 @@ std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int lay
//creates <source> for texcoords
void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
{
-#if 0
- int totfaces = dm->getNumTessFaces(dm);
- MFace *mfaces = dm->getTessFaceArray(dm);
-#endif
- int totfaces = me->totface;
- MFace *mfaces = me->mface;
- int totuv = 0;
- int i;
+ int totpoly = me->totpoly;
+ int totuv = me->totloop;
+ MPoly *mpolys = me->mpoly;
- // count totuv
- for (i = 0; i < totfaces; i++) {
- MFace *f = &mfaces[i];
- if (f->v4 == 0) {
- totuv += 3;
- }
- else {
- totuv += 4;
- }
- }
-
- int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
// write <source> for each layer
// each <source> will get id like meshName + "map-channel-1"
int map_index = 0;
- int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE)-1;
+ int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
for (int a = 0; a < num_layers; a++) {
if (!this->export_settings->active_uv_only || a == active_uv_index) {
- MTFace *tface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a);
- // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, a);
+ MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a);
COLLADASW::FloatSourceF source(mSW);
std::string layer_id = makeTexcoordSourceId(geom_id, map_index++);
@@ -541,12 +516,12 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
source.prepareToAppendValues();
- for (i = 0; i < totfaces; i++) {
- MFace *f = &mfaces[i];
-
- for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
- source.appendValues(tface[i].uv[j][0],
- tface[i].uv[j][1]);
+ for (int index = 0; index < totpoly; index++) {
+ MPoly *mpoly = mpolys+index;
+ MLoopUV *mloop = mloops+mpoly->loopstart;
+ for (int j = 0; j < mpoly->totloop; j++) {
+ source.appendValues(mloop[j].uv[0],
+ mloop[j].uv[1]);
}
}
@@ -586,53 +561,55 @@ void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::v
source.finish();
}
-void GeometryExporter::create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me)
+void GeometryExporter::create_normals(std::vector<Normal> &normals, std::vector<BCPolygonNormalsIndices> &polygons_normals, Mesh *me)
{
- int i, j, v;
MVert *vert = me->mvert;
- std::map<unsigned int, unsigned int> nshar;
-
- for (i = 0; i < me->totface; i++) {
- MFace *fa = &me->mface[i];
- Face f;
- unsigned int *nn = &f.v1;
- unsigned int *vv = &fa->v1;
-
- memset(&f, 0, sizeof(f));
- v = fa->v4 == 0 ? 3 : 4;
-
- if (!(fa->flag & ME_SMOOTH)) {
- Normal n;
- if (v == 4)
- normal_quad_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co, vert[fa->v4].co);
- else
- normal_tri_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co);
- nor.push_back(n);
+ std::map<unsigned int, unsigned int> shared_normal_indices;
+
+ for (int poly_index = 0; poly_index < me->totpoly; poly_index++) {
+ MPoly *mpoly = &me->mpoly[poly_index];
+ MLoop *mloops = me->mloop;
+
+ unsigned int last_normal_index = -1;
+ if (!(mpoly->flag & ME_SMOOTH)) {
+ // For flat faces calculate use face normal as vertex normal:
+
+ float vector[3];
+ BKE_mesh_calc_poly_normal(mpoly, mloops, vert, vector);
+
+ Normal n = { vector[0], vector[1], vector[2] };
+ normals.push_back(n);
+ last_normal_index++;
}
- for (j = 0; j < v; j++) {
- if (fa->flag & ME_SMOOTH) {
- if (nshar.find(*vv) != nshar.end())
- *nn = nshar[*vv];
+
+ MLoop *mloop = mloops + mpoly->loopstart;
+ BCPolygonNormalsIndices poly_indices;
+ for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) {
+ unsigned int vertex_index = mloop[loop_index].v;
+ if (mpoly->flag & ME_SMOOTH) {
+ if (shared_normal_indices.find(vertex_index) != shared_normal_indices.end())
+ poly_indices.add_index (shared_normal_indices[vertex_index]);
else {
- Normal n = {
- (float)vert[*vv].no[0] / 32767.0f,
- (float)vert[*vv].no[1] / 32767.0f,
- (float)vert[*vv].no[2] / 32767.0f
- };
- nor.push_back(n);
- *nn = (unsigned int)nor.size() - 1;
- nshar[*vv] = *nn;
+
+ float vector[3];
+ normal_short_to_float_v3(vector, vert[vertex_index].no);
+ normalize_v3(vector);
+
+ Normal n = { vector[0], vector[1], vector[2] };
+ normals.push_back(n);
+ last_normal_index++;
+
+ poly_indices.add_index(last_normal_index);
+ shared_normal_indices[vertex_index] = last_normal_index;
}
- vv++;
}
else {
- *nn = (unsigned int)nor.size() - 1;
+ poly_indices.add_index(last_normal_index);
}
- nn++;
}
- ind.push_back(f);
+ polygons_normals.push_back(poly_indices);
}
}
@@ -655,19 +632,4 @@ COLLADASW::URI GeometryExporter::makeUrl(std::string id)
return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
}
-#if 0
-int GeometryExporter::getTriCount(MFace *faces, int totface)
-{
- int i;
- int tris = 0;
- for (i = 0; i < totface; i++) {
- // if quad
- if (faces[i].v4 != 0)
- tris += 2;
- else
- tris++;
- }
- return tris;
-}
-#endif
diff --git a/source/blender/collada/GeometryExporter.h b/source/blender/collada/GeometryExporter.h
index 7cbbf0da8fa..4b1427c11ca 100644
--- a/source/blender/collada/GeometryExporter.h
+++ b/source/blender/collada/GeometryExporter.h
@@ -42,6 +42,7 @@
#include "DNA_key_types.h"
#include "ExportSettings.h"
+#include "collada_utils.h"
#include "BKE_key.h"
@@ -71,8 +72,7 @@ public:
void createLooseEdgeList(Object *ob,
Mesh *me,
- std::string& geom_id,
- std::vector<Face>& norind);
+ std::string& geom_id);
// powerful because it handles both cases when there is material and when there's not
void createPolylist(short material_index,
@@ -81,7 +81,7 @@ public:
Object *ob,
Mesh *me,
std::string& geom_id,
- std::vector<Face>& norind);
+ std::vector<BCPolygonNormalsIndices>& norind);
// creates <source> for positions
void createVertsSource(std::string geom_id, Mesh *me);
@@ -92,11 +92,12 @@ public:
//creates <source> for texcoords
void createTexcoordsSource(std::string geom_id, Mesh *me);
+ void createTesselatedTexcoordsSource(std::string geom_id, Mesh *me);
//creates <source> for normals
void createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor);
- void create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me);
+ void create_normals(std::vector<Normal> &nor, std::vector<BCPolygonNormalsIndices> &ind, Mesh *me);
std::string getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix = "");
@@ -106,7 +107,6 @@ public:
void export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb);
- /* int getTriCount(MFace *faces, int totface);*/
private:
std::set<std::string> exportedGeometry;
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 26915f37002..69944563b6a 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -173,83 +173,30 @@ void UVDataWrapper::getUV(int uv_index, float *uv)
}
}
-void MeshImporter::set_face_indices(MFace *mface, unsigned int *indices, bool quad)
-{
- mface->v1 = indices[0];
- mface->v2 = indices[1];
- mface->v3 = indices[2];
- if (quad) mface->v4 = indices[3];
- else mface->v4 = 0;
-#ifdef COLLADA_DEBUG
- // fprintf(stderr, "%u, %u, %u\n", indices[0], indices[1], indices[2]);
-#endif
-}
-
-// not used anymore, test_index_face from blenkernel is better
-#if 0
-// change face indices order so that v4 is not 0
-void MeshImporter::rotate_face_indices(MFace *mface)
-{
- mface->v4 = mface->v1;
- mface->v1 = mface->v2;
- mface->v2 = mface->v3;
- mface->v3 = 0;
+MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce) : unitconverter(unitconv), scene(sce), armature_importer(arm) {
}
-#endif
-void MeshImporter::set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
- COLLADAFW::IndexList& index_list, unsigned int *tris_indices)
+void MeshImporter::set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count)
{
- // per face vertex indices, this means for quad we have 4 indices, not 8
- COLLADAFW::UIntValuesArray& indices = index_list.getIndices();
+ mpoly->loopstart = loop_index;
+ mpoly->totloop = loop_count;
- uvs.getUV(indices[tris_indices[0]], mtface->uv[0]);
- uvs.getUV(indices[tris_indices[1]], mtface->uv[1]);
- uvs.getUV(indices[tris_indices[2]], mtface->uv[2]);
+ for (int index=0; index < loop_count; index++) {
+ mloop->v = indices[index];
+ mloop++;
+ }
}
-void MeshImporter::set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
- COLLADAFW::IndexList& index_list, int index, bool quad)
+void MeshImporter::set_face_uv(MLoopUV *mloopuv, UVDataWrapper &uvs,
+ int start_index, COLLADAFW::IndexList& index_list, int count)
{
// per face vertex indices, this means for quad we have 4 indices, not 8
COLLADAFW::UIntValuesArray& indices = index_list.getIndices();
- uvs.getUV(indices[index + 0], mtface->uv[0]);
- uvs.getUV(indices[index + 1], mtface->uv[1]);
- uvs.getUV(indices[index + 2], mtface->uv[2]);
-
- if (quad) uvs.getUV(indices[index + 3], mtface->uv[3]);
-
-#ifdef COLLADA_DEBUG
- if (quad) {
- fprintf(stderr, "face uv:\n"
- "((%d, %d, %d, %d))\n"
- "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n",
-
- indices[index + 0],
- indices[index + 1],
- indices[index + 2],
- indices[index + 3],
-
- mtface->uv[0][0], mtface->uv[0][1],
- mtface->uv[1][0], mtface->uv[1][1],
- mtface->uv[2][0], mtface->uv[2][1],
- mtface->uv[3][0], mtface->uv[3][1]);
+ for (int index = 0; index < count; index++) {
+ int uv_index = indices[index+start_index];
+ uvs.getUV(uv_index, mloopuv[index].uv);
}
- else {
- fprintf(stderr, "face uv:\n"
- "((%d, %d, %d))\n"
- "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n",
-
- indices[index + 0],
- indices[index + 1],
- indices[index + 2],
-
- mtface->uv[0][0], mtface->uv[0][1],
- mtface->uv[1][0], mtface->uv[1][1],
- mtface->uv[2][0], mtface->uv[2][1]);
- }
-#endif
}
#ifdef COLLADA_DEBUG
@@ -329,91 +276,6 @@ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
}
}
-int MeshImporter::triangulate_poly(unsigned int *indices, int totvert, MVert *verts, std::vector<unsigned int>& tri)
-{
- ListBase dispbase;
- DispList *dl;
- float *vert;
- int i = 0;
-
- dispbase.first = dispbase.last = NULL;
-
- dl = (DispList *)MEM_callocN(sizeof(DispList), "poly disp");
- dl->nr = totvert;
- dl->type = DL_POLY;
- dl->parts = 1;
- dl->verts = vert = (float *)MEM_callocN(totvert * 3 * sizeof(float), "poly verts");
- dl->index = (int *)MEM_callocN(sizeof(int) * 3 * totvert, "dl index");
-
- BLI_addtail(&dispbase, dl);
-
- for (i = 0; i < totvert; i++) {
- copy_v3_v3(vert, verts[indices[i]].co);
- vert += 3;
- }
-
- BKE_displist_fill(&dispbase, &dispbase, 0);
-
- int tottri = 0;
- dl = (DispList *)dispbase.first;
-
- if (dl->type == DL_INDEX3) {
- tottri = dl->parts;
-
- int *index = dl->index;
- for (i = 0; i < tottri; i++) {
- int t[3] = {*index, *(index + 1), *(index + 2)};
-
- std::sort(t, t + 3);
-
- tri.push_back(t[0]);
- tri.push_back(t[1]);
- tri.push_back(t[2]);
-
- index += 3;
- }
- }
-
- BKE_displist_free(&dispbase);
-
- return tottri;
-}
-
-int MeshImporter::count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me)
-{
- COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
- unsigned int i;
- int tottri = 0;
-
- for (i = 0; i < prim_arr.getCount(); i++) {
-
- COLLADAFW::MeshPrimitive *mp = prim_arr[i];
- int type = mp->getPrimitiveType();
- size_t prim_totface = mp->getFaceCount();
- unsigned int *indices = mp->getPositionIndices().getData();
-
- if (type == COLLADAFW::MeshPrimitive::POLYLIST ||
- type == COLLADAFW::MeshPrimitive::POLYGONS)
- {
- COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
- COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray();
-
- for (unsigned int j = 0; j < prim_totface; j++) {
- int vcount = vcounta[j];
-
- if (vcount > 4) {
- std::vector<unsigned int> tri;
-
- // tottri += triangulate_poly(indices, vcount, me->mvert, tri) - 1; // XXX why - 1?!
- tottri += triangulate_poly(indices, vcount, me->mvert, tri);
- }
-
- indices += vcount;
- }
- }
- }
- return tottri;
-}
// =====================================================================
// condition 1: The Primitive has normals
@@ -471,10 +333,11 @@ bool MeshImporter::primitive_has_faces(COLLADAFW::MeshPrimitive *mp) {
// hint: This is done because mesh->getFacesCount() does
// count loose edges as extra faces, which is not what we want here.
// =================================================================
-void MeshImporter::allocate_face_data(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris)
+void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
- COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
- int total_facecount = 0;
+ COLLADAFW::MeshPrimitiveArray& prim_arr = collada_mesh->getMeshPrimitives();
+ int total_poly_count = 0;
+ int total_loop_count = 0;
// collect edge_count and face_count from all parts
for (int i = 0; i < prim_arr.getCount(); i++) {
@@ -485,21 +348,77 @@ void MeshImporter::allocate_face_data(COLLADAFW::Mesh *mesh, Mesh *me, int new_t
case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
case COLLADAFW::MeshPrimitive::POLYLIST:
case COLLADAFW::MeshPrimitive::POLYGONS: {
- size_t prim_totface = mp->getFaceCount();
- total_facecount += prim_totface;
+
+ COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
+ size_t prim_poly_count = mpvc->getFaceCount();
+
+ size_t prim_loop_count = 0;
+ for(int index=0; index < prim_poly_count; index++) {
+ prim_loop_count += get_vertex_count(mpvc, index);
+ }
+
+ total_poly_count += prim_poly_count;
+ total_loop_count += prim_loop_count;
break;
}
default: break;
}
}
- // allocate space for faces
- if (total_facecount > 0) {
- me->totface = total_facecount + new_tris;
- me->mface = (MFace *)CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
+ // Add the data containers
+ if (total_poly_count > 0) {
+ me->totpoly = total_poly_count;
+ me->totloop = total_loop_count;
+ me->mpoly = (MPoly *)CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, me->totpoly);
+ me->mloop = (MLoop *)CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, me->totloop);
+
+ unsigned int totuvset = collada_mesh->getUVCoords().getInputInfosArray().getCount();
+ for (int i = 0; i < totuvset; i++) {
+ if (collada_mesh->getUVCoords().getLength(i) == 0) {
+ totuvset = 0;
+ break;
+ }
+ }
+
+ if (totuvset > 0) {
+ for (int i = 0; i < totuvset; i++) {
+ COLLADAFW::MeshVertexData::InputInfos *info = collada_mesh->getUVCoords().getInputInfosArray()[i];
+ COLLADAFW::String &uvname = info->mName;
+ int x = 0;
+ // Allocate space for UV_data
+ CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, uvname.c_str());
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, uvname.c_str());
+ }
+ // activate the first uv map
+ me->mtpoly = (MTexPoly *)CustomData_get_layer_n(&me->pdata, CD_MTEXPOLY, 0);
+ me->mloopuv = (MLoopUV *) CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, 0);
+ }
}
}
+unsigned int MeshImporter::get_vertex_count(COLLADAFW::Polygons *mp, int index) {
+ int type = mp->getPrimitiveType();
+ int result;
+ switch (type) {
+ case COLLADAFW::MeshPrimitive::TRIANGLES:
+ case COLLADAFW::MeshPrimitive::TRIANGLE_FANS: {
+ result = 3;
+ break;
+ }
+ case COLLADAFW::MeshPrimitive::POLYLIST:
+ case COLLADAFW::MeshPrimitive::POLYGONS: {
+ result = mp->getGroupedVerticesVertexCountArray()[index];
+ break;
+ }
+ default: {
+ result = -1;
+ break;
+ }
+ }
+ return result;
+}
+
+
unsigned int MeshImporter::get_loose_edge_count(COLLADAFW::Mesh *mesh) {
COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
int loose_edge_count = 0;
@@ -606,256 +525,118 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
//
// TODO: import uv set names
// ========================================================================
-void MeshImporter::read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris) //TODO:: Refactor. Possibly replace by iterators
+void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
unsigned int i;
- allocate_face_data(mesh, me, new_tris);
-
- // allocate UV Maps
- unsigned int totuvset = mesh->getUVCoords().getInputInfosArray().getCount();
+ allocate_poly_data(collada_mesh, me);
- for (i = 0; i < totuvset; i++) {
- if (mesh->getUVCoords().getLength(i) == 0) {
- totuvset = 0;
- break;
- }
- }
-
- for (i = 0; i < totuvset; i++) {
- COLLADAFW::MeshVertexData::InputInfos *info = mesh->getUVCoords().getInputInfosArray()[i];
- CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_CALLOC, NULL, me->totface, info->mName.c_str());
- //this->set_layername_map[i] = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
- }
-
- // activate the first uv map
- if (totuvset) me->mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, 0);
-
- UVDataWrapper uvs(mesh->getUVCoords());
-
-#ifdef COLLADA_DEBUG
- // uvs.print();
-#endif
+ UVDataWrapper uvs(collada_mesh->getUVCoords());
- MFace *mface = me->mface;
+ MPoly *mpoly = me->mpoly;
+ MLoop *mloop = me->mloop;
+ int loop_index = 0;
MaterialIdPrimitiveArrayMap mat_prim_map;
- int face_index = 0;
-
- COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
-
- COLLADAFW::MeshVertexData& nor = mesh->getNormals();
+ COLLADAFW::MeshPrimitiveArray& prim_arr = collada_mesh->getMeshPrimitives();
+ COLLADAFW::MeshVertexData& nor = collada_mesh->getNormals();
for (i = 0; i < prim_arr.getCount(); i++) {
COLLADAFW::MeshPrimitive *mp = prim_arr[i];
// faces
- size_t prim_totface = mp->getFaceCount();
- unsigned int *indices = mp->getPositionIndices().getData();
- unsigned int *nind = mp->getNormalIndices().getData();
+ size_t prim_totpoly = mp->getFaceCount();
+ unsigned int *position_indices = mp->getPositionIndices().getData();
+ unsigned int *normal_indices = mp->getNormalIndices().getData();
bool mp_has_normals = primitive_has_useable_normals(mp);
bool mp_has_faces = primitive_has_faces(mp);
- int type = mp->getPrimitiveType();
- int index = 0;
+ int collada_meshtype = mp->getPrimitiveType();
- // since we cannot set mface->mat_nr here, we store a portion of me->mface in Primitive
- Primitive prim = {mface, 0};
+ // since we cannot set mpoly->mat_nr here, we store a portion of me->mface in Primitive
+ Primitive prim = {mpoly, 0};
COLLADAFW::IndexListArray& index_list_array = mp->getUVCoordIndicesArray();
-#ifdef COLLADA_DEBUG
- /*
- fprintf(stderr, "Primitive %d:\n", i);
- for (unsigned int j = 0; j < totuvset; j++) {
- print_index_list(*index_list_array[j]);
- }
- */
-#endif
-
- if (type == COLLADAFW::MeshPrimitive::TRIANGLES) {
- for (unsigned int j = 0; j < prim_totface; j++) {
-
- set_face_indices(mface, indices, false);
- indices += 3;
-
-#if 0
- for (unsigned int k = 0; k < totuvset; k++) {
- if (!index_list_array.empty() && index_list_array[k]) {
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
- set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, false);
- }
- }
-#else
- for (unsigned int k = 0; k < index_list_array.getCount(); k++) {
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
- set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, false);
- }
-#endif
-
- test_index_face(mface, &me->fdata, face_index, 3);
-
- if (mp_has_normals) {
- if (!flat_face(nind, nor, 3))
- mface->flag |= ME_SMOOTH;
-
- nind += 3;
- }
-
- index += 3;
- mface++;
- face_index++;
- prim.totface++;
- }
- }
-
// If MeshPrimitive is TRIANGLE_FANS we split it into triangles
// The first trifan vertex will be the first vertex in every triangle
- if (type == COLLADAFW::MeshPrimitive::TRIANGLE_FANS) {
+ // XXX The proper function of TRIANGLE_FANS is not tested!!!
+ // XXX In particular the handling of the normal_indices looks very wrong to me
+ if (collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLE_FANS) {
unsigned grouped_vertex_count = mp->getGroupedVertexElementsCount();
for (unsigned int group_index = 0; group_index < grouped_vertex_count; group_index++) {
- unsigned int first_vertex = indices[0]; // Store first trifan vertex
- unsigned int first_normal = nind[0]; // Store first trifan vertex normal
+ unsigned int first_vertex = position_indices[0]; // Store first trifan vertex
+ unsigned int first_normal = normal_indices[0]; // Store first trifan vertex normal
unsigned int vertex_count = mp->getGroupedVerticesVertexCount(group_index);
for (unsigned int vertex_index = 0; vertex_index < vertex_count - 2; vertex_index++) {
// For each triangle store indeces of its 3 vertices
- unsigned int triangle_vertex_indices[3] = {first_vertex, indices[1], indices[2]};
- set_face_indices(mface, triangle_vertex_indices, false);
- test_index_face(mface, &me->fdata, face_index, 3);
+ unsigned int triangle_vertex_indices[3] = {first_vertex, position_indices[1], position_indices[2]};
+ set_poly_indices(mpoly, mloop, loop_index, triangle_vertex_indices, 3);
if (mp_has_normals) { // vertex normals, same inplementation as for the triangles
// the same for vertces normals
- unsigned int vertex_normal_indices[3] = {first_normal, nind[1], nind[2]};
- if (!flat_face(vertex_normal_indices, nor, 3))
- mface->flag |= ME_SMOOTH;
- nind++;
+ unsigned int vertex_normal_indices[3] = {first_normal, normal_indices[1], normal_indices[2]};
+ if (!is_flat_face(vertex_normal_indices, nor, 3))
+ mpoly->flag |= ME_SMOOTH;
+ normal_indices++;
}
- mface++; // same inplementation as for the triangles
- indices++;
- face_index++;
- prim.totface++;
+ mpoly++;
+ mloop += 3;
+ loop_index += 3;
+ prim.totpoly++;
+
}
// Moving cursor to the next triangle fan.
if (mp_has_normals)
- nind += 2;
+ normal_indices += 2;
- indices += 2;
+ position_indices += 2;
}
}
- else if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
- COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
- COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray();
- for (unsigned int j = 0; j < prim_totface; j++) {
+ if (collada_meshtype == COLLADAFW::MeshPrimitive::POLYLIST ||
+ collada_meshtype == COLLADAFW::MeshPrimitive::POLYGONS ||
+ collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLES) {
+ COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
+ for (unsigned int j = 0; j < prim_totpoly; j++) {
- // face
- int vcount = vcounta[j];
- if (vcount == 3 || vcount == 4) {
-
- set_face_indices(mface, indices, vcount == 4);
-
- // set mtface for each uv set
- // it is assumed that all primitives have equal number of UV sets
-
-#if 0
- for (unsigned int k = 0; k < totuvset; k++) {
- if (!index_list_array.empty() && index_list_array[k]) {
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
- set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, mface->v4 != 0);
- }
- }
-#else
- for (unsigned int k = 0; k < index_list_array.getCount(); k++) {
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
- set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, vcount == 4);
- }
-#endif
+ // Vertices in polygon:
+ int vcount = get_vertex_count(mpvc, j);
+ set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount);
- test_index_face(mface, &me->fdata, face_index, vcount);
- if (mp_has_normals) {
- if (!flat_face(nind, nor, vcount))
- mface->flag |= ME_SMOOTH;
+ for (unsigned int l = 0; l < index_list_array.getCount(); l++) {
+ int uvset_index = index_list_array[l]->getSetIndex();
- nind += vcount;
- }
-
- mface++;
- face_index++;
- prim.totface++;
-
- }
- else {
- std::vector<unsigned int> tri;
-
- triangulate_poly(indices, vcount, me->mvert, tri);
-
- for (unsigned int k = 0; k < tri.size() / 3; k++) {
- int v = k * 3;
- unsigned int uv_indices[3] = {
- index + tri[v],
- index + tri[v + 1],
- index + tri[v + 2]
- };
- unsigned int tri_indices[3] = {
- indices[tri[v]],
- indices[tri[v + 1]],
- indices[tri[v + 2]]
- };
-
- set_face_indices(mface, tri_indices, false);
-
-#if 0
- for (unsigned int l = 0; l < totuvset; l++) {
- if (!index_list_array.empty() && index_list_array[l]) {
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, l);
- set_face_uv(&mtface[face_index], uvs, l, *index_list_array[l], uv_indices);
- }
- }
-#else
- for (unsigned int l = 0; l < index_list_array.getCount(); l++) {
- int uvset_index = index_list_array[l]->getSetIndex();
-
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index);
- set_face_uv(&mtface[face_index], uvs, *index_list_array[l], uv_indices);
- }
-#endif
-
-
- test_index_face(mface, &me->fdata, face_index, 3);
-
- if (mp_has_normals) {
- unsigned int ntri[3] = {nind[tri[v]], nind[tri[v + 1]], nind[tri[v + 2]]};
+ // get mtface by face index and uv set index
+ MLoopUV *mloopuv = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, uvset_index);
- if (!flat_face(ntri, nor, 3))
- mface->flag |= ME_SMOOTH;
- }
-
- mface++;
- face_index++;
- prim.totface++;
- }
+ set_face_uv(mloopuv+loop_index, uvs, loop_index, *index_list_array[l], vcount);
+ }
- if (mp_has_normals)
- nind += vcount;
+ if (mp_has_normals) {
+ if (!is_flat_face(normal_indices, nor, vcount))
+ mpoly->flag |= ME_SMOOTH;
}
+
+ mpoly++;
+ mloop += vcount;
+ loop_index += vcount;
+ prim.totpoly++;
+
+ if (mp_has_normals)
+ normal_indices += vcount;
- index += vcount;
- indices += vcount;
+ position_indices += vcount;
}
}
- else if (type == COLLADAFW::MeshPrimitive::LINES) {
+
+ else if (collada_meshtype == COLLADAFW::MeshPrimitive::LINES) {
continue; // read the lines later after all the rest is done
}
@@ -863,7 +644,7 @@ void MeshImporter::read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris) //T
mat_prim_map[mp->getMaterialId()].push_back(prim);
}
- geom_uid_mat_mapping_map[mesh->getUniqueId()] = mat_prim_map;
+ geom_uid_mat_mapping_map[collada_mesh->getUniqueId()] = mat_prim_map;
}
void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i, int stride)
@@ -896,8 +677,7 @@ void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i,
break;
}
}
-
-bool MeshImporter::flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count)
+bool MeshImporter::is_flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count)
{
float a[3], b[3];
@@ -919,8 +699,6 @@ bool MeshImporter::flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor,
return true;
}
-MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce) : unitconverter(unitconv), scene(sce), armature_importer(arm) {
-}
void MeshImporter::bmeshConversion()
{
@@ -929,10 +707,9 @@ void MeshImporter::bmeshConversion()
{
if ((*m).second) {
Mesh *me = (*m).second;
- BKE_mesh_convert_mfaces_to_mpolys(me);
BKE_mesh_tessface_clear(me);
-
BKE_mesh_calc_normals_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL);
+ //BKE_mesh_validate(me, 1);
}
}
}
@@ -1137,9 +914,10 @@ void MeshImporter::optimize_material_assignements()
MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
std::map<COLLADAFW::UniqueId, Material *>& uid_material_map,
Object *ob, const COLLADAFW::UniqueId *geom_uid,
- MTex **color_texture, char *layername, MTFace *texture_face,
+ char *layername, MTFace *texture_face,
std::map<Material *, TexIndexTextureArrayMap>& material_texture_mapping_map, short mat_index)
{
+ MTex *color_texture = NULL;
Mesh *me = (Mesh *)ob->data;
const COLLADAFW::UniqueId& ma_uid = cmaterial.getReferencedMaterial();
@@ -1167,17 +945,17 @@ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmateri
// loop through <bind_vertex_inputs>
for (i = 0; i < tex_array.getCount(); i++) {
- *color_texture = assign_textures_to_uvlayer(tex_array[i], me, texindex_texarray_map,
- *color_texture);
+ color_texture = assign_textures_to_uvlayer(tex_array[i], me, texindex_texarray_map,
+ color_texture);
}
// set texture face
- if (*color_texture &&
- strlen((*color_texture)->uvname) &&
- strcmp(layername, (*color_texture)->uvname) != 0) {
+ if (color_texture &&
+ strlen((color_texture)->uvname) &&
+ strcmp(layername, color_texture->uvname) != 0) {
texture_face = (MTFace *)CustomData_get_layer_named(&me->fdata, CD_MTFACE,
- (*color_texture)->uvname);
- strcpy(layername, (*color_texture)->uvname);
+ color_texture->uvname);
+ strcpy(layername, color_texture->uvname);
}
MaterialIdPrimitiveArrayMap& mat_prim_map = geom_uid_mat_mapping_map[*geom_uid];
@@ -1192,19 +970,18 @@ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmateri
for (it = prims.begin(); it != prims.end(); it++) {
Primitive& prim = *it;
- MFace *mface = prim.mface;
+ MPoly *mpoly = prim.mpoly;
- for (i = 0; i < prim.totface; i++, mface++) {
- mface->mat_nr = mat_index;
+ for (i = 0; i < prim.totpoly; i++, mpoly++) {
+ mpoly->mat_nr = mat_index;
// bind texture images to faces
- if (texture_face && (*color_texture)) {
- texture_face->tpage = (Image *)(*color_texture)->tex->ima;
+ if (texture_face && color_texture) {
+ texture_face->tpage = (Image *)color_texture->tex->ima;
texture_face++;
}
}
}
- }
-
+ }
return texture_face;
}
@@ -1251,15 +1028,15 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
// replace ob->data freeing the old one
Mesh *old_mesh = (Mesh *)ob->data;
+ Mesh *new_mesh = uid_mesh_map[*geom_uid];
- set_mesh(ob, uid_mesh_map[*geom_uid]);
+ set_mesh(ob, new_mesh);
if (old_mesh->id.us == 0) BKE_libblock_free(&G.main->mesh, old_mesh);
char layername[100];
layername[0] = '\0';
MTFace *texture_face = NULL;
- MTex *color_texture = NULL;
COLLADAFW::MaterialBindingArray& mat_array =
geom->getMaterialBindings();
@@ -1269,7 +1046,7 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
if (mat_array[i].getReferencedMaterial().isValid()) {
texture_face = assign_material_to_geom(mat_array[i], uid_material_map, ob, geom_uid,
- &color_texture, layername, texture_face,
+ layername, texture_face,
material_texture_mapping_map, i);
}
else {
@@ -1283,11 +1060,7 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
// create a mesh storing a pointer in a map so it can be retrieved later by geometry UID
bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
{
- // TODO: import also uvs, normals
- // XXX what to do with normal indices?
- // XXX num_normals may be != num verts, then what to do?
- // check geometry->getType() first
if (geom->getType() != COLLADAFW::Geometry::GEO_TYPE_MESH) {
// TODO: report warning
fprintf(stderr, "Mesh type %s is not supported\n", bc_geomTypeToStr(geom->getType()));
@@ -1306,23 +1079,16 @@ bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
me->id.us--; // is already 1 here, but will be set later in set_mesh
// store the Mesh pointer to link it later with an Object
+ // mesh_geom_map needed to map mesh to its geometry name (for shape key naming)
this->uid_mesh_map[mesh->getUniqueId()] = me;
- // needed to map mesh to its geometry name (needed for shape key naming)
this->mesh_geom_map[std::string(me->id.name)] = str_geom_id;
-
- int new_tris = 0;
read_vertices(mesh, me);
-
- new_tris = count_new_tris(mesh, me);
-
- read_faces(mesh, me, new_tris);
-
- BKE_mesh_make_edges(me, 0);
+ read_polys(mesh, me);
+ BKE_mesh_calc_edges(me, 0);
// read_lines() must be called after the face edges have been generated.
// Oterwise the loose edges will be silently deleted again.
read_lines(mesh, me);
-
return true;
}
diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h
index 8b0f5cdc200..751e6faf02b 100644
--- a/source/blender/collada/MeshImporter.h
+++ b/source/blender/collada/MeshImporter.h
@@ -31,6 +31,7 @@
#include <vector>
#include "COLLADAFWIndexList.h"
+#include "COLLADAFWPolygons.h"
#include "COLLADAFWInstanceGeometry.h"
#include "COLLADAFWMaterialBinding.h"
#include "COLLADAFWMesh.h"
@@ -89,30 +90,28 @@ private:
std::map<COLLADAFW::UniqueId, Mesh*> uid_mesh_map; // geometry unique id-to-mesh map
std::map<COLLADAFW::UniqueId, Object*> uid_object_map; // geom uid-to-object
std::vector<Object*> imported_objects; // list of imported objects
- // this structure is used to assign material indices to faces
+
+ // this structure is used to assign material indices to polygons
// it holds a portion of Mesh faces and corresponds to a DAE primitive list (<triangles>, <polylist>, etc.)
struct Primitive {
- MFace *mface;
- unsigned int totface;
+ MPoly *mpoly;
+ unsigned int totpoly;
};
typedef std::map<COLLADAFW::MaterialId, std::vector<Primitive> > MaterialIdPrimitiveArrayMap;
std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map; // crazy name!
std::multimap<COLLADAFW::UniqueId, COLLADAFW::UniqueId> materials_mapped_to_geom; //< materials that have already been mapped to a geometry. A pair of geom uid and mat uid, one geometry can have several materials
-
- void set_face_indices(MFace *mface, unsigned int *indices, bool quad);
-
- // not used anymore, test_index_face from blenkernel is better
-#if 0
- // change face indices order so that v4 is not 0
- void rotate_face_indices(MFace *mface);
-#endif
-
- void set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
- COLLADAFW::IndexList& index_list, unsigned int *tris_indices);
-
- void set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
- COLLADAFW::IndexList& index_list, int index, bool quad);
+ void set_poly_indices(MPoly *mpoly,
+ MLoop *mloop,
+ int loop_index,
+ unsigned int *indices,
+ int loop_count);
+
+ void set_face_uv(MLoopUV *mloopuv,
+ UVDataWrapper &uvs,
+ int loop_index,
+ COLLADAFW::IndexList& index_list,
+ int count);
#ifdef COLLADA_DEBUG
void print_index_list(COLLADAFW::IndexList& index_list);
@@ -121,11 +120,7 @@ private:
bool is_nice_mesh(COLLADAFW::Mesh *mesh);
void read_vertices(COLLADAFW::Mesh *mesh, Mesh *me);
-
- int triangulate_poly(unsigned int *indices, int totvert, MVert *verts, std::vector<unsigned int>& tri);
-
- int count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me);
-
+
bool primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp);
bool primitive_has_faces(COLLADAFW::MeshPrimitive *mp);
@@ -135,15 +130,16 @@ private:
CustomData create_edge_custom_data(EdgeHash *eh);
- void allocate_face_data(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris);
+ void allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me);
// TODO: import uv set names
- void read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris);
+ void read_polys(COLLADAFW::Mesh *mesh, Mesh *me);
void read_lines(COLLADAFW::Mesh *mesh, Mesh *me);
+ unsigned int get_vertex_count(COLLADAFW::Polygons *mp, int index);
void get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i, int stride);
- bool flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count);
+ bool is_flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count);
std::vector<Object *> get_all_users_of(Mesh *reference_mesh);
@@ -166,7 +162,7 @@ public:
MTFace *assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
Object *ob, const COLLADAFW::UniqueId *geom_uid,
- MTex **color_texture, char *layername, MTFace *texture_face,
+ char *layername, MTFace *texture_face,
std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, short mat_index);
diff --git a/source/blender/collada/SConscript b/source/blender/collada/SConscript
index 18ef62e6c85..4da99a21517 100644
--- a/source/blender/collada/SConscript
+++ b/source/blender/collada/SConscript
@@ -33,9 +33,9 @@ defs = []
# TODO sanitize inc path building
# relative paths to include dirs, space-separated, string
if env['OURPLATFORM']=='darwin':
- incs = '../ikplugin ../../../intern/iksolver/extern ../blenlib ../blenkernel ../windowmanager ../blenloader ../makesdna ../makesrna ../editors/include ../imbuf ../../../intern/guardedalloc [OPENCOLLADA]/COLLADAStreamWriter [OPENCOLLADA]/COLLADABaseUtils [OPENCOLLADA]/COLLADAFramework [OPENCOLLADA]/COLLADASaxFrameworkLoader [OPENCOLLADA]/GeneratedSaxParser '.replace('[OPENCOLLADA]', env['BF_OPENCOLLADA_INC'])
+ incs = '../ikplugin ../../../intern/iksolver/extern ../blenlib ../blenkernel ../windowmanager ../blenloader ../makesdna ../makesrna ../editors/include ../imbuf ../bmesh ../../../intern/guardedalloc [OPENCOLLADA]/COLLADAStreamWriter [OPENCOLLADA]/COLLADABaseUtils [OPENCOLLADA]/COLLADAFramework [OPENCOLLADA]/COLLADASaxFrameworkLoader [OPENCOLLADA]/GeneratedSaxParser '.replace('[OPENCOLLADA]', env['BF_OPENCOLLADA_INC'])
else:
- incs = '../ikplugin ../../../intern/iksolver/extern ../blenlib ../blenkernel ../windowmanager ../makesdna ../blenloader ../makesrna ../editors/include ../imbuf ../../../intern/guardedalloc [OPENCOLLADA]/COLLADAStreamWriter/include [OPENCOLLADA]/COLLADABaseUtils/include [OPENCOLLADA]/COLLADAFramework/include [OPENCOLLADA]/COLLADASaxFrameworkLoader/include [OPENCOLLADA]/GeneratedSaxParser/include '.replace('[OPENCOLLADA]', env['BF_OPENCOLLADA_INC'])
+ incs = '../ikplugin ../../../intern/iksolver/extern ../blenlib ../blenkernel ../windowmanager ../makesdna ../blenloader ../makesrna ../editors/include ../imbuf ../bmesh ../../../intern/guardedalloc [OPENCOLLADA]/COLLADAStreamWriter/include [OPENCOLLADA]/COLLADABaseUtils/include [OPENCOLLADA]/COLLADAFramework/include [OPENCOLLADA]/COLLADASaxFrameworkLoader/include [OPENCOLLADA]/GeneratedSaxParser/include '.replace('[OPENCOLLADA]', env['BF_OPENCOLLADA_INC'])
if env['BF_BUILDINFO']:
defs.append('WITH_BUILDINFO')
diff --git a/source/blender/collada/TransformReader.cpp b/source/blender/collada/TransformReader.cpp
index 67166d819a6..e0ba77e2554 100644
--- a/source/blender/collada/TransformReader.cpp
+++ b/source/blender/collada/TransformReader.cpp
@@ -46,30 +46,28 @@ void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::
COLLADAFW::Transformation *tm = node->getTransformations()[i];
COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
- if (type == COLLADAFW::Transformation::MATRIX) {
- // XXX why does this return and discard all following transformations?
- dae_matrix_to_mat4(tm, mat);
- return;
- }
- else {
- switch (type) {
- case COLLADAFW::Transformation::TRANSLATE:
- dae_translate_to_mat4(tm, cur);
- break;
- case COLLADAFW::Transformation::ROTATE:
- dae_rotate_to_mat4(tm, cur);
- break;
- case COLLADAFW::Transformation::SCALE:
- dae_scale_to_mat4(tm, cur);
- break;
- case COLLADAFW::Transformation::LOOKAT:
- case COLLADAFW::Transformation::SKEW:
- fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n");
- break;
- }
- copy_m4_m4(copy, mat);
- mult_m4_m4m4(mat, copy, cur);
+ switch (type) {
+ case COLLADAFW::Transformation::MATRIX:
+ // XXX why does this return and discard all following transformations?
+ dae_matrix_to_mat4(tm, mat);
+ return;
+ case COLLADAFW::Transformation::TRANSLATE:
+ dae_translate_to_mat4(tm, cur);
+ break;
+ case COLLADAFW::Transformation::ROTATE:
+ dae_rotate_to_mat4(tm, cur);
+ break;
+ case COLLADAFW::Transformation::SCALE:
+ dae_scale_to_mat4(tm, cur);
+ break;
+ case COLLADAFW::Transformation::LOOKAT:
+ case COLLADAFW::Transformation::SKEW:
+ fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n");
+ break;
}
+
+ copy_m4_m4(copy, mat);
+ mult_m4_m4m4(mat, copy, cur);
if (animation_map) {
// AnimationList that drives this Transformation
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index b3c288c8fc5..e75123c1e76 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -75,6 +75,7 @@ int collada_export(Scene *sce,
int include_material_textures,
int use_texture_copies,
+ int triangulate,
int use_object_instantiation,
int sort_by_name,
int second_life)
@@ -106,6 +107,7 @@ int collada_export(Scene *sce,
export_settings.include_material_textures= include_material_textures != 0;
export_settings.use_texture_copies = use_texture_copies != 0;
+ export_settings.triangulate = triangulate != 0;
export_settings.use_object_instantiation = use_object_instantiation != 0;
export_settings.sort_by_name = sort_by_name != 0;
export_settings.second_life = second_life != 0;
diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h
index 2fa5b22bb15..642259da7fc 100644
--- a/source/blender/collada/collada.h
+++ b/source/blender/collada/collada.h
@@ -67,6 +67,7 @@ int collada_export(Scene *sce,
int include_material_textures,
int use_texture_copies,
+ int triangulate,
int use_object_instantiation,
int sort_by_name,
int second_life);
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index f43878943c1..c56aa3fdaf0 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -56,6 +56,7 @@ extern "C" {
#include "WM_api.h" // XXX hrm, see if we can do without this
#include "WM_types.h"
+#include "bmesh.h"
}
float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index)
@@ -137,25 +138,38 @@ Object *bc_add_object(Scene *scene, int type, const char *name)
return ob;
}
-Mesh *bc_to_mesh_apply_modifiers(Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type)
+Mesh *bc_get_mesh_copy(Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate)
{
Mesh *tmpmesh;
CustomDataMask mask = CD_MASK_MESH;
DerivedMesh *dm = NULL;
- switch (export_mesh_type) {
- case BC_MESH_TYPE_VIEW: {
- dm = mesh_create_derived_view(scene, ob, mask);
- break;
- }
- case BC_MESH_TYPE_RENDER: {
- dm = mesh_create_derived_render(scene, ob, mask);
- break;
+ if(apply_modifiers) {
+ switch (export_mesh_type) {
+ case BC_MESH_TYPE_VIEW: {
+ dm = mesh_create_derived_view(scene, ob, mask);
+ break;
+ }
+ case BC_MESH_TYPE_RENDER: {
+ dm = mesh_create_derived_render(scene, ob, mask);
+ break;
+ }
}
}
+ else {
+ dm = mesh_create_derived((Mesh *)ob->data, ob, NULL);
+ }
tmpmesh = BKE_mesh_add(G.main, "ColladaMesh"); // name is not important here
DM_to_mesh(dm, tmpmesh, ob);
dm->release(dm);
+
+ if (triangulate) {
+ bc_triangulate_mesh(tmpmesh);
+ }
+
+ // XXX Not sure if we need that for ngon_export as well.
+ BKE_mesh_tessface_ensure(tmpmesh);
+
return tmpmesh;
}
@@ -366,3 +380,14 @@ void bc_match_scale(std::vector<Object *> *objects_done,
}
}
+
+void bc_triangulate_mesh(Mesh *me) {
+ bool use_beauty = false;
+ bool tag_only = false;
+
+ BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ BM_mesh_bm_from_me(bm, me, FALSE, 0);
+ BM_mesh_triangulate(bm, use_beauty, tag_only, NULL, NULL);
+ BM_mesh_bm_to_me(bm, me, FALSE);
+ BM_mesh_free(bm);
+}
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index 892b57e6a4a..f8e6f09e498 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -62,7 +62,7 @@ extern float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsi
extern int bc_test_parent_loop(Object *par, Object *ob);
extern int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space = true);
extern Object *bc_add_object(Scene *scene, int type, const char *name);
-extern Mesh *bc_to_mesh_apply_modifiers(Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type);
+extern Mesh *bc_get_mesh_copy(Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate);
extern Object *bc_get_assigned_armature(Object *ob);
extern Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *ob);
@@ -84,4 +84,24 @@ extern int bc_get_active_UVLayer(Object *ob);
extern std::string bc_replace_string(std::string data, const std::string& pattern, const std::string& replacement);
extern std::string bc_url_encode(std::string data);
extern void bc_match_scale(std::vector<Object *> *objects_done, Scene &sce, UnitConverter &unit_converter);
+
+extern void bc_triangulate_mesh(Mesh *me);
+
+
+class BCPolygonNormalsIndices
+{
+ std::vector<unsigned int> normal_indices;
+
+ public:
+
+ void add_index(unsigned int index) {
+ normal_indices.push_back(index);
+ }
+
+ unsigned int operator[](unsigned int i) {
+ return normal_indices[i];
+ }
+
+};
+
#endif
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp
index 864d6f08311..e4dd72d79e9 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_ImageNode.cpp
@@ -25,6 +25,7 @@
#include "COM_ExecutionSystem.h"
#include "COM_ImageOperation.h"
#include "COM_MultilayerImageOperation.h"
+#include "COM_ConvertPremulToStraightOperation.h"
#include "BKE_node.h"
#include "BLI_utildefines.h"
@@ -72,6 +73,7 @@ void ImageNode::convertToOperations(ExecutionSystem *graph, CompositorContext *c
ImageUser *imageuser = (ImageUser *)editorNode->storage;
int framenumber = context->getFramenumber();
int numberOfOutputs = this->getNumberOfOutputSockets();
+ bool outputStraightAlpha = editorNode->custom1 & CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT;
BKE_image_user_frame_calc(imageuser, context->getFramenumber(), 0);
/* force a load, we assume iuser index will be set OK anyway */
@@ -138,7 +140,15 @@ void ImageNode::convertToOperations(ExecutionSystem *graph, CompositorContext *c
if (numberOfOutputs > 0) {
ImageOperation *operation = new ImageOperation();
if (outputImage->isConnected()) {
- outputImage->relinkConnections(operation->getOutputSocket());
+ if (outputStraightAlpha) {
+ NodeOperation *alphaConvertOperation = new ConvertPremulToStraightOperation();
+ addLink(graph, operation->getOutputSocket(0), alphaConvertOperation->getInputSocket(0));
+ outputImage->relinkConnections(alphaConvertOperation->getOutputSocket());
+ graph->addOperation(alphaConvertOperation);
+ }
+ else {
+ outputImage->relinkConnections(operation->getOutputSocket());
+ }
}
operation->setImage(image);
operation->setImageUser(imageuser);
diff --git a/source/blender/compositor/operations/COM_TranslateOperation.h b/source/blender/compositor/operations/COM_TranslateOperation.h
index d53c3e464fc..a638ae7ce69 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.h
+++ b/source/blender/compositor/operations/COM_TranslateOperation.h
@@ -33,8 +33,6 @@ private:
float m_deltaX;
float m_deltaY;
bool m_isDeltaSet;
- float m_relativeOffsetX;
- float m_relativeOffsetY;
float m_factorX;
float m_factorY;
public:
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index bc7b62df185..533420ad641 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -36,6 +36,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
@@ -3341,21 +3343,21 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
icon = ICON_VISIBLE_IPO_OFF;
if (ale->type == ANIMTYPE_FCURVE)
- tooltip = "Channel is visible in Graph Editor for editing";
+ tooltip = TIP_("Channel is visible in Graph Editor for editing");
else
- tooltip = "Channel(s) are visible in Graph Editor for editing";
+ tooltip = TIP_("Channels are visible in Graph Editor for editing");
break;
case ACHANNEL_SETTING_EXPAND: /* expanded triangle */
//icon = ((enabled)? ICON_TRIA_DOWN : ICON_TRIA_RIGHT);
icon = ICON_TRIA_RIGHT;
- tooltip = "Make channels grouped under this channel visible";
+ tooltip = TIP_("Make channels grouped under this channel visible");
break;
case ACHANNEL_SETTING_SOLO: /* NLA Tracks only */
//icon = ((enabled)? ICON_LAYER_ACTIVE : ICON_LAYER_USED);
icon = ICON_LAYER_USED;
- tooltip = "NLA Track is the only one evaluated for the AnimData block it belongs to";
+ tooltip = TIP_("NLA Track is the only one evaluated for the AnimData block it belongs to");
break;
/* --- */
@@ -3364,7 +3366,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
// TODO: what about when there's no protect needed?
//icon = ((enabled)? ICON_LOCKED : ICON_UNLOCKED);
icon = ICON_UNLOCKED;
- tooltip = "Editability of keyframes for this channel";
+ tooltip = TIP_("Editability of keyframes for this channel");
break;
case ACHANNEL_SETTING_MUTE: /* muted speaker */
@@ -3372,9 +3374,9 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
icon = ICON_MUTE_IPO_OFF;
if (ale->type == ALE_FCURVE)
- tooltip = "Does F-Curve contribute to result";
+ tooltip = TIP_("Does F-Curve contribute to result");
else
- tooltip = "Do channels contribute to result";
+ tooltip = TIP_("Do channels contribute to result");
break;
default:
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index cc2366affe6..dc0fba0930f 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -584,9 +584,9 @@ void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, ID *id, ListBase *modifier
/* name */
if (fmi)
- uiItemL(sub, fmi->name, ICON_NONE);
+ uiItemL(sub, IFACE_(fmi->name), ICON_NONE);
else
- uiItemL(sub, "<Unknown Modifier>", ICON_NONE);
+ uiItemL(sub, IFACE_("<Unknown Modifier>"), ICON_NONE);
/* right-align ------------------------------------------- */
sub = uiLayoutRow(row, TRUE);
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index 2bd9956ef5a..d9555108733 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -36,16 +36,25 @@ set(INC_SYS
)
set(SRC
+ armature_add.c
+ armature_edit.c
+ armature_naming.c
armature_ops.c
- editarmature.c
+ armature_relations.c
+ armature_select.c
+ armature_skinning.c
+ armature_utils.c
editarmature_generate.c
editarmature_retarget.c
editarmature_sketch.c
meshlaplacian.c
- poseSlide.c
- poseUtils.c
- poselib.c
- poseobject.c
+ pose_edit.c
+ pose_lib.c
+ pose_group.c
+ pose_select.c
+ pose_slide.c
+ pose_transform.c
+ pose_utils.c
reeb.c
BIF_generate.h
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
new file mode 100644
index 00000000000..531c0551c87
--- /dev/null
+++ b/source/blender/editors/armature/armature_add.c
@@ -0,0 +1,849 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators and API's for creating bones
+ */
+
+/** \file blender/editors/armature/armature_add.c
+ * \ingroup edarmature
+ */
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_action.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_idprop.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "armature_intern.h"
+
+/* *************** Adding stuff in editmode *************** */
+
+/* default bone add, returns it selected, but without tail set */
+/* XXX should be used everywhere, now it mallocs bones still locally in functions */
+EditBone *ED_armature_edit_bone_add(bArmature *arm, const char *name)
+{
+ EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone");
+
+ BLI_strncpy(bone->name, name, sizeof(bone->name));
+ unique_editbone_name(arm->edbo, bone->name, NULL);
+
+ BLI_addtail(arm->edbo, bone);
+
+ bone->flag |= BONE_TIPSEL;
+ bone->weight = 1.0f;
+ bone->dist = 0.25f;
+ bone->xwidth = 0.1f;
+ bone->zwidth = 0.1f;
+ bone->ease1 = 1.0f;
+ bone->ease2 = 1.0f;
+ bone->rad_head = 0.10f;
+ bone->rad_tail = 0.05f;
+ bone->segments = 1;
+ bone->layer = arm->layer;
+
+ return bone;
+}
+
+/* v3d and rv3d are allowed to be NULL */
+void add_primitive_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d)
+{
+ Object *obedit = scene->obedit; // XXX get from context
+ bArmature *arm = obedit->data;
+ float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
+ EditBone *bone;
+
+ /* Get inverse point for head and orientation for tail */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d));
+
+ if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
+ copy_m3_m4(obmat, rv3d->viewmat);
+ else unit_m3(obmat);
+
+ copy_m3_m4(viewmat, obedit->obmat);
+ mul_m3_m3m3(totmat, obmat, viewmat);
+ invert_m3_m3(imat, totmat);
+
+ ED_armature_deselect_all(obedit, 0);
+
+ /* Create a bone */
+ bone = ED_armature_edit_bone_add(arm, "Bone");
+
+ arm->act_edbone = bone;
+
+ copy_v3_v3(bone->head, curs);
+
+ if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
+ add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1
+ else
+ add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z
+}
+
+
+/* previously addvert_armature */
+/* the ctrl-click method */
+static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ View3D *v3d;
+ bArmature *arm;
+ EditBone *ebone, *newbone, *flipbone;
+ float mat[3][3], imat[3][3];
+ const float *curs;
+ int a, to_root = 0;
+ Object *obedit;
+ Scene *scene;
+
+ scene = CTX_data_scene(C);
+ v3d = CTX_wm_view3d(C);
+ obedit = CTX_data_edit_object(C);
+ arm = obedit->data;
+
+ /* find the active or selected bone */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (ebone->flag & BONE_TIPSEL || arm->act_edbone == ebone)
+ break;
+ }
+ }
+
+ if (ebone == NULL) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (ebone->flag & BONE_ROOTSEL || arm->act_edbone == ebone)
+ break;
+ }
+ }
+ if (ebone == NULL)
+ return OPERATOR_CANCELLED;
+
+ to_root = 1;
+ }
+
+ ED_armature_deselect_all(obedit, 0);
+
+ /* we re-use code for mirror editing... */
+ flipbone = NULL;
+ if (arm->flag & ARM_MIRROR_EDIT)
+ flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone);
+
+ for (a = 0; a < 2; a++) {
+ if (a == 1) {
+ if (flipbone == NULL)
+ break;
+ else {
+ SWAP(EditBone *, flipbone, ebone);
+ }
+ }
+
+ newbone = ED_armature_edit_bone_add(arm, ebone->name);
+ arm->act_edbone = newbone;
+
+ if (to_root) {
+ copy_v3_v3(newbone->head, ebone->head);
+ newbone->rad_head = ebone->rad_tail;
+ newbone->parent = ebone->parent;
+ }
+ else {
+ copy_v3_v3(newbone->head, ebone->tail);
+ newbone->rad_head = ebone->rad_tail;
+ newbone->parent = ebone;
+ newbone->flag |= BONE_CONNECTED;
+ }
+
+ curs = give_cursor(scene, v3d);
+ copy_v3_v3(newbone->tail, curs);
+ sub_v3_v3v3(newbone->tail, newbone->tail, obedit->obmat[3]);
+
+ if (a == 1)
+ newbone->tail[0] = -newbone->tail[0];
+
+ copy_m3_m4(mat, obedit->obmat);
+ invert_m3_m3(imat, mat);
+ mul_m3_v3(imat, newbone->tail);
+
+ newbone->length = len_v3v3(newbone->head, newbone->tail);
+ newbone->rad_tail = newbone->length * 0.05f;
+ newbone->dist = newbone->length * 0.25f;
+
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+static int armature_click_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ /* TODO most of this code is copied from set3dcursor_invoke,
+ * it would be better to reuse code in set3dcursor_invoke */
+
+ /* temporarily change 3d cursor position */
+ Scene *scene;
+ ARegion *ar;
+ View3D *v3d;
+ float *fp, tvec[3], oldcurs[3], mval_f[2];
+ int retv;
+
+ scene = CTX_data_scene(C);
+ ar = CTX_wm_region(C);
+ v3d = CTX_wm_view3d(C);
+
+ fp = give_cursor(scene, v3d);
+
+ copy_v3_v3(oldcurs, fp);
+
+ VECCOPY2D(mval_f, event->mval);
+ ED_view3d_win_to_3d(ar, fp, mval_f, tvec);
+ copy_v3_v3(fp, tvec);
+
+ /* extrude to the where new cursor is and store the operation result */
+ retv = armature_click_extrude_exec(C, op);
+
+ /* restore previous 3d cursor position */
+ copy_v3_v3(fp, oldcurs);
+
+ return retv;
+}
+
+void ARMATURE_OT_click_extrude(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Click-Extrude";
+ ot->idname = "ARMATURE_OT_click_extrude";
+ ot->description = "Create a new bone going from the last selected joint to the mouse position";
+
+ /* api callbacks */
+ ot->invoke = armature_click_extrude_invoke;
+ ot->exec = armature_click_extrude_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+}
+
+/* adds an EditBone between the nominated locations (should be in the right space) */
+EditBone *add_points_bone(Object *obedit, float head[3], float tail[3])
+{
+ EditBone *ebo;
+
+ ebo = ED_armature_edit_bone_add(obedit->data, "Bone");
+
+ copy_v3_v3(ebo->head, head);
+ copy_v3_v3(ebo->tail, tail);
+
+ return ebo;
+}
+
+
+static EditBone *get_named_editbone(ListBase *edbo, char *name)
+{
+ EditBone *eBone;
+
+ if (name) {
+ for (eBone = edbo->first; eBone; eBone = eBone->next) {
+ if (!strcmp(name, eBone->name))
+ return eBone;
+ }
+ }
+
+ return NULL;
+}
+
+/* Call this before doing any duplications
+ * */
+void preEditBoneDuplicate(ListBase *editbones)
+{
+ EditBone *eBone;
+
+ /* clear temp */
+ for (eBone = editbones->first; eBone; eBone = eBone->next) {
+ eBone->temp = NULL;
+ }
+}
+
+/*
+ * Note: When duplicating cross objects, editbones here is the list of bones
+ * from the SOURCE object but ob is the DESTINATION object
+ * */
+void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Object *src_ob, Object *dst_ob)
+{
+ /* If an edit bone has been duplicated, lets
+ * update it's constraints if the subtarget
+ * they point to has also been duplicated
+ */
+ EditBone *oldtarget, *newtarget;
+ bPoseChannel *pchan;
+ bConstraint *curcon;
+ ListBase *conlist;
+
+ if ( (pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name)) ) {
+ if ( (conlist = &pchan->constraints) ) {
+ for (curcon = conlist->first; curcon; curcon = curcon->next) {
+ /* does this constraint have a subtarget in
+ * this armature?
+ */
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(curcon, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if ((ct->tar == src_ob) && (ct->subtarget[0])) {
+ ct->tar = dst_ob; /* update target */
+ oldtarget = get_named_editbone(editbones, ct->subtarget);
+ if (oldtarget) {
+ /* was the subtarget bone duplicated too? If
+ * so, update the constraint to point at the
+ * duplicate of the old subtarget.
+ */
+ if (oldtarget->temp) {
+ newtarget = (EditBone *) oldtarget->temp;
+ BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(curcon, &targets, 0);
+ }
+ }
+ }
+ }
+}
+
+void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob)
+{
+ updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob);
+}
+
+
+EditBone *duplicateEditBoneObjects(EditBone *curBone, const char *name, ListBase *editbones,
+ Object *src_ob, Object *dst_ob)
+{
+ EditBone *eBone = MEM_mallocN(sizeof(EditBone), "addup_editbone");
+
+ /* Copy data from old bone to new bone */
+ memcpy(eBone, curBone, sizeof(EditBone));
+
+ curBone->temp = eBone;
+ eBone->temp = curBone;
+
+ if (name != NULL) {
+ BLI_strncpy(eBone->name, name, sizeof(eBone->name));
+ }
+
+ unique_editbone_name(editbones, eBone->name, NULL);
+ BLI_addtail(editbones, eBone);
+
+ /* copy the ID property */
+ if (curBone->prop)
+ eBone->prop = IDP_CopyProperty(curBone->prop);
+
+ /* Lets duplicate the list of constraints that the
+ * current bone has.
+ */
+ if (src_ob->pose) {
+ bPoseChannel *chanold, *channew;
+
+ chanold = BKE_pose_channel_verify(src_ob->pose, curBone->name);
+ if (chanold) {
+ /* WARNING: this creates a new posechannel, but there will not be an attached bone
+ * yet as the new bones created here are still 'EditBones' not 'Bones'.
+ */
+ channew = BKE_pose_channel_verify(dst_ob->pose, eBone->name);
+
+ if (channew) {
+ BKE_pose_channel_copy_data(channew, chanold);
+ }
+ }
+ }
+
+ return eBone;
+}
+
+EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editbones, Object *ob)
+{
+ return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
+}
+
+/* previously adduplicate_armature */
+static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bArmature *arm;
+ EditBone *eBone = NULL;
+ EditBone *curBone;
+ EditBone *firstDup = NULL; /* The beginning of the duplicated bones in the edbo list */
+
+ Object *obedit = CTX_data_edit_object(C);
+ arm = obedit->data;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ ED_armature_sync_selection(arm->edbo); // XXX why is this needed?
+
+ preEditBoneDuplicate(arm->edbo);
+
+ /* Select mirrored bones */
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (EBONE_VISIBLE(arm, curBone)) {
+ if (curBone->flag & BONE_SELECTED) {
+ eBone = ED_armature_bone_get_mirrored(arm->edbo, curBone);
+ if (eBone)
+ eBone->flag |= BONE_SELECTED;
+ }
+ }
+ }
+ }
+
+
+ /* Find the selected bones and duplicate them as needed */
+ for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
+ if (EBONE_VISIBLE(arm, curBone)) {
+ if (curBone->flag & BONE_SELECTED) {
+
+ eBone = duplicateEditBone(curBone, curBone->name, arm->edbo, obedit);
+
+ if (!firstDup)
+ firstDup = eBone;
+
+ }
+ }
+ }
+
+ /* Run though the list and fix the pointers */
+ for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
+ if (EBONE_VISIBLE(arm, curBone)) {
+ if (curBone->flag & BONE_SELECTED) {
+ eBone = (EditBone *) curBone->temp;
+
+ if (!curBone->parent) {
+ /* If this bone has no parent,
+ * Set the duplicate->parent to NULL
+ */
+ eBone->parent = NULL;
+ }
+ else if (curBone->parent->temp) {
+ /* If this bone has a parent that was duplicated,
+ * Set the duplicate->parent to the curBone->parent->temp
+ */
+ eBone->parent = (EditBone *)curBone->parent->temp;
+ }
+ else {
+ /* If this bone has a parent that IS not selected,
+ * Set the duplicate->parent to the curBone->parent
+ */
+ eBone->parent = (EditBone *) curBone->parent;
+ eBone->flag &= ~BONE_CONNECTED;
+ }
+
+ /* Lets try to fix any constraint subtargets that might
+ * have been duplicated
+ */
+ updateDuplicateSubtarget(eBone, arm->edbo, obedit);
+ }
+ }
+ }
+
+ /* correct the active bone */
+ if (arm->act_edbone) {
+ eBone = arm->act_edbone;
+ if (eBone->temp)
+ arm->act_edbone = eBone->temp;
+ }
+
+ /* Deselect the old bones and select the new ones */
+ for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
+ if (EBONE_VISIBLE(arm, curBone))
+ curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+
+ ED_armature_validate_active(arm);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void ARMATURE_OT_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Duplicate Selected Bone(s)";
+ ot->idname = "ARMATURE_OT_duplicate";
+ ot->description = "Make copies of the selected bones within the same armature";
+
+ /* api callbacks */
+ ot->exec = armature_duplicate_selected_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ------------------------------------------ */
+
+/* previously extrude_armature */
+/* context; editmode armature */
+/* if forked && mirror-edit: makes two bones with flipped names */
+static int armature_extrude_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ bArmature *arm;
+ EditBone *newbone, *ebone, *flipbone, *first = NULL;
+ int a, totbone = 0, do_extrude;
+ int forked = RNA_boolean_get(op->ptr, "forked");
+
+ obedit = CTX_data_edit_object(C);
+ arm = obedit->data;
+
+ /* since we allow root extrude too, we have to make sure selection is OK */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (ebone->flag & BONE_ROOTSEL) {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ if (ebone->parent->flag & BONE_TIPSEL)
+ ebone->flag &= ~BONE_ROOTSEL;
+ }
+ }
+ }
+ }
+
+ /* Duplicate the necessary bones */
+ for (ebone = arm->edbo->first; ((ebone) && (ebone != first)); ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ /* we extrude per definition the tip */
+ do_extrude = FALSE;
+ if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED)) {
+ do_extrude = TRUE;
+ }
+ else if (ebone->flag & BONE_ROOTSEL) {
+ /* but, a bone with parent deselected we do the root... */
+ if (ebone->parent && (ebone->parent->flag & BONE_TIPSEL)) {
+ /* pass */
+ }
+ else {
+ do_extrude = 2;
+ }
+ }
+
+ if (do_extrude) {
+ /* we re-use code for mirror editing... */
+ flipbone = NULL;
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone);
+ if (flipbone) {
+ forked = 0; // we extrude 2 different bones
+ if (flipbone->flag & (BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED))
+ /* don't want this bone to be selected... */
+ flipbone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ }
+ if ((flipbone == NULL) && (forked))
+ flipbone = ebone;
+ }
+
+ for (a = 0; a < 2; a++) {
+ if (a == 1) {
+ if (flipbone == NULL)
+ break;
+ else {
+ SWAP(EditBone *, flipbone, ebone);
+ }
+ }
+
+ totbone++;
+ newbone = MEM_callocN(sizeof(EditBone), "extrudebone");
+
+ if (do_extrude == TRUE) {
+ copy_v3_v3(newbone->head, ebone->tail);
+ copy_v3_v3(newbone->tail, newbone->head);
+ newbone->parent = ebone;
+
+ newbone->flag = ebone->flag & (BONE_TIPSEL | BONE_RELATIVE_PARENTING); // copies it, in case mirrored bone
+
+ if (newbone->parent) newbone->flag |= BONE_CONNECTED;
+ }
+ else {
+ copy_v3_v3(newbone->head, ebone->head);
+ copy_v3_v3(newbone->tail, ebone->head);
+ newbone->parent = ebone->parent;
+
+ newbone->flag = BONE_TIPSEL;
+
+ if (newbone->parent && (ebone->flag & BONE_CONNECTED)) {
+ newbone->flag |= BONE_CONNECTED;
+ }
+ }
+
+ newbone->weight = ebone->weight;
+ newbone->dist = ebone->dist;
+ newbone->xwidth = ebone->xwidth;
+ newbone->zwidth = ebone->zwidth;
+ newbone->ease1 = ebone->ease1;
+ newbone->ease2 = ebone->ease2;
+ newbone->rad_head = ebone->rad_tail; // don't copy entire bone...
+ newbone->rad_tail = ebone->rad_tail;
+ newbone->segments = 1;
+ newbone->layer = ebone->layer;
+
+ BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name));
+
+ if (flipbone && forked) { // only set if mirror edit
+ if (strlen(newbone->name) < 30) {
+ if (a == 0) strcat(newbone->name, "_L");
+ else strcat(newbone->name, "_R");
+ }
+ }
+ unique_editbone_name(arm->edbo, newbone->name, NULL);
+
+ /* Add the new bone to the list */
+ BLI_addtail(arm->edbo, newbone);
+ if (!first)
+ first = newbone;
+
+ /* restore ebone if we were flipping */
+ if (a == 1 && flipbone)
+ SWAP(EditBone *, flipbone, ebone);
+ }
+ }
+
+ /* Deselect the old bone */
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ }
+ }
+ /* if only one bone, make this one active */
+ if (totbone == 1 && first) arm->act_edbone = first;
+
+ if (totbone == 0) return OPERATOR_CANCELLED;
+
+ /* Transform the endpoints */
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_extrude(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Extrude";
+ ot->idname = "ARMATURE_OT_extrude";
+ ot->description = "Create new bones from the selected joints";
+
+ /* api callbacks */
+ ot->exec = armature_extrude_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "forked", 0, "Forked", "");
+}
+
+/* ********************** Bone Add *************************************/
+
+/*op makes a new bone and returns it with its tip selected */
+
+static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
+{
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ Object *obedit = CTX_data_edit_object(C);
+ EditBone *bone;
+ float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
+ char name[MAXBONENAME];
+
+ RNA_string_get(op->ptr, "name", name);
+
+ copy_v3_v3(curs, give_cursor(CTX_data_scene(C), CTX_wm_view3d(C)));
+
+ /* Get inverse point for head and orientation for tail */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_m4_v3(obedit->imat, curs);
+
+ if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
+ copy_m3_m4(obmat, rv3d->viewmat);
+ else unit_m3(obmat);
+
+ copy_m3_m4(viewmat, obedit->obmat);
+ mul_m3_m3m3(totmat, obmat, viewmat);
+ invert_m3_m3(imat, totmat);
+
+ ED_armature_deselect_all(obedit, 0);
+
+ /* Create a bone */
+ bone = ED_armature_edit_bone_add(obedit->data, name);
+
+ copy_v3_v3(bone->head, curs);
+
+ if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
+ add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1
+ else
+ add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_bone_primitive_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Bone";
+ ot->idname = "ARMATURE_OT_bone_primitive_add";
+ ot->description = "Add a new bone located at the 3D-Cursor";
+
+ /* api callbacks */
+ ot->exec = armature_bone_primitive_add_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_string(ot->srna, "name", "Bone", MAXBONENAME, "Name", "Name of the newly created bone");
+
+}
+
+/* ********************** Subdivide *******************************/
+
+/* Subdivide Operators:
+ * This group of operators all use the same 'exec' callback, but they are called
+ * through several different operators - a combined menu (which just calls the exec in the
+ * appropriate ways), and two separate ones.
+ */
+
+static int armature_subdivide_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *newbone, *tbone;
+ int cuts, i;
+
+ /* there may not be a number_cuts property defined (for 'simple' subdivide) */
+ cuts = RNA_int_get(op->ptr, "number_cuts");
+
+ /* loop over all editable bones */
+ // XXX the old code did this in reverse order though!
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ for (i = cuts + 1; i > 1; i--) {
+ /* compute cut ratio first */
+ float cutratio = 1.0f / (float)i;
+ float cutratioI = 1.0f - cutratio;
+
+ float val1[3];
+ float val2[3];
+ float val3[3];
+
+ newbone = MEM_mallocN(sizeof(EditBone), "ebone subdiv");
+ *newbone = *ebone;
+ BLI_addtail(arm->edbo, newbone);
+
+ /* calculate location of newbone->head */
+ copy_v3_v3(val1, ebone->head);
+ copy_v3_v3(val2, ebone->tail);
+ copy_v3_v3(val3, newbone->head);
+
+ val3[0] = val1[0] * cutratio + val2[0] * cutratioI;
+ val3[1] = val1[1] * cutratio + val2[1] * cutratioI;
+ val3[2] = val1[2] * cutratio + val2[2] * cutratioI;
+
+ copy_v3_v3(newbone->head, val3);
+ copy_v3_v3(newbone->tail, ebone->tail);
+ copy_v3_v3(ebone->tail, newbone->head);
+
+ newbone->rad_head = 0.5f * (ebone->rad_head + ebone->rad_tail);
+ ebone->rad_tail = newbone->rad_head;
+
+ newbone->flag |= BONE_CONNECTED;
+
+ unique_editbone_name(arm->edbo, newbone->name, NULL);
+
+ /* correct parent bones */
+ for (tbone = arm->edbo->first; tbone; tbone = tbone->next) {
+ if (tbone->parent == ebone)
+ tbone->parent = newbone;
+ }
+ newbone->parent = ebone;
+ }
+ }
+ CTX_DATA_END;
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_subdivide(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Subdivide Multi";
+ ot->idname = "ARMATURE_OT_subdivide";
+ ot->description = "Break selected bones into chains of smaller bones";
+
+ /* api callbacks */
+ ot->exec = armature_subdivide_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Properties */
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
+ /* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
new file mode 100644
index 00000000000..12602c10955
--- /dev/null
+++ b/source/blender/editors/armature/armature_edit.c
@@ -0,0 +1,1245 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Armature EditMode tools - transforms, chain based editing, and other settings
+ */
+
+/** \file blender/editors/armature/armature_edit.c
+ * \ingroup edarmature
+ */
+
+#include <assert.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "armature_intern.h"
+
+/* ************************** Object Tools Exports ******************************* */
+/* NOTE: these functions are exported to the Object module to be called from the tools there */
+
+void ED_armature_apply_transform(Object *ob, float mat[4][4])
+{
+ EditBone *ebone;
+ bArmature *arm = ob->data;
+ float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */
+ float mat3[3][3];
+
+ copy_m3_m4(mat3, mat);
+ normalize_m3(mat3);
+
+ /* Put the armature into editmode */
+ ED_armature_to_edit(ob);
+
+ /* Do the rotations */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ float delta[3], tmat[3][3];
+
+ /* find the current bone's roll matrix */
+ sub_v3_v3v3(delta, ebone->tail, ebone->head);
+ vec_roll_to_mat3(delta, ebone->roll, tmat);
+
+ /* transform the roll matrix */
+ mul_m3_m3m3(tmat, mat3, tmat);
+
+ /* transform the bone */
+ mul_m4_v3(mat, ebone->head);
+ mul_m4_v3(mat, ebone->tail);
+
+ /* apply the transfiormed roll back */
+ mat3_to_vec_roll(tmat, NULL, &ebone->roll);
+
+ ebone->rad_head *= scale;
+ ebone->rad_tail *= scale;
+ ebone->dist *= scale;
+
+ /* we could be smarter and scale by the matrix along the x & z axis */
+ ebone->xwidth *= scale;
+ ebone->zwidth *= scale;
+ }
+
+ /* Turn the list into an armature */
+ ED_armature_from_edit(ob);
+ ED_armature_edit_free(ob);
+}
+
+/* exported for use in editors/object/ */
+/* 0 == do center, 1 == center new, 2 == center cursor */
+void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int centermode, int around)
+{
+ Object *obedit = scene->obedit; // XXX get from context
+ EditBone *ebone;
+ bArmature *arm = ob->data;
+ float cent[3];
+
+ /* Put the armature into editmode */
+ if (ob != obedit) {
+ ED_armature_to_edit(ob);
+ obedit = NULL; /* we cant use this so behave as if there is no obedit */
+ }
+
+ /* Find the centerpoint */
+ if (centermode == 2) {
+ copy_v3_v3(cent, cursor);
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_v3(ob->imat, cent);
+ }
+ else {
+ if (around == V3D_CENTROID) {
+ int total = 0;
+ zero_v3(cent);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ total += 2;
+ add_v3_v3(cent, ebone->head);
+ add_v3_v3(cent, ebone->tail);
+ }
+ if (total) {
+ mul_v3_fl(cent, 1.0f / (float)total);
+ }
+ }
+ else {
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ minmax_v3v3_v3(min, max, ebone->head);
+ minmax_v3v3_v3(min, max, ebone->tail);
+ }
+ mid_v3_v3v3(cent, min, max);
+ }
+ }
+
+ /* Do the adjustments */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ sub_v3_v3(ebone->head, cent);
+ sub_v3_v3(ebone->tail, cent);
+ }
+
+ /* Turn the list into an armature */
+ if (obedit == NULL) {
+ ED_armature_from_edit(ob);
+ ED_armature_edit_free(ob);
+ }
+
+ /* Adjust object location for new centerpoint */
+ if (centermode && obedit == NULL) {
+ mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */
+ add_v3_v3(ob->loc, cent);
+ }
+}
+
+/* ********************************* Roll ******************************* */
+
+/* adjust bone roll to align Z axis with vector
+ * vec is in local space and is normalized
+ */
+float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const short axis_only)
+{
+ float mat[3][3], nor[3];
+
+ sub_v3_v3v3(nor, bone->tail, bone->head);
+ vec_roll_to_mat3(nor, 0.0f, mat);
+
+ /* check the bone isn't aligned with the axis */
+ if (!is_zero_v3(align_axis) && angle_v3v3(align_axis, mat[2]) > FLT_EPSILON) {
+ float vec[3], align_axis_proj[3], roll;
+
+ /* project the new_up_axis along the normal */
+ project_v3_v3v3(vec, align_axis, nor);
+ sub_v3_v3v3(align_axis_proj, align_axis, vec);
+
+ if (axis_only) {
+ if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI / 2.0)) {
+ negate_v3(align_axis_proj);
+ }
+ }
+
+ roll = angle_v3v3(align_axis_proj, mat[2]);
+
+ cross_v3_v3v3(vec, mat[2], align_axis_proj);
+
+ if (dot_v3v3(vec, nor) < 0) {
+ roll = -roll;
+ }
+
+ return roll;
+ }
+
+ return 0.0f;
+}
+
+
+typedef enum eCalcRollTypes {
+ CALC_ROLL_X = 0,
+ CALC_ROLL_Y = 1,
+ CALC_ROLL_Z = 2,
+
+ CALC_ROLL_ACTIVE = 5,
+ CALC_ROLL_VIEW = 6,
+ CALC_ROLL_CURSOR = 7
+} eCalcRollTypes;
+
+static EnumPropertyItem prop_calc_roll_types[] = {
+ {CALC_ROLL_X, "X", 0, "X Axis", ""},
+ {CALC_ROLL_Y, "Y", 0, "Y Axis", ""},
+ {CALC_ROLL_Z, "Z", 0, "Z Axis", ""},
+ {CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""},
+ {CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""},
+ {CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+
+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");
+ const short axis_only = RNA_boolean_get(op->ptr, "axis_only");
+ const short axis_flip = RNA_boolean_get(op->ptr, "axis_flip");
+
+ float imat[3][3];
+
+ bArmature *arm = ob->data;
+ EditBone *ebone;
+
+ copy_m3_m4(imat, ob->obmat);
+ invert_m3(imat);
+
+ if (type == CALC_ROLL_CURSOR) { /* Cursor */
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C); /* can be NULL */
+ float cursor_local[3];
+ const float *cursor = give_cursor(scene, v3d);
+
+
+ copy_v3_v3(cursor_local, cursor);
+ mul_m3_v3(imat, cursor_local);
+
+ /* cursor */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
+ float cursor_rel[3];
+ sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
+ if (axis_flip) negate_v3(cursor_rel);
+ ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only);
+ }
+ }
+ }
+ else {
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+ if (type == CALC_ROLL_VIEW) { /* View */
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No region view3d available");
+ return OPERATOR_CANCELLED;
+ }
+
+ copy_v3_v3(vec, rv3d->viewinv[2]);
+ mul_m3_v3(imat, vec);
+ }
+ else if (type == CALC_ROLL_ACTIVE) {
+ float mat[3][3], nor[3];
+ ebone = (EditBone *)arm->act_edbone;
+ if (ebone == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active bone set");
+ return OPERATOR_CANCELLED;
+ }
+
+ sub_v3_v3v3(nor, ebone->tail, ebone->head);
+ vec_roll_to_mat3(nor, ebone->roll, mat);
+ copy_v3_v3(vec, mat[2]);
+ }
+ else { /* Axis */
+ assert(type >= 0 && type <= 5);
+ if (type < 3) vec[type] = 1.0f;
+ else vec[type - 2] = -1.0f;
+ mul_m3_v3(imat, vec);
+ }
+
+ if (axis_flip) negate_v3(vec);
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
+ /* roll func is a callback which assumes that all is well */
+ ebone->roll = ED_rollBoneToVector(ebone, vec, axis_only);
+ }
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
+ EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, ebone);
+ if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
+ ebone->roll = -ebone_mirr->roll;
+ }
+ }
+ }
+ }
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Recalculate Roll";
+ ot->idname = "ARMATURE_OT_calculate_roll";
+ ot->description = "Automatically fix alignment of select bones' axes";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_calc_roll_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, 0, "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");
+}
+
+/* ******************************** Chain-Based Tools ********************************* */
+
+/* temporary data-structure for merge/fill bones */
+typedef struct EditBonePoint {
+ struct EditBonePoint *next, *prev;
+
+ EditBone *head_owner; /* EditBone which uses this point as a 'head' point */
+ EditBone *tail_owner; /* EditBone which uses this point as a 'tail' point */
+
+ float vec[3]; /* the actual location of the point in local/EditMode space */
+} EditBonePoint;
+
+/* find chain-tips (i.e. bones without children) */
+static void chains_find_tips(ListBase *edbo, ListBase *list)
+{
+ EditBone *curBone, *ebo;
+ LinkData *ld;
+
+ /* note: this is potentially very slow ... there's got to be a better way */
+ for (curBone = edbo->first; curBone; curBone = curBone->next) {
+ short stop = 0;
+
+ /* is this bone contained within any existing chain? (skip if so) */
+ for (ld = list->first; ld; ld = ld->next) {
+ for (ebo = ld->data; ebo; ebo = ebo->parent) {
+ if (ebo == curBone) {
+ stop = 1;
+ break;
+ }
+ }
+
+ if (stop) break;
+ }
+ /* skip current bone if it is part of an existing chain */
+ if (stop) continue;
+
+ /* is any existing chain part of the chain formed by this bone? */
+ stop = 0;
+ for (ebo = curBone->parent; ebo; ebo = ebo->parent) {
+ for (ld = list->first; ld; ld = ld->next) {
+ if (ld->data == ebo) {
+ ld->data = curBone;
+ stop = 1;
+ break;
+ }
+ }
+
+ if (stop) break;
+ }
+ /* current bone has already been added to a chain? */
+ if (stop) continue;
+
+ /* add current bone to a new chain */
+ ld = MEM_callocN(sizeof(LinkData), "BoneChain");
+ ld->data = curBone;
+ BLI_addtail(list, ld);
+ }
+}
+
+/* --------------------- */
+
+static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points)
+{
+ EditBonePoint *ebp;
+ float vec[3];
+ short found = 0;
+
+ if (eb_tail) {
+ copy_v3_v3(vec, ebo->tail);
+ }
+ else {
+ copy_v3_v3(vec, ebo->head);
+ }
+
+ for (ebp = points->first; ebp; ebp = ebp->next) {
+ if (equals_v3v3(ebp->vec, vec)) {
+ if (eb_tail) {
+ if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) {
+ /* so this bone's tail owner is this bone */
+ ebp->tail_owner = ebo;
+ found = 1;
+ break;
+ }
+ }
+ else {
+ if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) {
+ /* so this bone's head owner is this bone */
+ ebp->head_owner = ebo;
+ found = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ /* allocate a new point if no existing point was related */
+ if (found == 0) {
+ ebp = MEM_callocN(sizeof(EditBonePoint), "EditBonePoint");
+
+ if (eb_tail) {
+ copy_v3_v3(ebp->vec, ebo->tail);
+ ebp->tail_owner = ebo;
+ }
+ else {
+ copy_v3_v3(ebp->vec, ebo->head);
+ ebp->head_owner = ebo;
+ }
+
+ BLI_addtail(points, ebp);
+ }
+}
+
+/* bone adding between selected joints */
+static int armature_fill_bones_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = (obedit) ? obedit->data : NULL;
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ ListBase points = {NULL, NULL};
+ int count;
+
+ /* sanity checks */
+ if (ELEM(NULL, obedit, arm))
+ return OPERATOR_CANCELLED;
+
+ /* loop over all bones, and only consider if visible */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
+ {
+ if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL))
+ fill_add_joint(ebone, 0, &points);
+ if (ebone->flag & BONE_TIPSEL)
+ fill_add_joint(ebone, 1, &points);
+ }
+ CTX_DATA_END;
+
+ /* the number of joints determines how we fill:
+ * 1) between joint and cursor (joint=head, cursor=tail)
+ * 2) between the two joints (order is dependent on active-bone/hierachy)
+ * 3+) error (a smarter method involving finding chains needs to be worked out
+ */
+ count = BLI_countlist(&points);
+
+ if (count == 0) {
+ BKE_report(op->reports, RPT_ERROR, "No joints selected");
+ return OPERATOR_CANCELLED;
+ }
+ else if (count == 1) {
+ EditBonePoint *ebp;
+ float curs[3];
+
+ /* Get Points - selected joint */
+ ebp = (EditBonePoint *)points.first;
+
+ /* Get points - cursor (tail) */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d));
+
+ /* Create a bone */
+ /* newbone = */ add_points_bone(obedit, ebp->vec, curs);
+ }
+ else if (count == 2) {
+ EditBonePoint *ebp, *ebp2;
+ float head[3], tail[3];
+ short headtail = 0;
+
+ /* check that the points don't belong to the same bone */
+ ebp = (EditBonePoint *)points.first;
+ ebp2 = ebp->next;
+
+ if ((ebp->head_owner == ebp2->tail_owner) && (ebp->head_owner != NULL)) {
+ BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+ if ((ebp->tail_owner == ebp2->head_owner) && (ebp->tail_owner != NULL)) {
+ BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* find which one should be the 'head' */
+ if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) {
+ /* rule: whichever one is closer to 3d-cursor */
+ float curs[3];
+ float vecA[3], vecB[3];
+ float distA, distB;
+
+ /* get cursor location */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d));
+
+ /* get distances */
+ sub_v3_v3v3(vecA, ebp->vec, curs);
+ sub_v3_v3v3(vecB, ebp2->vec, curs);
+ distA = len_v3(vecA);
+ distB = len_v3(vecB);
+
+ /* compare distances - closer one therefore acts as direction for bone to go */
+ headtail = (distA < distB) ? 2 : 1;
+ }
+ else if (ebp->head_owner) {
+ headtail = 1;
+ }
+ else if (ebp2->head_owner) {
+ headtail = 2;
+ }
+
+ /* assign head/tail combinations */
+ if (headtail == 2) {
+ copy_v3_v3(head, ebp->vec);
+ copy_v3_v3(tail, ebp2->vec);
+ }
+ else if (headtail == 1) {
+ copy_v3_v3(head, ebp2->vec);
+ copy_v3_v3(tail, ebp->vec);
+ }
+
+ /* add new bone and parent it to the appropriate end */
+ if (headtail) {
+ EditBone *newbone = add_points_bone(obedit, head, tail);
+
+ /* do parenting (will need to set connected flag too) */
+ if (headtail == 2) {
+ /* ebp tail or head - tail gets priority */
+ if (ebp->tail_owner)
+ newbone->parent = ebp->tail_owner;
+ else
+ newbone->parent = ebp->head_owner;
+ }
+ else {
+ /* ebp2 tail or head - tail gets priority */
+ if (ebp2->tail_owner)
+ newbone->parent = ebp2->tail_owner;
+ else
+ newbone->parent = ebp2->head_owner;
+ }
+
+ newbone->flag |= BONE_CONNECTED;
+ }
+ }
+ else {
+ /* FIXME.. figure out a method for multiple bones */
+ BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count);
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+
+ /* free points */
+ BLI_freelistN(&points);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_fill(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Fill Between Joints";
+ ot->idname = "ARMATURE_OT_fill";
+ ot->description = "Add bone between selected joint(s) and/or 3D-Cursor";
+
+ /* callbacks */
+ ot->exec = armature_fill_bones_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* --------------------- */
+
+/* this function merges between two bones, removes them and those in-between,
+ * and adjusts the parent relationships for those in-between
+ */
+static void bones_merge(Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains)
+{
+ bArmature *arm = obedit->data;
+ EditBone *ebo, *ebone, *newbone;
+ LinkData *chain;
+ float head[3], tail[3];
+
+ /* check if same bone */
+ if (start == end) {
+ if (G.debug & G_DEBUG) {
+ printf("Error: same bone!\n");
+ printf("\tstart = %s, end = %s\n", start->name, end->name);
+ }
+ }
+
+ /* step 1: add a new bone
+ * - head = head/tail of start (default head)
+ * - tail = head/tail of end (default tail)
+ * - parent = parent of start
+ */
+ if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) {
+ copy_v3_v3(head, start->tail);
+ }
+ else {
+ copy_v3_v3(head, start->head);
+ }
+ if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) {
+ copy_v3_v3(tail, end->head);
+ }
+ else {
+ copy_v3_v3(tail, end->tail);
+ }
+ newbone = add_points_bone(obedit, head, tail);
+ newbone->parent = start->parent;
+
+ /* TODO, copy more things to the new bone */
+ newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE |
+ BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE);
+
+ /* step 2a: reparent any side chains which may be parented to any bone in the chain of bones to merge
+ * - potentially several tips for side chains leading to some tree exist...
+ */
+ for (chain = chains->first; chain; chain = chain->next) {
+ /* traverse down chain until we hit the bottom or if we run into the tip of the chain of bones we're
+ * merging (need to stop in this case to avoid corrupting this chain too!)
+ */
+ for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) {
+ short found = 0;
+
+ /* check if this bone is parented to one in the merging chain
+ * ! WATCHIT: must only go check until end of checking chain
+ */
+ for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) {
+ /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */
+ if (ebone->parent == ebo) {
+ ebone->parent = newbone;
+ found = 1;
+ break;
+ }
+ }
+
+ /* carry on to the next tip now */
+ if (found)
+ break;
+ }
+ }
+
+ /* step 2b: parent child of end to newbone (child from this chain) */
+ if (endchild)
+ endchild->parent = newbone;
+
+ /* step 3: delete all bones between and including start and end */
+ for (ebo = end; ebo; ebo = ebone) {
+ ebone = (ebo == start) ? (NULL) : (ebo->parent);
+ bone_free(arm, ebo);
+ }
+
+ newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
+ ED_armature_sync_selection(arm->edbo);
+}
+
+
+static int armature_merge_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = (obedit) ? obedit->data : NULL;
+ short type = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, obedit, arm))
+ return OPERATOR_CANCELLED;
+
+ /* for now, there's only really one type of merging that's performed... */
+ if (type == 1) {
+ /* go down chains, merging bones */
+ ListBase chains = {NULL, NULL};
+ LinkData *chain, *nchain;
+ EditBone *ebo;
+
+ armature_tag_select_mirrored(arm);
+
+ /* get chains (ends on chains) */
+ chains_find_tips(arm->edbo, &chains);
+ if (chains.first == NULL) return OPERATOR_CANCELLED;
+
+ /* each 'chain' is the last bone in the chain (with no children) */
+ for (chain = chains.first; chain; chain = nchain) {
+ EditBone *bstart = NULL, *bend = NULL;
+ EditBone *bchild = NULL, *child = NULL;
+
+ /* temporarily remove chain from list of chains */
+ nchain = chain->next;
+ BLI_remlink(&chains, chain);
+
+ /* only consider bones that are visible and selected */
+ for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
+ /* check if visible + selected */
+ if (EBONE_VISIBLE(arm, ebo) &&
+ ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
+ (ebo->flag & BONE_SELECTED) )
+ {
+ /* set either end or start (end gets priority, unless it is already set) */
+ if (bend == NULL) {
+ bend = ebo;
+ bchild = child;
+ }
+ else
+ bstart = ebo;
+ }
+ else {
+ /* chain is broken... merge any continous segments then clear */
+ if (bstart && bend)
+ bones_merge(obedit, bstart, bend, bchild, &chains);
+
+ bstart = NULL;
+ bend = NULL;
+ bchild = NULL;
+ }
+ }
+
+ /* merge from bstart to bend if something not merged */
+ if (bstart && bend)
+ bones_merge(obedit, bstart, bend, bchild, &chains);
+
+ /* put back link */
+ BLI_insertlinkbefore(&chains, nchain, chain);
+ }
+
+ armature_tag_unselect(arm);
+
+ BLI_freelistN(&chains);
+ }
+
+ /* updates */
+ ED_armature_sync_selection(arm->edbo);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_merge(wmOperatorType *ot)
+{
+ static EnumPropertyItem merge_types[] = {
+ {1, "WITHIN_CHAIN", 0, "Within Chains", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Merge Bones";
+ ot->idname = "ARMATURE_OT_merge";
+ ot->description = "Merge continuous chains of selected bones";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_merge_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", merge_types, 0, "Type", "");
+}
+
+/* --------------------- */
+
+/* Switch Direction operator:
+ * Currently, this does not use context loops, as context loops do not make it
+ * easy to retrieve any hierarchical/chain relationships which are necessary for
+ * this to be done easily.
+ */
+
+/* helper to clear BONE_TRANSFORM flags */
+static void armature_clear_swap_done_flags(bArmature *arm)
+{
+ EditBone *ebone;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->flag &= ~BONE_TRANSFORM;
+ }
+}
+
+static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = (bArmature *)ob->data;
+ ListBase chains = {NULL, NULL};
+ LinkData *chain;
+
+ /* get chains of bones (ends on chains) */
+ chains_find_tips(arm->edbo, &chains);
+ if (chains.first == NULL) return OPERATOR_CANCELLED;
+
+ /* ensure that mirror bones will also be operated on */
+ armature_tag_select_mirrored(arm);
+
+ /* clear BONE_TRANSFORM flags
+ * - used to prevent duplicate/cancelling operations from occurring [#34123]
+ * - BONE_DONE cannot be used here as that's already used for mirroring
+ */
+ armature_clear_swap_done_flags(arm);
+
+ /* loop over chains, only considering selected and visible bones */
+ for (chain = chains.first; chain; chain = chain->next) {
+ EditBone *ebo, *child = NULL, *parent = NULL;
+
+ /* loop over bones in chain */
+ for (ebo = chain->data; ebo; ebo = parent) {
+ /* parent is this bone's original parent
+ * - we store this, as the next bone that is checked is this one
+ * but the value of ebo->parent may change here...
+ */
+ parent = ebo->parent;
+
+ /* skip bone if already handled... [#34123] */
+ if ((ebo->flag & BONE_TRANSFORM) == 0) {
+ /* only if selected and editable */
+ if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
+ /* swap head and tail coordinates */
+ SWAP(float, ebo->head[0], ebo->tail[0]);
+ SWAP(float, ebo->head[1], ebo->tail[1]);
+ SWAP(float, ebo->head[2], ebo->tail[2]);
+
+ /* do parent swapping:
+ * - use 'child' as new parent
+ * - connected flag is only set if points are coincidental
+ */
+ ebo->parent = child;
+ if ((child) && equals_v3v3(ebo->head, child->tail))
+ ebo->flag |= BONE_CONNECTED;
+ else
+ ebo->flag &= ~BONE_CONNECTED;
+
+ /* get next bones
+ * - child will become the new parent of next bone
+ */
+ child = ebo;
+ }
+ else {
+ /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it
+ * as it will be facing in opposite direction
+ */
+ if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
+ ebo->parent = NULL;
+ ebo->flag &= ~BONE_CONNECTED;
+ }
+
+ /* get next bones
+ * - child will become new parent of next bone (not swapping occurred,
+ * so set to NULL to prevent infinite-loop)
+ */
+ child = NULL;
+ }
+
+ /* tag as done (to prevent double-swaps) */
+ ebo->flag |= BONE_TRANSFORM;
+ }
+ }
+ }
+
+ /* free chains */
+ BLI_freelistN(&chains);
+
+ /* clear temp flags */
+ armature_clear_swap_done_flags(arm);
+ armature_tag_unselect(arm);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_switch_direction(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Switch Direction";
+ ot->idname = "ARMATURE_OT_switch_direction";
+ ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)";
+
+ /* api callbacks */
+ ot->exec = armature_switch_direction_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************* Align ******************************* */
+
+/* helper to fix a ebone position if its parent has moved due to alignment*/
+static void fix_connected_bone(EditBone *ebone)
+{
+ float diff[3];
+
+ if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || equals_v3v3(ebone->parent->tail, ebone->head))
+ return;
+
+ /* if the parent has moved we translate child's head and tail accordingly */
+ sub_v3_v3v3(diff, ebone->parent->tail, ebone->head);
+ add_v3_v3(ebone->head, diff);
+ add_v3_v3(ebone->tail, diff);
+}
+
+/* helper to recursively find chains of connected bones starting at ebone and fix their position */
+static void fix_editbone_connected_children(ListBase *edbo, EditBone *ebone)
+{
+ EditBone *selbone;
+
+ for (selbone = edbo->first; selbone; selbone = selbone->next) {
+ if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
+ fix_connected_bone(selbone);
+ fix_editbone_connected_children(edbo, selbone);
+ }
+ }
+}
+
+static void bone_align_to_bone(ListBase *edbo, EditBone *selbone, EditBone *actbone)
+{
+ float selboneaxis[3], actboneaxis[3], length;
+
+ sub_v3_v3v3(actboneaxis, actbone->tail, actbone->head);
+ normalize_v3(actboneaxis);
+
+ sub_v3_v3v3(selboneaxis, selbone->tail, selbone->head);
+ length = len_v3(selboneaxis);
+
+ mul_v3_fl(actboneaxis, length);
+ add_v3_v3v3(selbone->tail, selbone->head, actboneaxis);
+ selbone->roll = actbone->roll;
+
+ /* if the bone being aligned has connected descendants they must be moved
+ * according to their parent new position, otherwise they would be left
+ * in an inconsistent state: connected but away from the parent*/
+ fix_editbone_connected_children(edbo, selbone);
+}
+
+static int armature_align_bones_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = (bArmature *)ob->data;
+ EditBone *actbone = CTX_data_active_bone(C);
+ EditBone *actmirb = NULL;
+
+ /* there must be an active bone */
+ if (actbone == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
+ return OPERATOR_CANCELLED;
+ }
+ else if (arm->flag & ARM_MIRROR_EDIT) {
+ /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
+ * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
+ * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
+ * This is useful for arm-chains, for example parenting lower arm to upper arm
+ * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
+ * then just use actbone. Useful when doing upper arm to spine.
+ */
+ actmirb = ED_armature_bone_get_mirrored(arm->edbo, actbone);
+ if (actmirb == NULL)
+ actmirb = actbone;
+ }
+
+ /* if there is only 1 selected bone, we assume that that is the active bone,
+ * since a user will need to have clicked on a bone (thus selecting it) to make it active
+ */
+ if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) {
+ /* When only the active bone is selected, and it has a parent,
+ * align it to the parent, as that is the only possible outcome.
+ */
+ if (actbone->parent) {
+ bone_align_to_bone(arm->edbo, actbone, actbone->parent);
+
+ if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
+ bone_align_to_bone(arm->edbo, actmirb, actmirb->parent);
+ }
+ }
+ else {
+ /* Align 'selected' bones to the active one
+ * - the context iterator contains both selected bones and their mirrored copies,
+ * so we assume that unselected bones are mirrored copies of some selected bone
+ * - since the active one (and/or its mirror) will also be selected, we also need
+ * to check that we are not trying to operate on them, since such an operation
+ * would cause errors
+ */
+
+ /* align selected bones to the active one */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ if (ELEM(ebone, actbone, actmirb) == 0) {
+ if (ebone->flag & BONE_SELECTED)
+ bone_align_to_bone(arm->edbo, ebone, actbone);
+ else
+ bone_align_to_bone(arm->edbo, ebone, actmirb);
+ }
+ }
+ CTX_DATA_END;
+ }
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_align(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Align Bones";
+ ot->idname = "ARMATURE_OT_align";
+ ot->description = "Align selected bones to the active bone (or to their parent)";
+
+ /* api callbacks */
+ ot->invoke = WM_operator_confirm;
+ ot->exec = armature_align_bones_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************* Delete ******************************* */
+
+/* previously delete_armature */
+/* only editmode! */
+static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bArmature *arm;
+ EditBone *curBone, *ebone_next;
+ bConstraint *con;
+ Object *obedit = CTX_data_edit_object(C); // XXX get from context
+ arm = obedit->data;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ armature_select_mirrored(arm);
+
+ /* First erase any associated pose channel */
+ if (obedit->pose) {
+ bPoseChannel *pchan, *pchan_next;
+ for (pchan = obedit->pose->chanbase.first; pchan; pchan = pchan_next) {
+ pchan_next = pchan->next;
+ curBone = editbone_name_exists(arm->edbo, pchan->name);
+
+ if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
+ BKE_pose_channel_free(pchan);
+ BKE_pose_channels_hash_free(obedit->pose);
+ BLI_freelinkN(&obedit->pose->chanbase, pchan);
+ }
+ else {
+ for (con = pchan->constraints.first; con; con = con->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == obedit) {
+ if (ct->subtarget[0]) {
+ curBone = editbone_name_exists(arm->edbo, ct->subtarget);
+ if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ ct->subtarget[0] = 0;
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+ }
+ }
+
+
+ for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
+ ebone_next = curBone->next;
+ if (arm->layer & curBone->layer) {
+ if (curBone->flag & BONE_SELECTED) {
+ if (curBone == arm->act_edbone) arm->act_edbone = NULL;
+ ED_armature_edit_bone_remove(arm, curBone);
+ }
+ }
+ }
+
+
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Selected Bone(s)";
+ ot->idname = "ARMATURE_OT_delete";
+ ot->description = "Remove selected bones from the armature";
+
+ /* api callbacks */
+ ot->invoke = WM_operator_confirm;
+ ot->exec = armature_delete_selected_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************* Show/Hide ******************************* */
+
+static int armature_hide_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone;
+ const int invert = RNA_boolean_get(op->ptr, "unselected") ? BONE_SELECTED : 0;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if ((ebone->flag & BONE_SELECTED) != invert) {
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ ebone->flag |= BONE_HIDDEN_A;
+ }
+ }
+ }
+ ED_armature_validate_active(arm);
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hide Selected Bones";
+ ot->idname = "ARMATURE_OT_hide";
+ ot->description = "Tag selected bones to not be visible in Edit Mode";
+
+ /* api callbacks */
+ ot->exec = armature_hide_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
+}
+
+static int armature_reveal_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (arm->layer & ebone->layer) {
+ if (ebone->flag & BONE_HIDDEN_A) {
+ ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ ebone->flag &= ~BONE_HIDDEN_A;
+ }
+ }
+ }
+ ED_armature_validate_active(arm);
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_reveal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Reveal Bones";
+ ot->idname = "ARMATURE_OT_reveal";
+ ot->description = "Unhide all bones that have been tagged to be hidden in Edit Mode";
+
+ /* api callbacks */
+ ot->exec = armature_reveal_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+}
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index ddf66a6169b..bfebc68ea46 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -37,17 +37,19 @@ struct wmOperatorType;
struct bContext;
struct Scene;
struct Object;
+struct Base;
struct bAction;
struct bPoseChannel;
struct bArmature;
struct EditBone;
+struct Bone;
struct ListBase;
struct LinkData;
/* ******************************************************* */
-/* editarmature.c operators */
+/* Armature EditMode Operators */
void ARMATURE_OT_bone_primitive_add(struct wmOperatorType *ot);
void ARMATURE_OT_align(struct wmOperatorType *ot);
@@ -131,7 +133,7 @@ void POSE_OT_armature_layers(struct wmOperatorType *ot);
void POSE_OT_bone_layers(struct wmOperatorType *ot);
/* ******************************************************* */
-/* Etch-A-Ton */
+/* Etch-A-Ton (Skeleton Sketching) Operators */
void SKETCH_OT_gesture(struct wmOperatorType *ot);
void SKETCH_OT_delete(struct wmOperatorType *ot);
@@ -144,7 +146,7 @@ void SKETCH_OT_select(struct wmOperatorType *ot);
/* ******************************************************* */
/* Pose Tool Utilities (for PoseLib, Pose Sliding, etc.) */
-/* poseUtils.c */
+/* pose_utils.c */
/* Temporary data linking PoseChannels with the F-Curves they affect */
typedef struct tPChanFCurveLink {
@@ -178,7 +180,7 @@ LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, con
/* ******************************************************* */
/* PoseLib */
-/* poselib.c */
+/* pose_lib.c */
void POSELIB_OT_new(struct wmOperatorType *ot);
void POSELIB_OT_unlink(struct wmOperatorType *ot);
@@ -194,7 +196,7 @@ void POSELIB_OT_apply_pose(struct wmOperatorType *ot);
/* ******************************************************* */
/* Pose Sliding Tools */
-/* poseSlide.c */
+/* pose_slide.c */
void POSE_OT_push(struct wmOperatorType *ot);
void POSE_OT_relax(struct wmOperatorType *ot);
@@ -203,7 +205,11 @@ void POSE_OT_breakdown(struct wmOperatorType *ot);
void POSE_OT_propagate(struct wmOperatorType *ot);
/* ******************************************************* */
-/* editarmature.c */
+/* Various Armature Edit/Pose Editing API's */
+
+/* Ideally, many of these defines would not be needed as everything would be strictly self-contained
+ * within each file, but some tools still have a bit of overlap which makes things messy -- Feb 2013
+ */
EditBone *make_boneList(struct ListBase *edbo, struct ListBase *bones, struct EditBone *parent, struct Bone *actBone);
void BIF_sk_selectStroke(struct bContext *C, const int mval[2], short extend);
@@ -213,13 +219,29 @@ void preEditBoneDuplicate(struct ListBase *editbones);
struct EditBone *duplicateEditBone(struct EditBone *curBone, const char *name, struct ListBase *editbones, struct Object *ob);
void updateDuplicateSubtarget(struct EditBone *dupBone, struct ListBase *editbones, struct Object *ob);
-/* duplicate method (cross objects */
-
+/* duplicate method (cross objects) */
/* editbones is the target list */
struct EditBone *duplicateEditBoneObjects(struct EditBone *curBone, const char *name, struct ListBase *editbones, struct Object *src_ob, struct Object *dst_ob);
/* editbones is the source list */
void updateDuplicateSubtargetObjects(struct EditBone *dupBone, struct ListBase *editbones, struct Object *src_ob, struct Object *dst_ob);
+
+EditBone *editbone_name_exists(struct ListBase *edbo, const char *name);
+
+EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]);
+void bone_free(struct bArmature *arm, struct EditBone *bone);
+
+void armature_tag_select_mirrored(struct bArmature *arm);
+void armature_select_mirrored(struct bArmature *arm);
+void armature_tag_unselect(struct bArmature *arm);
+
+void *get_nearest_bone(struct bContext *C, short findunsel, int x, int y);
+void *get_bone_from_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer, short hits, short findunsel);
+
+int bone_looper(struct Object *ob, struct Bone *bone, void *data,
+ int (*bone_func)(struct Object *, struct Bone *, void *));
+
+
#endif /* __ARMATURE_INTERN_H__ */
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
new file mode 100644
index 00000000000..6417a795712
--- /dev/null
+++ b/source/blender/editors/armature/armature_naming.c
@@ -0,0 +1,368 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators and API's for renaming bones both in and out of Edit Mode
+ */
+
+/** \file blender/editors/armature/armature_naming.c
+ * \ingroup edarmature
+ */
+
+#include <string.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+
+#include "BKE_animsys.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+
+#include "armature_intern.h"
+
+/* This file contains functions/API's for renaming bones and/or working with them */
+
+/* ************************************************** */
+/* EditBone Names */
+
+/* checks if an EditBone with a matching name already, returning the matching bone if it exists */
+EditBone *editbone_name_exists(ListBase *edbo, const char *name)
+{
+ return BLI_findstring(edbo, name, offsetof(EditBone, name));
+}
+
+/* note: there's a unique_bone_name() too! */
+static int editbone_unique_check(void *arg, const char *name)
+{
+ struct {ListBase *lb; void *bone; } *data = arg;
+ EditBone *dupli = editbone_name_exists(data->lb, name);
+ return dupli && dupli != data->bone;
+}
+
+void unique_editbone_name(ListBase *edbo, char *name, EditBone *bone)
+{
+ struct {ListBase *lb; void *bone; } data;
+ data.lb = edbo;
+ data.bone = bone;
+
+ BLI_uniquename_cb(editbone_unique_check, &data, "Bone", '.', name, sizeof(bone->name));
+}
+
+/* ************************************************** */
+/* Bone Renaming - API */
+
+static int bone_unique_check(void *arg, const char *name)
+{
+ return BKE_armature_find_bone_name((bArmature *)arg, name) != NULL;
+}
+
+static void unique_bone_name(bArmature *arm, char *name)
+{
+ BLI_uniquename_cb(bone_unique_check, (void *)arm, "Bone", '.', name, sizeof(((Bone *)NULL)->name));
+}
+
+/* helper call for armature_bone_rename */
+static void constraint_bone_name_fix(Object *ob, ListBase *conlist, char *oldname, char *newname)
+{
+ bConstraint *curcon;
+ bConstraintTarget *ct;
+
+ for (curcon = conlist->first; curcon; curcon = curcon->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon);
+ ListBase targets = {NULL, NULL};
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(curcon, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == ob) {
+ if (!strcmp(ct->subtarget, oldname) )
+ BLI_strncpy(ct->subtarget, newname, MAXBONENAME);
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(curcon, &targets, 0);
+ }
+ }
+}
+
+/* called by UI for renaming a bone */
+/* warning: make sure the original bone was not renamed yet! */
+/* seems messy, but thats what you get with not using pointers but channel names :) */
+void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *newnamep)
+{
+ Object *ob;
+ char newname[MAXBONENAME];
+ char oldname[MAXBONENAME];
+
+ /* names better differ! */
+ if (strncmp(oldnamep, newnamep, MAXBONENAME)) {
+
+ /* we alter newname string... so make copy */
+ BLI_strncpy(newname, newnamep, MAXBONENAME);
+ /* we use oldname for search... so make copy */
+ BLI_strncpy(oldname, oldnamep, MAXBONENAME);
+
+ /* now check if we're in editmode, we need to find the unique name */
+ if (arm->edbo) {
+ EditBone *eBone = editbone_name_exists(arm->edbo, oldname);
+
+ if (eBone) {
+ unique_editbone_name(arm->edbo, newname, NULL);
+ BLI_strncpy(eBone->name, newname, MAXBONENAME);
+ }
+ else return;
+ }
+ else {
+ Bone *bone = BKE_armature_find_bone_name(arm, oldname);
+
+ if (bone) {
+ unique_bone_name(arm, newname);
+ BLI_strncpy(bone->name, newname, MAXBONENAME);
+ }
+ else return;
+ }
+
+ /* do entire dbase - objects */
+ for (ob = G.main->object.first; ob; ob = ob->id.next) {
+ ModifierData *md;
+
+ /* we have the object using the armature */
+ if (arm == ob->data) {
+ Object *cob;
+
+ /* Rename the pose channel, if it exists */
+ if (ob->pose) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, oldname);
+ if (pchan) {
+ BLI_strncpy(pchan->name, newname, MAXBONENAME);
+
+ if (ob->pose->chanhash) {
+ GHash *gh = ob->pose->chanhash;
+
+ /* remove the old hash entry, and replace with the new name */
+ BLI_ghash_remove(gh, oldname, NULL, NULL);
+ BLI_ghash_insert(gh, pchan->name, pchan);
+ }
+ }
+ }
+
+ /* Update any object constraints to use the new bone name */
+ for (cob = G.main->object.first; cob; cob = cob->id.next) {
+ if (cob->constraints.first)
+ constraint_bone_name_fix(ob, &cob->constraints, oldname, newname);
+ if (cob->pose) {
+ bPoseChannel *pchan;
+ for (pchan = cob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ constraint_bone_name_fix(ob, &pchan->constraints, oldname, newname);
+ }
+ }
+ }
+ }
+
+ /* See if an object is parented to this armature */
+ if (ob->parent && (ob->parent->data == arm)) {
+ if (ob->partype == PARBONE) {
+ /* bone name in object */
+ if (!strcmp(ob->parsubstr, oldname))
+ BLI_strncpy(ob->parsubstr, newname, MAXBONENAME);
+ }
+ }
+
+ if (modifiers_usesArmature(ob, arm)) {
+ bDeformGroup *dg = defgroup_find_name(ob, oldname);
+ if (dg) {
+ BLI_strncpy(dg->name, newname, MAXBONENAME);
+ }
+ }
+
+ /* fix modifiers that might be using this name */
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData *)md;
+
+ /* uses armature, so may use the affected bone name */
+ if (hmd->object && (hmd->object->data == arm)) {
+ if (!strcmp(hmd->subtarget, oldname))
+ BLI_strncpy(hmd->subtarget, newname, MAXBONENAME);
+ }
+ }
+ }
+ }
+
+ /* 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]
+ */
+ {
+
+ BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname);
+ }
+
+ /* correct view locking */
+ {
+ bScreen *screen;
+ for (screen = G.main->screen.first; screen; screen = screen->id.next) {
+ ScrArea *sa;
+ /* add regions */
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ 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)) {
+ BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* ************************************************** */
+/* Bone Renaming - EditMode */
+
+static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm;
+ char newname[MAXBONENAME];
+
+ /* paranoia checks */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+ arm = ob->data;
+
+ /* loop through selected bones, auto-naming them */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ flip_side_name(newname, ebone->name, TRUE); // 1 = do strip off number extensions
+ ED_armature_bone_rename(arm, ebone->name, newname);
+ }
+ CTX_DATA_END;
+
+ /* since we renamed stuff... */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_flip_names(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flip Names";
+ ot->idname = "ARMATURE_OT_flip_names";
+ ot->description = "Flips (and corrects) the axis suffixes of the names of selected bones";
+
+ /* api callbacks */
+ ot->exec = armature_flip_names_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int armature_autoside_names_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm;
+ char newname[MAXBONENAME];
+ short axis = RNA_enum_get(op->ptr, "type");
+
+ /* paranoia checks */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+ arm = ob->data;
+
+ /* loop through selected bones, auto-naming them */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ BLI_strncpy(newname, ebone->name, sizeof(newname));
+ if (bone_autoside_name(newname, 1, axis, ebone->head[axis], ebone->tail[axis]))
+ ED_armature_bone_rename(arm, ebone->name, newname);
+ }
+ CTX_DATA_END;
+
+ /* since we renamed stuff... */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_autoside_names(wmOperatorType *ot)
+{
+ static EnumPropertyItem axis_items[] = {
+ {0, "XAXIS", 0, "X-Axis", "Left/Right"},
+ {1, "YAXIS", 0, "Y-Axis", "Front/Back"},
+ {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "AutoName by Axis";
+ ot->idname = "ARMATURE_OT_autoside_names";
+ ot->description = "Automatically renames the selected bones according to which side of the target axis they fall on";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_autoside_names_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* settings */
+ ot->prop = RNA_def_enum(ot->srna, "type", axis_items, 0, "Axis", "Axis tag names with");
+}
+
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index 7c5b75e56ae..f87d4bc4d47 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -28,15 +28,7 @@
* \ingroup edarmature
*/
-
-#include <stdlib.h>
-#include <math.h>
-
-#include "BLO_sys_types.h"
-
#include "BLI_math.h"
-#include "BLI_blenlib.h"
-
#include "RNA_access.h"
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
new file mode 100644
index 00000000000..c64bb5c4683
--- /dev/null
+++ b/source/blender/editors/armature/armature_relations.c
@@ -0,0 +1,774 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for relations between bones and for transferring bones between armature objects
+ */
+
+/** \file blender/editors/armature/armature_relations.c
+ * \ingroup edarmature
+ */
+
+#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_math.h"
+
+#include "BLF_translation.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "armature_intern.h"
+
+/* *************************************** Join *************************************** */
+/* NOTE: no operator define here as this is exported to the Object-level operator */
+
+/* Helper function for armature joining - link fixing */
+static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone)
+{
+ Object *ob;
+ bPose *pose;
+ bPoseChannel *pchant;
+ bConstraint *con;
+
+ /* let's go through all objects in database */
+ for (ob = G.main->object.first; ob; ob = ob->id.next) {
+ /* do some object-type specific things */
+ if (ob->type == OB_ARMATURE) {
+ pose = ob->pose;
+ for (pchant = pose->chanbase.first; pchant; pchant = pchant->next) {
+ for (con = pchant->constraints.first; con; con = con->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == srcArm) {
+ if (ct->subtarget[0] == '\0') {
+ ct->tar = tarArm;
+ }
+ else if (strcmp(ct->subtarget, pchan->name) == 0) {
+ ct->tar = tarArm;
+ BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget));
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+
+ /* action constraint? */
+ if (con->type == CONSTRAINT_TYPE_ACTION) {
+ bActionConstraint *data = con->data; // XXX old animation system
+ bAction *act;
+ bActionChannel *achan;
+
+ if (data->act) {
+ act = data->act;
+
+ for (achan = act->chanbase.first; achan; achan = achan->next) {
+ if (strcmp(achan->name, pchan->name) == 0)
+ BLI_strncpy(achan->name, curbone->name, sizeof(achan->name));
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ /* fix object-level constraints */
+ if (ob != srcArm) {
+ for (con = ob->constraints.first; con; con = con->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == srcArm) {
+ if (ct->subtarget[0] == '\0') {
+ ct->tar = tarArm;
+ }
+ else if (strcmp(ct->subtarget, pchan->name) == 0) {
+ ct->tar = tarArm;
+ BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget));
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+
+ /* See if an object is parented to this armature */
+ if (ob->parent && (ob->parent == srcArm)) {
+ /* Is object parented to a bone of this src armature? */
+ if (ob->partype == PARBONE) {
+ /* bone name in object */
+ if (!strcmp(ob->parsubstr, pchan->name))
+ BLI_strncpy(ob->parsubstr, curbone->name, sizeof(ob->parsubstr));
+ }
+
+ /* make tar armature be new parent */
+ ob->parent = tarArm;
+ }
+ }
+}
+
+/* join armature exec is exported for use in object->join objects operator... */
+int join_armature_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bPose *pose, *opose;
+ bPoseChannel *pchan, *pchann;
+ EditBone *curbone;
+ float mat[4][4], oimat[4][4];
+
+ /* Ensure we're not in editmode and that the active object is an armature*/
+ if (!ob || ob->type != OB_ARMATURE)
+ return OPERATOR_CANCELLED;
+ if (!arm || arm->edbo)
+ return OPERATOR_CANCELLED;
+
+ /* Get editbones of active armature to add editbones to */
+ ED_armature_to_edit(ob);
+
+ /* get pose of active object and move it out of posemode */
+ pose = ob->pose;
+ ob->mode &= ~OB_MODE_POSE;
+
+ CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
+ {
+ if ((base->object->type == OB_ARMATURE) && (base->object != ob)) {
+ bArmature *curarm = base->object->data;
+
+ /* Make a list of editbones in current armature */
+ ED_armature_to_edit(base->object);
+
+ /* Get Pose of current armature */
+ opose = base->object->pose;
+ base->object->mode &= ~OB_MODE_POSE;
+ //BASACT->flag &= ~OB_MODE_POSE;
+
+ /* Find the difference matrix */
+ invert_m4_m4(oimat, ob->obmat);
+ mult_m4_m4m4(mat, oimat, base->object->obmat);
+
+ /* Copy bones and posechannels from the object to the edit armature */
+ for (pchan = opose->chanbase.first; pchan; pchan = pchann) {
+ pchann = pchan->next;
+ curbone = editbone_name_exists(curarm->edbo, pchan->name);
+
+ /* Get new name */
+ unique_editbone_name(arm->edbo, curbone->name, NULL);
+
+ /* Transform the bone */
+ {
+ float premat[4][4];
+ float postmat[4][4];
+ float difmat[4][4];
+ float imat[4][4];
+ float temp[3][3];
+ float delta[3];
+
+ /* Get the premat */
+ sub_v3_v3v3(delta, curbone->tail, curbone->head);
+ vec_roll_to_mat3(delta, curbone->roll, temp);
+
+ unit_m4(premat); /* Mat4MulMat34 only sets 3x3 part */
+ mul_m4_m3m4(premat, temp, mat);
+
+ mul_m4_v3(mat, curbone->head);
+ mul_m4_v3(mat, curbone->tail);
+
+ /* Get the postmat */
+ sub_v3_v3v3(delta, curbone->tail, curbone->head);
+ vec_roll_to_mat3(delta, curbone->roll, temp);
+ copy_m4_m3(postmat, temp);
+
+ /* Find the roll */
+ invert_m4_m4(imat, premat);
+ mult_m4_m4m4(difmat, imat, postmat);
+
+ curbone->roll -= (float)atan2(difmat[2][0], difmat[2][2]);
+ }
+
+ /* Fix Constraints and Other Links to this Bone and Armature */
+ joined_armature_fix_links(ob, base->object, pchan, curbone);
+
+ /* Rename pchan */
+ BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name));
+
+ /* Jump Ship! */
+ BLI_remlink(curarm->edbo, curbone);
+ BLI_addtail(arm->edbo, curbone);
+
+ BLI_remlink(&opose->chanbase, pchan);
+ BLI_addtail(&pose->chanbase, pchan);
+ BKE_pose_channels_hash_free(opose);
+ BKE_pose_channels_hash_free(pose);
+ }
+
+ ED_base_object_free_and_unlink(bmain, scene, base);
+ }
+ }
+ CTX_DATA_END;
+
+ DAG_relations_tag_update(bmain); /* because we removed object(s) */
+
+ ED_armature_from_edit(ob);
+ ED_armature_edit_free(ob);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+/* *********************************** Separate *********************************************** */
+
+/* Helper function for armature separating - link fixing */
+static void separated_armature_fix_links(Object *origArm, Object *newArm)
+{
+ Object *ob;
+ bPoseChannel *pchan;
+ bConstraint *con;
+ ListBase *opchans, *npchans;
+
+ /* get reference to list of bones in original and new armatures */
+ opchans = &origArm->pose->chanbase;
+ npchans = &newArm->pose->chanbase;
+
+ /* let's go through all objects in database */
+ for (ob = G.main->object.first; ob; ob = ob->id.next) {
+ /* do some object-type specific things */
+ if (ob->type == OB_ARMATURE) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (con = pchan->constraints.first; con; con = con->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ /* any targets which point to original armature are redirected to the new one only if:
+ * - the target isn't origArm/newArm itself
+ * - the target is one that can be found in newArm/origArm
+ */
+ if (ct->subtarget[0] != 0) {
+ if (ct->tar == origArm) {
+ if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
+ ct->tar = newArm;
+ }
+ }
+ else if (ct->tar == newArm) {
+ if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
+ ct->tar = origArm;
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets) {
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+ }
+ }
+
+ /* fix object-level constraints */
+ if (ob != origArm) {
+ for (con = ob->constraints.first; con; con = con->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ /* any targets which point to original armature are redirected to the new one only if:
+ * - the target isn't origArm/newArm itself
+ * - the target is one that can be found in newArm/origArm
+ */
+ if (ct->subtarget[0] != '\0') {
+ if (ct->tar == origArm) {
+ if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
+ ct->tar = newArm;
+ }
+ }
+ else if (ct->tar == newArm) {
+ if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
+ ct->tar = origArm;
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets) {
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+ }
+
+ /* See if an object is parented to this armature */
+ if (ob->parent && (ob->parent == origArm)) {
+ /* Is object parented to a bone of this src armature? */
+ if ((ob->partype == PARBONE) && (ob->parsubstr[0] != '\0')) {
+ if (BLI_findstring(npchans, ob->parsubstr, offsetof(bPoseChannel, name))) {
+ ob->parent = newArm;
+ }
+ }
+ }
+ }
+}
+
+/* Helper function for armature separating - remove certain bones from the given armature
+ * sel: remove selected bones from the armature, otherwise the unselected bones are removed
+ * (ob is not in editmode)
+ */
+static void separate_armature_bones(Object *ob, short sel)
+{
+ bArmature *arm = (bArmature *)ob->data;
+ bPoseChannel *pchan, *pchann;
+ EditBone *curbone;
+
+ /* make local set of editbones to manipulate here */
+ ED_armature_to_edit(ob);
+
+ /* go through pose-channels, checking if a bone should be removed */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchann) {
+ pchann = pchan->next;
+ curbone = editbone_name_exists(arm->edbo, pchan->name);
+
+ /* check if bone needs to be removed */
+ if ( (sel && (curbone->flag & BONE_SELECTED)) ||
+ (!sel && !(curbone->flag & BONE_SELECTED)) )
+ {
+ EditBone *ebo;
+ bPoseChannel *pchn;
+
+ /* clear the bone->parent var of any bone that had this as its parent */
+ for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ if (ebo->parent == curbone) {
+ ebo->parent = NULL;
+ ebo->temp = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */
+ ebo->flag &= ~BONE_CONNECTED;
+ }
+ }
+
+ /* clear the pchan->parent var of any pchan that had this as its parent */
+ for (pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) {
+ if (pchn->parent == pchan)
+ pchn->parent = NULL;
+ }
+
+ /* free any of the extra-data this pchan might have */
+ BKE_pose_channel_free(pchan);
+ BKE_pose_channels_hash_free(ob->pose);
+
+ /* get rid of unneeded bone */
+ bone_free(arm, curbone);
+ BLI_freelinkN(&ob->pose->chanbase, pchan);
+ }
+ }
+
+ /* exit editmode (recalculates pchans too) */
+ ED_armature_from_edit(ob);
+ ED_armature_edit_free(ob);
+}
+
+/* separate selected bones into their armature */
+static int separate_armature_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ Object *oldob, *newob;
+ Base *oldbase, *newbase;
+
+ /* sanity checks */
+ if (obedit == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* set wait cursor in case this takes a while */
+ WM_cursor_wait(1);
+
+ /* we are going to do this as follows (unlike every other instance of separate):
+ * 1. exit editmode +posemode for active armature/base. Take note of what this is.
+ * 2. duplicate base - BASACT is the new one now
+ * 3. for each of the two armatures, enter editmode -> remove appropriate bones -> exit editmode + recalc
+ * 4. fix constraint links
+ * 5. make original armature active and enter editmode
+ */
+
+ /* 1) only edit-base selected */
+ /* TODO: use context iterators for this? */
+ CTX_DATA_BEGIN(C, Base *, base, visible_bases)
+ {
+ if (base->object == obedit) base->flag |= 1;
+ else base->flag &= ~1;
+ }
+ CTX_DATA_END;
+
+ /* 1) store starting settings and exit editmode */
+ oldob = obedit;
+ oldbase = BASACT;
+ oldob->mode &= ~OB_MODE_POSE;
+ //oldbase->flag &= ~OB_POSEMODE;
+
+ ED_armature_from_edit(obedit);
+ ED_armature_edit_free(obedit);
+
+ /* 2) duplicate base */
+ newbase = ED_object_add_duplicate(bmain, scene, oldbase, USER_DUP_ARM); /* only duplicate linked armature */
+ DAG_relations_tag_update(bmain);
+
+ newob = newbase->object;
+ newbase->flag &= ~SELECT;
+
+
+ /* 3) remove bones that shouldn't still be around on both armatures */
+ separate_armature_bones(oldob, 1);
+ separate_armature_bones(newob, 0);
+
+
+ /* 4) fix links before depsgraph flushes */ // err... or after?
+ separated_armature_fix_links(oldob, newob);
+
+ DAG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */
+ DAG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */
+
+
+ /* 5) restore original conditions */
+ obedit = oldob;
+
+ ED_armature_to_edit(obedit);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+
+ /* recalc/redraw + cleanup */
+ WM_cursor_wait(0);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_separate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Separate Bones";
+ ot->idname = "ARMATURE_OT_separate";
+ ot->description = "Isolate selected bones into a separate armature";
+
+ /* callbacks */
+ ot->invoke = WM_operator_confirm;
+ ot->exec = separate_armature_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************************************** Parenting ************************************************* */
+
+/* armature parenting options */
+#define ARM_PAR_CONNECT 1
+#define ARM_PAR_OFFSET 2
+
+
+/* check for null, before calling! */
+static void bone_connect_to_existing_parent(EditBone *bone)
+{
+ bone->flag |= BONE_CONNECTED;
+ copy_v3_v3(bone->head, bone->parent->tail);
+ bone->rad_head = bone->parent->rad_tail;
+}
+
+static void bone_connect_to_new_parent(ListBase *edbo, EditBone *selbone, EditBone *actbone, short mode)
+{
+ EditBone *ebone;
+ float offset[3];
+
+ if ((selbone->parent) && (selbone->flag & BONE_CONNECTED))
+ selbone->parent->flag &= ~(BONE_TIPSEL);
+
+ /* make actbone the parent of selbone */
+ selbone->parent = actbone;
+
+ /* in actbone tree we cannot have a loop */
+ for (ebone = actbone->parent; ebone; ebone = ebone->parent) {
+ if (ebone->parent == selbone) {
+ ebone->parent = NULL;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+ }
+
+ if (mode == ARM_PAR_CONNECT) {
+ /* Connected: Child bones will be moved to the parent tip */
+ selbone->flag |= BONE_CONNECTED;
+ sub_v3_v3v3(offset, actbone->tail, selbone->head);
+
+ copy_v3_v3(selbone->head, actbone->tail);
+ selbone->rad_head = actbone->rad_tail;
+
+ add_v3_v3(selbone->tail, offset);
+
+ /* offset for all its children */
+ for (ebone = edbo->first; ebone; ebone = ebone->next) {
+ EditBone *par;
+
+ for (par = ebone->parent; par; par = par->parent) {
+ if (par == selbone) {
+ add_v3_v3(ebone->head, offset);
+ add_v3_v3(ebone->tail, offset);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ /* Offset: Child bones will retain their distance from the parent tip */
+ selbone->flag &= ~BONE_CONNECTED;
+ }
+}
+
+
+static EnumPropertyItem prop_editarm_make_parent_types[] = {
+ {ARM_PAR_CONNECT, "CONNECTED", 0, "Connected", ""},
+ {ARM_PAR_OFFSET, "OFFSET", 0, "Keep Offset", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int armature_parent_set_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = (bArmature *)ob->data;
+ EditBone *actbone = CTX_data_active_bone(C);
+ EditBone *actmirb = NULL;
+ short val = RNA_enum_get(op->ptr, "type");
+
+ /* there must be an active bone */
+ if (actbone == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
+ return OPERATOR_CANCELLED;
+ }
+ else if (arm->flag & ARM_MIRROR_EDIT) {
+ /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
+ * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
+ * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
+ * This is useful for arm-chains, for example parenting lower arm to upper arm
+ * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
+ * then just use actbone. Useful when doing upper arm to spine.
+ */
+ actmirb = ED_armature_bone_get_mirrored(arm->edbo, actbone);
+ if (actmirb == NULL)
+ actmirb = actbone;
+ }
+
+ /* if there is only 1 selected bone, we assume that that is the active bone,
+ * since a user will need to have clicked on a bone (thus selecting it) to make it active
+ */
+ if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) {
+ /* When only the active bone is selected, and it has a parent,
+ * connect it to the parent, as that is the only possible outcome.
+ */
+ if (actbone->parent) {
+ bone_connect_to_existing_parent(actbone);
+
+ if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
+ bone_connect_to_existing_parent(actmirb);
+ }
+ }
+ else {
+ /* Parent 'selected' bones to the active one
+ * - the context iterator contains both selected bones and their mirrored copies,
+ * so we assume that unselected bones are mirrored copies of some selected bone
+ * - since the active one (and/or its mirror) will also be selected, we also need
+ * to check that we are not trying to operate on them, since such an operation
+ * would cause errors
+ */
+
+ /* parent selected bones to the active one */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ if (ELEM(ebone, actbone, actmirb) == 0) {
+ if (ebone->flag & BONE_SELECTED)
+ bone_connect_to_new_parent(arm->edbo, ebone, actbone, val);
+ else
+ bone_connect_to_new_parent(arm->edbo, ebone, actmirb, val);
+ }
+ }
+ CTX_DATA_END;
+ }
+
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+{
+ EditBone *actbone = CTX_data_active_bone(C);
+ uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE);
+ uiLayout *layout = uiPupMenuLayout(pup);
+ int allchildbones = 0;
+
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ if (ebone != actbone) {
+ if (ebone->parent != actbone) allchildbones = 1;
+ }
+ }
+ CTX_DATA_END;
+
+ uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT);
+
+ /* ob becomes parent, make the associated menus */
+ if (allchildbones)
+ uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET);
+
+ uiPupMenuEnd(C, pup);
+
+ return OPERATOR_CANCELLED;
+}
+
+void ARMATURE_OT_parent_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Make Parent";
+ ot->idname = "ARMATURE_OT_parent_set";
+ ot->description = "Set the active bone as the parent of the selected bones";
+
+ /* api callbacks */
+ ot->invoke = armature_parent_set_invoke;
+ ot->exec = armature_parent_set_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "type", prop_editarm_make_parent_types, 0, "ParentType", "Type of parenting");
+}
+
+
+
+static EnumPropertyItem prop_editarm_clear_parent_types[] = {
+ {1, "CLEAR", 0, "Clear Parent", ""},
+ {2, "DISCONNECT", 0, "Disconnect Bone", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static void editbone_clear_parent(EditBone *ebone, int mode)
+{
+ if (ebone->parent) {
+ /* for nice selection */
+ ebone->parent->flag &= ~(BONE_TIPSEL);
+ }
+
+ if (mode == 1) ebone->parent = NULL;
+ ebone->flag &= ~BONE_CONNECTED;
+}
+
+static int armature_parent_clear_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = (bArmature *)ob->data;
+ int val = RNA_enum_get(op->ptr, "type");
+
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ editbone_clear_parent(ebone, val);
+ }
+ CTX_DATA_END;
+
+ ED_armature_sync_selection(arm->edbo);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_parent_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Parent";
+ ot->idname = "ARMATURE_OT_parent_clear";
+ ot->description = "Remove the parent-child relationship between selected bones and their parents";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_parent_clear_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_editarm_clear_parent_types, 0, "ClearType", "What way to clear parenting");
+}
+
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
new file mode 100644
index 00000000000..b7a436cc209
--- /dev/null
+++ b/source/blender/editors/armature/armature_select.c
@@ -0,0 +1,940 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * API's and Operators for selecting armature bones in EditMode
+ */
+
+/** \file blender/editors/armature/armature_select.c
+ * \ingroup edarmature
+ */
+
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_report.h"
+
+#include "BIF_gl.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "armature_intern.h"
+
+/* **************** PoseMode & EditMode Selection Buffer Queries *************************** */
+
+/* only for opengl selection indices */
+Bone *get_indexed_bone(Object *ob, int index)
+{
+ bPoseChannel *pchan;
+ if (ob->pose == NULL) return NULL;
+ index >>= 16; // bone selection codes use left 2 bytes
+
+ pchan = BLI_findlink(&ob->pose->chanbase, index);
+ return pchan ? pchan->bone : NULL;
+}
+
+/* See if there are any selected bones in this buffer */
+/* only bones from base are checked on */
+void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits, short findunsel)
+{
+ Object *obedit = scene->obedit; // XXX get from context
+ Bone *bone;
+ EditBone *ebone;
+ void *firstunSel = NULL, *firstSel = NULL, *data;
+ unsigned int hitresult;
+ short i, takeNext = 0, sel;
+
+ for (i = 0; i < hits; i++) {
+ hitresult = buffer[3 + (i * 4)];
+
+ if (!(hitresult & BONESEL_NOSEL)) { // -1
+ if (hitresult & BONESEL_ANY) { // to avoid including objects in selection
+
+ hitresult &= ~(BONESEL_ANY);
+ /* Determine what the current bone is */
+ if (obedit == NULL || base->object != obedit) {
+ /* no singular posemode, so check for correct object */
+ if (base->selcol == (hitresult & 0xFFFF)) {
+ bone = get_indexed_bone(base->object, hitresult);
+
+ if (findunsel)
+ sel = (bone->flag & BONE_SELECTED);
+ else
+ sel = !(bone->flag & BONE_SELECTED);
+
+ data = bone;
+ }
+ else {
+ data = NULL;
+ sel = 0;
+ }
+ }
+ else {
+ bArmature *arm = obedit->data;
+
+ ebone = BLI_findlink(arm->edbo, hitresult);
+ if (findunsel)
+ sel = (ebone->flag & BONE_SELECTED);
+ else
+ sel = !(ebone->flag & BONE_SELECTED);
+
+ data = ebone;
+ }
+
+ if (data) {
+ if (sel) {
+ if (!firstSel) firstSel = data;
+ takeNext = 1;
+ }
+ else {
+ if (!firstunSel)
+ firstunSel = data;
+ if (takeNext)
+ return data;
+ }
+ }
+ }
+ }
+ }
+
+ if (firstunSel)
+ return firstunSel;
+ else
+ return firstSel;
+}
+
+/* used by posemode as well editmode */
+/* only checks scene->basact! */
+/* x and y are mouse coords (area space) */
+void *get_nearest_bone(bContext *C, short findunsel, int x, int y)
+{
+ ViewContext vc;
+ rcti rect;
+ unsigned int buffer[MAXPICKBUF];
+ short hits;
+
+ view3d_set_viewcontext(C, &vc);
+
+ // rect.xmin = ... mouseco!
+ rect.xmin = rect.xmax = x;
+ rect.ymin = rect.ymax = y;
+
+ glInitNames();
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
+
+ if (hits > 0)
+ return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel);
+
+ return NULL;
+}
+
+/* **************** EditMode stuff ********************** */
+
+/* called in space.c */
+/* previously "selectconnected_armature" */
+static int armature_select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ bArmature *arm;
+ EditBone *bone, *curBone, *next;
+ int extend = RNA_boolean_get(op->ptr, "extend");
+ Object *obedit = CTX_data_edit_object(C);
+ arm = obedit->data;
+
+ view3d_operator_needs_opengl(C);
+
+ if (extend)
+ bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
+ else
+ bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]);
+
+ if (!bone)
+ return OPERATOR_CANCELLED;
+
+ /* Select parents */
+ for (curBone = bone; curBone; curBone = next) {
+ if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
+ if (extend) {
+ curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+
+ if (curBone->flag & BONE_CONNECTED)
+ next = curBone->parent;
+ else
+ next = NULL;
+ }
+
+ /* Select children */
+ while (bone) {
+ for (curBone = arm->edbo->first; curBone; curBone = next) {
+ next = curBone->next;
+ if ((curBone->parent == bone) && (curBone->flag & BONE_UNSELECTABLE) == 0) {
+ if (curBone->flag & BONE_CONNECTED) {
+ if (extend)
+ curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ else
+ curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ bone = curBone;
+ break;
+ }
+ else {
+ bone = NULL;
+ break;
+ }
+ }
+ }
+ if (!curBone)
+ bone = NULL;
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+static int armature_select_linked_poll(bContext *C)
+{
+ return (ED_operator_view3d_active(C) && ED_operator_editarmature(C) );
+}
+
+void ARMATURE_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Connected";
+ ot->idname = "ARMATURE_OT_select_linked";
+ ot->description = "Select bones related to selected ones by parent/child relationships";
+
+ /* api callbacks */
+ ot->exec = NULL;
+ ot->invoke = armature_select_linked_invoke;
+ ot->poll = armature_select_linked_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
+}
+
+/* does bones and points */
+/* note that BONE ROOT only gets drawn for root bones (or without IK) */
+static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
+ ListBase *edbo, int findunsel, int *selmask)
+{
+ bArmature *arm = (bArmature *)vc->obedit->data;
+ EditBone *ebone_next_act = arm->act_edbone;
+
+ EditBone *ebone;
+ rcti rect;
+ unsigned int buffer[MAXPICKBUF];
+ unsigned int hitresult, besthitresult = BONESEL_NOSEL;
+ int i, mindep = 4;
+ short hits;
+
+ glInitNames();
+
+ /* find the bone after the current active bone, so as to bump up its chances in selection.
+ * this way overlapping bones will cycle selection state as with objects. */
+ if (ebone_next_act &&
+ EBONE_VISIBLE(arm, ebone_next_act) &&
+ ebone_next_act->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL))
+ {
+ ebone_next_act = ebone_next_act->next ? ebone_next_act->next : arm->edbo->first;
+ }
+ else {
+ ebone_next_act = NULL;
+ }
+
+ rect.xmin = mval[0] - 5;
+ rect.xmax = mval[0] + 5;
+ rect.ymin = mval[1] - 5;
+ rect.ymax = mval[1] + 5;
+
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
+ if (hits == 0) {
+ rect.xmin = mval[0] - 12;
+ rect.xmax = mval[0] + 12;
+ rect.ymin = mval[1] - 12;
+ rect.ymax = mval[1] + 12;
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
+ }
+ /* See if there are any selected bones in this group */
+ if (hits > 0) {
+
+ if (hits == 1) {
+ if (!(buffer[3] & BONESEL_NOSEL))
+ besthitresult = buffer[3];
+ }
+ else {
+ for (i = 0; i < hits; i++) {
+ hitresult = buffer[3 + (i * 4)];
+ if (!(hitresult & BONESEL_NOSEL)) {
+ int dep;
+
+ ebone = BLI_findlink(edbo, hitresult & ~BONESEL_ANY);
+
+ /* clicks on bone points get advantage */
+ if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
+ /* but also the unselected one */
+ if (findunsel) {
+ if ( (hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0)
+ dep = 1;
+ else if ( (hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0)
+ dep = 1;
+ else
+ dep = 2;
+ }
+ else dep = 2;
+ }
+ else {
+ /* bone found */
+ if (findunsel) {
+ if ((ebone->flag & BONE_SELECTED) == 0)
+ dep = 2;
+ else
+ dep = 3;
+ }
+ else dep = 3;
+ }
+
+ if (ebone == ebone_next_act) {
+ dep -= 1;
+ }
+
+ if (dep < mindep) {
+ mindep = dep;
+ besthitresult = hitresult;
+ }
+ }
+ }
+ }
+
+ if (!(besthitresult & BONESEL_NOSEL)) {
+
+ ebone = BLI_findlink(edbo, besthitresult & ~BONESEL_ANY);
+
+ *selmask = 0;
+ if (besthitresult & BONESEL_ROOT)
+ *selmask |= BONE_ROOTSEL;
+ if (besthitresult & BONESEL_TIP)
+ *selmask |= BONE_TIPSEL;
+ if (besthitresult & BONESEL_BONE)
+ *selmask |= BONE_SELECTED;
+ return ebone;
+ }
+ }
+ *selmask = 0;
+ return NULL;
+}
+
+
+
+/* toggle==0: deselect
+ * toggle==1: swap (based on test)
+ * toggle==2: swap (no test), CURRENTLY UNUSED
+ */
+void ED_armature_deselect_all(Object *obedit, int toggle)
+{
+ bArmature *arm = obedit->data;
+ EditBone *eBone;
+ int sel = 1;
+
+ if (toggle == 1) {
+ /* Determine if there are any selected bones
+ * and therefore whether we are selecting or deselecting */
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ // if (arm->layer & eBone->layer) {
+ if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
+ sel = 0;
+ break;
+ }
+ // }
+ }
+ }
+ else sel = toggle;
+
+ /* Set the flags */
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ if (sel == 2) {
+ /* invert selection of bone */
+ if (EBONE_VISIBLE(arm, eBone)) {
+ eBone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if (arm->act_edbone == eBone)
+ arm->act_edbone = NULL;
+ }
+ }
+ else if (sel == 1) {
+ /* select bone */
+ if (EBONE_VISIBLE(arm, eBone)) {
+ eBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if (eBone->parent)
+ eBone->parent->flag |= (BONE_TIPSEL);
+ }
+ }
+ else {
+ /* deselect bone */
+ eBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if (arm->act_edbone == eBone)
+ arm->act_edbone = NULL;
+ }
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+}
+
+void ED_armature_deselect_all_visible(Object *obedit)
+{
+ bArmature *arm = obedit->data;
+ EditBone *ebone;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ /* first and foremost, bone must be visible and selected */
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+}
+
+/* accounts for connected parents */
+static int ebone_select_flag(EditBone *ebone)
+{
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) | (ebone->flag & (BONE_SELECTED | BONE_TIPSEL));
+ }
+ else {
+ return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+ }
+}
+
+/* context: editmode armature in view3d */
+int mouse_armature(bContext *C, const int mval[2], int extend, int deselect, int toggle)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ ViewContext vc;
+ EditBone *nearBone = NULL;
+ int selmask;
+
+ view3d_set_viewcontext(C, &vc);
+
+ BIF_sk_selectStroke(C, mval, extend);
+
+ nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask);
+ if (nearBone) {
+
+ if (!extend && !deselect && !toggle)
+ ED_armature_deselect_all(obedit, 0);
+
+ /* by definition the non-root connected bones have no root point drawn,
+ * so a root selection needs to be delivered to the parent tip */
+
+ if (selmask & BONE_SELECTED) {
+ if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) {
+ /* click in a chain */
+ if (extend) {
+ /* select this bone */
+ nearBone->flag |= BONE_TIPSEL;
+ nearBone->parent->flag |= BONE_TIPSEL;
+ }
+ else if (deselect) {
+ /* deselect this bone */
+ nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
+ /* only deselect parent tip if it is not selected */
+ if (!(nearBone->parent->flag & BONE_SELECTED))
+ nearBone->parent->flag &= ~BONE_TIPSEL;
+ }
+ else if (toggle) {
+ /* hold shift inverts this bone's selection */
+ if (nearBone->flag & BONE_SELECTED) {
+ /* deselect this bone */
+ nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
+ /* only deselect parent tip if it is not selected */
+ if (!(nearBone->parent->flag & BONE_SELECTED))
+ nearBone->parent->flag &= ~BONE_TIPSEL;
+ }
+ else {
+ /* select this bone */
+ nearBone->flag |= BONE_TIPSEL;
+ nearBone->parent->flag |= BONE_TIPSEL;
+ }
+ }
+ else {
+ /* select this bone */
+ nearBone->flag |= BONE_TIPSEL;
+ nearBone->parent->flag |= BONE_TIPSEL;
+ }
+ }
+ else {
+ if (extend) {
+ nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if (deselect) {
+ nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if (toggle) {
+ /* hold shift inverts this bone's selection */
+ if (nearBone->flag & BONE_SELECTED)
+ nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
+ else
+ nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else
+ nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+ else {
+ if (extend)
+ nearBone->flag |= selmask;
+ else if (deselect)
+ nearBone->flag &= ~selmask;
+ else if (toggle && (nearBone->flag & selmask))
+ nearBone->flag &= ~selmask;
+ else
+ nearBone->flag |= selmask;
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+
+ if (nearBone) {
+ /* then now check for active status */
+ if (ebone_select_flag(nearBone)) {
+ arm->act_edbone = nearBone;
+ }
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* **************** Selections ******************/
+
+static int armature_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ /* Set the flags */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
+ {
+ /* ignore bone if selection can't change */
+ if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
+ /* select bone */
+ ebone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_select_inverse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Inverse";
+ ot->idname = "ARMATURE_OT_select_inverse";
+ ot->description = "Flip the selection status of bones (selected -> unselected, unselected -> selected)";
+
+ /* api callbacks */
+ ot->exec = armature_select_inverse_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+}
+static int armature_de_select_all_exec(bContext *C, wmOperator *op)
+{
+ int action = RNA_enum_get(op->ptr, "action");
+
+ if (action == SEL_TOGGLE) {
+ action = SEL_SELECT;
+ /* Determine if there are any selected bones
+ * And therefore whether we are selecting or deselecting */
+ if (CTX_DATA_COUNT(C, selected_bones) > 0)
+ action = SEL_DESELECT;
+ }
+
+ /* Set the flags */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
+ {
+ /* ignore bone if selection can't change */
+ if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
+ switch (action) {
+ case SEL_SELECT:
+ ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if (ebone->parent)
+ ebone->parent->flag |= (BONE_TIPSEL);
+ break;
+ case SEL_DESELECT:
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ case SEL_INVERT:
+ if (ebone->flag & BONE_SELECTED) {
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if (ebone->parent)
+ ebone->parent->flag |= (BONE_TIPSEL);
+ }
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "(De)select All";
+ ot->idname = "ARMATURE_OT_select_all";
+ ot->description = "Toggle selection status of all bones";
+
+ /* api callbacks */
+ ot->exec = armature_de_select_all_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_select_all(ot);
+}
+
+enum {
+ SIMEDBONE_LENGTH = 1,
+ SIMEDBONE_DIRECTION,
+ SIMEDBONE_PREFIX,
+ SIMEDBONE_SUFFIX,
+ SIMEDBONE_LAYER
+};
+
+static EnumPropertyItem prop_similar_types[] = {
+ {SIMEDBONE_LENGTH, "LENGTH", 0, "Length", ""},
+ {SIMEDBONE_DIRECTION, "DIRECTION", 0, "Direction (Y axis)", ""},
+ {SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""},
+ {SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""},
+ {SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+/* could be used in more places */
+static void ED_armature_edit_bone_select(EditBone *ebone)
+{
+ BLI_assert((ebone->flag & BONE_UNSELECTABLE) == 0);
+ ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+
+ if ((ebone->flag & BONE_CONNECTED) && (ebone->parent != NULL)) {
+ ebone->parent->flag |= BONE_TIPSEL;
+ }
+}
+
+static void select_similar_length(bArmature *arm, EditBone *ebone_act, const float thresh)
+{
+ EditBone *ebone;
+
+ /* thresh is always relative to current length */
+ const float len_min = ebone_act->length / (1.0f + thresh);
+ const float len_max = ebone_act->length * (1.0f + thresh);
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ if ((ebone->length >= len_min) &&
+ (ebone->length <= len_max))
+ {
+ ED_armature_edit_bone_select(ebone);
+ }
+ }
+ }
+}
+
+static void select_similar_direction(bArmature *arm, EditBone *ebone_act, const float thresh)
+{
+ EditBone *ebone;
+ float dir_act[3];
+ sub_v3_v3v3(dir_act, ebone_act->head, ebone_act->tail);
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ float dir[3];
+ sub_v3_v3v3(dir, ebone->head, ebone->tail);
+
+ if (angle_v3v3(dir_act, dir) / (float)M_PI < thresh) {
+ ED_armature_edit_bone_select(ebone);
+ }
+ }
+ }
+}
+
+static void select_similar_layer(bArmature *arm, EditBone *ebone_act)
+{
+ EditBone *ebone;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ if (ebone->layer & ebone_act->layer) {
+ ED_armature_edit_bone_select(ebone);
+ }
+ }
+ }
+}
+
+static void select_similar_prefix(bArmature *arm, EditBone *ebone_act)
+{
+ EditBone *ebone;
+
+ char body_tmp[MAX_VGROUP_NAME];
+ char prefix_act[MAX_VGROUP_NAME];
+
+ BKE_deform_split_prefix(ebone_act->name, prefix_act, body_tmp);
+
+ if (prefix_act[0] == '\0')
+ return;
+
+ /* Find matches */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ char prefix_other[MAX_VGROUP_NAME];
+ BKE_deform_split_prefix(ebone->name, prefix_other, body_tmp);
+ if (!strcmp(prefix_act, prefix_other)) {
+ ED_armature_edit_bone_select(ebone);
+ }
+ }
+ }
+}
+
+static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
+{
+ EditBone *ebone;
+
+ char body_tmp[MAX_VGROUP_NAME];
+ char suffix_act[MAX_VGROUP_NAME];
+
+ BKE_deform_split_suffix(ebone_act->name, body_tmp, suffix_act);
+
+ if (suffix_act[0] == '\0')
+ return;
+
+ /* Find matches */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ char suffix_other[MAX_VGROUP_NAME];
+ BKE_deform_split_suffix(ebone->name, body_tmp, suffix_other);
+ if (!strcmp(suffix_act, suffix_other)) {
+ ED_armature_edit_bone_select(ebone);
+ }
+ }
+ }
+}
+
+static int armature_select_similar_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone_act = CTX_data_active_bone(C);
+
+ /* Get props */
+ int type = RNA_enum_get(op->ptr, "type");
+ float thresh = RNA_float_get(op->ptr, "threshold");
+
+ /* Check for active bone */
+ if (ebone_act == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
+ return OPERATOR_CANCELLED;
+ }
+
+ switch (type) {
+ case SIMEDBONE_LENGTH:
+ select_similar_length(arm, ebone_act, thresh);
+ break;
+ case SIMEDBONE_DIRECTION:
+ select_similar_direction(arm, ebone_act, thresh);
+ break;
+ case SIMEDBONE_PREFIX:
+ select_similar_prefix(arm, ebone_act);
+ break;
+ case SIMEDBONE_SUFFIX:
+ select_similar_suffix(arm, ebone_act);
+ break;
+ case SIMEDBONE_LAYER:
+ select_similar_layer(arm, ebone_act);
+ break;
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_select_similar(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Similar";
+ ot->idname = "ARMATURE_OT_select_similar";
+
+ /* callback functions */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_select_similar_exec;
+ ot->poll = ED_operator_editarmature;
+ ot->description = "Select similar bones by property types";
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, 0, "Type", "");
+ RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
+}
+
+/* ********************* select hierarchy operator ************** */
+
+/* Get the first available child of an editbone */
+static EditBone *editbone_get_child(bArmature *arm, EditBone *pabone, short use_visibility)
+{
+ EditBone *curbone, *chbone = NULL;
+
+ for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
+ if (curbone->parent == pabone) {
+ if (use_visibility) {
+ if ((arm->layer & curbone->layer) && !(pabone->flag & BONE_HIDDEN_A)) {
+ chbone = curbone;
+ }
+ }
+ else
+ chbone = curbone;
+ }
+ }
+
+ return chbone;
+}
+
+static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Object *ob;
+ bArmature *arm;
+ EditBone *curbone, *pabone, *chbone;
+ int direction = RNA_enum_get(op->ptr, "direction");
+ int add_to_sel = RNA_boolean_get(op->ptr, "extend");
+
+ ob = obedit;
+ arm = (bArmature *)ob->data;
+
+ for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
+ /* only work on bone if it is visible and its selection can change */
+ if (EBONE_SELECTABLE(arm, curbone)) {
+ if (curbone == arm->act_edbone) {
+ if (direction == BONE_SELECT_PARENT) {
+ if (curbone->parent == NULL) continue;
+ else pabone = curbone->parent;
+
+ if (EBONE_VISIBLE(arm, pabone)) {
+ pabone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_edbone = pabone;
+ if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL;
+
+ if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ }
+
+ }
+ else { // BONE_SELECT_CHILD
+ chbone = editbone_get_child(arm, curbone, 1);
+ if (chbone == NULL) continue;
+
+ if (EBONE_SELECTABLE(arm, chbone)) {
+ chbone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_edbone = chbone;
+
+ if (!add_to_sel) {
+ curbone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL);
+ if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_select_hierarchy(wmOperatorType *ot)
+{
+ static EnumPropertyItem direction_items[] = {
+ {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
+ {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Select Hierarchy";
+ ot->idname = "ARMATURE_OT_select_hierarchy";
+ ot->description = "Select immediate parent/children of selected bones";
+
+ /* api callbacks */
+ ot->exec = armature_select_hierarchy_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "direction", direction_items,
+ BONE_SELECT_PARENT, "Direction", "");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+}
+
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
new file mode 100644
index 00000000000..2e43c388fa8
--- /dev/null
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -0,0 +1,441 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * API's for creating vertex groups from bones
+ * - Interfaces with heat weighting in meshlaplacian
+ */
+
+/** \file blender/editors/armature/armature_skinning.c
+ * \ingroup edarmature
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_deform.h"
+#include "BKE_report.h"
+#include "BKE_subsurf.h"
+#include "BKE_modifier.h"
+
+#include "ED_armature.h"
+#include "ED_mesh.h"
+
+
+#include "armature_intern.h"
+#include "meshlaplacian.h"
+
+#if 0
+#include "reeb.h"
+#endif
+
+/* ********************************** Bone Skinning *********************************************** */
+
+static int bone_skinnable_cb(Object *ob, Bone *bone, void *datap)
+{
+ /* Bones that are deforming
+ * are regarded to be "skinnable" and are eligible for
+ * auto-skinning.
+ *
+ * This function performs 2 functions:
+ *
+ * a) It returns 1 if the bone is skinnable.
+ * If we loop over all bones with this
+ * function, we can count the number of
+ * skinnable bones.
+ * b) If the pointer data is non null,
+ * it is treated like a handle to a
+ * bone pointer -- the bone pointer
+ * is set to point at this bone, and
+ * the pointer the handle points to
+ * is incremented to point to the
+ * next member of an array of pointers
+ * to bones. This way we can loop using
+ * this function to construct an array of
+ * pointers to bones that point to all
+ * skinnable bones.
+ */
+ Bone ***hbone;
+ int a, segments;
+ struct { Object *armob; void *list; int heat; } *data = datap;
+
+ if (!(ob->mode & OB_MODE_WEIGHT_PAINT) || !(bone->flag & BONE_HIDDEN_P)) {
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name))
+ segments = bone->segments;
+ else
+ segments = 1;
+
+ if (data->list != NULL) {
+ hbone = (Bone ***) &data->list;
+
+ for (a = 0; a < segments; a++) {
+ **hbone = bone;
+ ++*hbone;
+ }
+ }
+ return segments;
+ }
+ }
+ return 0;
+}
+
+static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
+{
+ /* This group creates a vertex group to ob that has the
+ * same name as bone (provided the bone is skinnable).
+ * If such a vertex group aleady exist the routine exits.
+ */
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (!defgroup_find_name(ob, bone->name)) {
+ ED_vgroup_add_name(ob, bone->name);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
+{
+ /* Bones that are deforming
+ * are regarded to be "skinnable" and are eligible for
+ * auto-skinning.
+ *
+ * This function performs 2 functions:
+ *
+ * a) If the bone is skinnable, it creates
+ * a vertex group for ob that has
+ * the name of the skinnable bone
+ * (if one doesn't exist already).
+ * b) If the pointer data is non null,
+ * it is treated like a handle to a
+ * bDeformGroup pointer -- the
+ * bDeformGroup pointer is set to point
+ * to the deform group with the bone's
+ * name, and the pointer the handle
+ * points to is incremented to point to the
+ * next member of an array of pointers
+ * to bDeformGroups. This way we can loop using
+ * this function to construct an array of
+ * pointers to bDeformGroups, all with names
+ * of skinnable bones.
+ */
+ bDeformGroup ***hgroup, *defgroup = NULL;
+ int a, segments;
+ struct { Object *armob; void *list; int heat; } *data = datap;
+ int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
+ bArmature *arm = data->armob->data;
+
+ if (!wpmode || !(bone->flag & BONE_HIDDEN_P)) {
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name))
+ segments = bone->segments;
+ else
+ segments = 1;
+
+ if (!wpmode || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED)))
+ if (!(defgroup = defgroup_find_name(ob, bone->name)))
+ defgroup = ED_vgroup_add_name(ob, bone->name);
+
+ if (data->list != NULL) {
+ hgroup = (bDeformGroup ***) &data->list;
+
+ for (a = 0; a < segments; a++) {
+ **hgroup = defgroup;
+ ++*hgroup;
+ }
+ }
+ return segments;
+ }
+ }
+ return 0;
+}
+
+static void add_vgroups__mapFunc(void *userData, int index, const float co[3],
+ const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+{
+ /* DerivedMesh mapFunc for getting final coords in weight paint mode */
+
+ float (*verts)[3] = userData;
+ copy_v3_v3(verts[index], co);
+}
+
+static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist,
+ bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
+ float (*root)[3], float (*tip)[3], int *selected, float scale)
+{
+ /* Create vertex group weights from envelopes */
+
+ Bone *bone;
+ bDeformGroup *dgroup;
+ float distance;
+ int i, iflip, j;
+
+ /* for each vertex in the mesh */
+ for (i = 0; i < mesh->totvert; i++) {
+ iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i) : 0;
+
+ /* for each skinnable bone */
+ for (j = 0; j < numbones; ++j) {
+ if (!selected[j])
+ continue;
+
+ bone = bonelist[j];
+ dgroup = dgrouplist[j];
+
+ /* store the distance-factor from the vertex to the bone */
+ distance = distfactor_to_bone(verts[i], root[j], tip[j],
+ bone->rad_head * scale, bone->rad_tail * scale, bone->dist * scale);
+
+ /* add the vert to the deform group if (weight != 0.0) */
+ if (distance != 0.0f)
+ ED_vgroup_vert_add(ob, dgroup, i, distance, WEIGHT_REPLACE);
+ else
+ ED_vgroup_vert_remove(ob, dgroup, i);
+
+ /* do same for mirror */
+ if (dgroupflip && dgroupflip[j] && iflip >= 0) {
+ if (distance != 0.0f)
+ ED_vgroup_vert_add(ob, dgroupflip[j], iflip, distance,
+ WEIGHT_REPLACE);
+ else
+ ED_vgroup_vert_remove(ob, dgroupflip[j], iflip);
+ }
+ }
+ }
+}
+
+static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par, int heat, int mirror)
+{
+ /* This functions implements the automatic computation of vertex group
+ * weights, either through envelopes or using a heat equilibrium.
+ *
+ * This function can be called both when parenting a mesh to an armature,
+ * or in weightpaint + posemode. In the latter case selection is taken
+ * into account and vertex weights can be mirrored.
+ *
+ * The mesh vertex positions used are either the final deformed coords
+ * from the derivedmesh in weightpaint mode, the final subsurf coords
+ * when parenting, or simply the original mesh coords.
+ */
+
+ bArmature *arm = par->data;
+ Bone **bonelist, *bone;
+ bDeformGroup **dgrouplist, **dgroupflip;
+ bDeformGroup *dgroup;
+ bPoseChannel *pchan;
+ Mesh *mesh;
+ Mat4 *bbone = NULL;
+ float (*root)[3], (*tip)[3], (*verts)[3];
+ int *selected;
+ int numbones, vertsfilled = 0, i, j, segments = 0;
+ int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
+ struct { Object *armob; void *list; int heat; } looper_data;
+
+ looper_data.armob = par;
+ looper_data.heat = heat;
+ looper_data.list = NULL;
+
+ /* count the number of skinnable bones */
+ numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
+
+ if (numbones == 0)
+ return;
+
+ if (ED_vgroup_data_create(ob->data) == FALSE)
+ return;
+
+ /* create an array of pointer to bones that are skinnable
+ * and fill it with all of the skinnable bones */
+ bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist");
+ looper_data.list = bonelist;
+ bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
+
+ /* create an array of pointers to the deform groups that
+ * correspond to the skinnable bones (creating them
+ * as necessary. */
+ dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist");
+ dgroupflip = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgroupflip");
+
+ looper_data.list = dgrouplist;
+ bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb);
+
+ /* create an array of root and tip positions transformed into
+ * global coords */
+ root = MEM_callocN(numbones * sizeof(float) * 3, "root");
+ tip = MEM_callocN(numbones * sizeof(float) * 3, "tip");
+ selected = MEM_callocN(numbones * sizeof(int), "selected");
+
+ for (j = 0; j < numbones; ++j) {
+ bone = bonelist[j];
+ dgroup = dgrouplist[j];
+
+ /* handle bbone */
+ if (heat) {
+ if (segments == 0) {
+ segments = 1;
+ bbone = NULL;
+
+ if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) {
+ if (bone->segments > 1) {
+ segments = bone->segments;
+ bbone = b_bone_spline_setup(pchan, 1);
+ }
+ }
+ }
+
+ segments--;
+ }
+
+ /* compute root and tip */
+ if (bbone) {
+ mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
+ if ((segments + 1) < bone->segments) {
+ mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
+ }
+ else {
+ copy_v3_v3(tip[j], bone->arm_tail);
+ }
+ }
+ else {
+ copy_v3_v3(root[j], bone->arm_head);
+ copy_v3_v3(tip[j], bone->arm_tail);
+ }
+
+ mul_m4_v3(par->obmat, root[j]);
+ mul_m4_v3(par->obmat, tip[j]);
+
+ /* set selected */
+ if (wpmode) {
+ if ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))
+ selected[j] = 1;
+ }
+ else
+ selected[j] = 1;
+
+ /* find flipped group */
+ if (dgroup && mirror) {
+ char name[MAXBONENAME];
+
+ // 0 = don't strip off number extensions
+ flip_side_name(name, dgroup->name, FALSE);
+ dgroupflip[j] = defgroup_find_name(ob, name);
+ }
+ }
+
+ /* create verts */
+ mesh = (Mesh *)ob->data;
+ verts = MEM_callocN(mesh->totvert * sizeof(*verts), "closestboneverts");
+
+ if (wpmode) {
+ /* if in weight paint mode, use final verts from derivedmesh */
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+
+ if (dm->foreachMappedVert) {
+ dm->foreachMappedVert(dm, add_vgroups__mapFunc, (void *)verts);
+ vertsfilled = 1;
+ }
+
+ dm->release(dm);
+ }
+ else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
+ /* is subsurf on? Lets use the verts on the limit surface then.
+ * = same amount of vertices as mesh, but vertices moved to the
+ * subsurfed position, like for 'optimal'. */
+ subsurf_calculate_limit_positions(mesh, verts);
+ vertsfilled = 1;
+ }
+
+ /* transform verts to global space */
+ for (i = 0; i < mesh->totvert; i++) {
+ if (!vertsfilled)
+ copy_v3_v3(verts[i], mesh->mvert[i].co);
+ mul_m4_v3(ob->obmat, verts[i]);
+ }
+
+ /* compute the weights based on gathered vertices and bones */
+ if (heat) {
+ const char *error = NULL;
+ heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip,
+ root, tip, selected, &error);
+
+ if (error) {
+ BKE_report(reports, RPT_WARNING, error);
+ }
+ }
+ else {
+ envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist,
+ dgroupflip, root, tip, selected, mat4_to_scale(par->obmat));
+ }
+
+ /* only generated in some cases but can call anyway */
+ mesh_octree_table(ob, NULL, NULL, 'e');
+
+ /* free the memory allocated */
+ MEM_freeN(bonelist);
+ MEM_freeN(dgrouplist);
+ MEM_freeN(dgroupflip);
+ MEM_freeN(root);
+ MEM_freeN(tip);
+ MEM_freeN(selected);
+ MEM_freeN(verts);
+}
+
+void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par, int mode, int mirror)
+{
+ /* Lets try to create some vertex groups
+ * based on the bones of the parent armature.
+ */
+ bArmature *arm = par->data;
+
+ if (mode == ARM_GROUPS_NAME) {
+ const int defbase_tot = BLI_countlist(&ob->defbase);
+ int defbase_add;
+ /* Traverse the bone list, trying to create empty vertex
+ * groups corresponding to the bone.
+ */
+ defbase_add = bone_looper(ob, arm->bonebase.first, NULL, vgroup_add_unique_bone_cb);
+
+ if (defbase_add) {
+ /* its possible there are DWeight's outside the range of the current
+ * objects deform groups, in this case the new groups wont be empty [#33889] */
+ ED_vgroup_data_clamp_range(ob->data, defbase_tot);
+ }
+ }
+ else if (mode == ARM_GROUPS_ENVELOPE || mode == ARM_GROUPS_AUTO) {
+ /* Traverse the bone list, trying to create vertex groups
+ * that are populated with the vertices for which the
+ * bone is closest.
+ */
+ add_verts_to_dgroups(reports, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror);
+ }
+}
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
new file mode 100644
index 00000000000..05f48ad73f4
--- /dev/null
+++ b/source/blender/editors/armature/armature_utils.c
@@ -0,0 +1,671 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/armature/armature_utils.c
+ * \ingroup edarmature
+ */
+
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_armature.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_main.h"
+
+#include "ED_armature.h"
+#include "ED_util.h"
+
+#include "armature_intern.h"
+
+/* *************************************************************** */
+/* Validation */
+
+/* Sync selection to parent for connected children */
+void ED_armature_sync_selection(ListBase *edbo)
+{
+ EditBone *ebo;
+
+ for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ /* if bone is not selectable, we shouldn't alter this setting... */
+ if ((ebo->flag & BONE_UNSELECTABLE) == 0) {
+ if ((ebo->flag & BONE_CONNECTED) && (ebo->parent)) {
+ if (ebo->parent->flag & BONE_TIPSEL)
+ ebo->flag |= BONE_ROOTSEL;
+ else
+ ebo->flag &= ~BONE_ROOTSEL;
+ }
+
+ if ((ebo->flag & BONE_TIPSEL) && (ebo->flag & BONE_ROOTSEL))
+ ebo->flag |= BONE_SELECTED;
+ else
+ ebo->flag &= ~BONE_SELECTED;
+ }
+ }
+}
+
+void ED_armature_validate_active(struct bArmature *arm)
+{
+ EditBone *ebone = arm->act_edbone;
+
+ if (ebone) {
+ if (ebone->flag & BONE_HIDDEN_A)
+ arm->act_edbone = NULL;
+ }
+}
+
+/* *************************************************************** */
+/* Bone Operations */
+
+/* XXX bone_looper is only to be used when we want to access settings
+ * (i.e. editability/visibility/selected) that context doesn't offer */
+int bone_looper(Object *ob, Bone *bone, void *data,
+ int (*bone_func)(Object *, Bone *, void *))
+{
+ /* We want to apply the function bone_func to every bone
+ * in an armature -- feed bone_looper the first bone and
+ * a pointer to the bone_func and watch it go!. The int count
+ * can be useful for counting bones with a certain property
+ * (e.g. skinnable)
+ */
+ int count = 0;
+
+ if (bone) {
+ /* only do bone_func if the bone is non null */
+ count += bone_func(ob, bone, data);
+
+ /* try to execute bone_func for the first child */
+ count += bone_looper(ob, bone->childbase.first, data, bone_func);
+
+ /* try to execute bone_func for the next bone at this
+ * depth of the recursion.
+ */
+ count += bone_looper(ob, bone->next, data, bone_func);
+ }
+
+ return count;
+}
+
+/* *************************************************************** */
+/* Bone Removal */
+
+void bone_free(bArmature *arm, EditBone *bone)
+{
+ if (arm->act_edbone == bone)
+ arm->act_edbone = NULL;
+
+ if (bone->prop) {
+ IDP_FreeProperty(bone->prop);
+ MEM_freeN(bone->prop);
+ }
+
+ BLI_freelinkN(arm->edbo, bone);
+}
+
+void ED_armature_edit_bone_remove(bArmature *arm, EditBone *exBone)
+{
+ EditBone *curBone;
+
+ /* Find any bones that refer to this bone */
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (curBone->parent == exBone) {
+ curBone->parent = exBone->parent;
+ curBone->flag &= ~BONE_CONNECTED;
+ }
+ }
+
+ bone_free(arm, exBone);
+}
+
+/* *************************************************************** */
+/* Mirroring */
+
+/* context: editmode armature */
+EditBone *ED_armature_bone_get_mirrored(ListBase *edbo, EditBone *ebo)
+{
+ EditBone *eboflip = NULL;
+ char name[MAXBONENAME];
+
+ if (ebo == NULL)
+ return NULL;
+
+ flip_side_name(name, ebo->name, FALSE);
+
+ for (eboflip = edbo->first; eboflip; eboflip = eboflip->next) {
+ if (ebo != eboflip) {
+ if (!strcmp(name, eboflip->name))
+ break;
+ }
+ }
+
+ return eboflip;
+}
+
+/* ------------------------------------- */
+
+/* helper function for tools to work on mirrored parts.
+ * it leaves mirrored bones selected then too, which is a good indication of what happened */
+void armature_select_mirrored(bArmature *arm)
+{
+ /* Select mirrored bones */
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *curBone, *ebone_mirr;
+
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (arm->layer & curBone->layer) {
+ if (curBone->flag & BONE_SELECTED) {
+ ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
+ if (ebone_mirr)
+ ebone_mirr->flag |= BONE_SELECTED;
+ }
+ }
+ }
+ }
+
+}
+
+void armature_tag_select_mirrored(bArmature *arm)
+{
+ EditBone *curBone;
+
+ /* always untag */
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ curBone->flag &= ~BONE_DONE;
+ }
+
+ /* Select mirrored bones */
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (arm->layer & curBone->layer) {
+ if (curBone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
+ EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
+ if (ebone_mirr && (ebone_mirr->flag & BONE_SELECTED) == 0) {
+ ebone_mirr->flag |= BONE_DONE;
+ }
+ }
+ }
+ }
+
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (curBone->flag & BONE_DONE) {
+ EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
+ curBone->flag |= ebone_mirr->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+ }
+ }
+ }
+}
+
+/* only works when tagged */
+void armature_tag_unselect(bArmature *arm)
+{
+ EditBone *curBone;
+
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (curBone->flag & BONE_DONE) {
+ curBone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL | BONE_DONE);
+ }
+ }
+}
+
+/* ------------------------------------- */
+
+/* if editbone (partial) selected, copy data */
+/* context; editmode armature, with mirror editing enabled */
+void transform_armature_mirror_update(Object *obedit)
+{
+ bArmature *arm = obedit->data;
+ EditBone *ebo, *eboflip;
+
+ for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ /* no layer check, correct mirror is more important */
+ if (ebo->flag & (BONE_TIPSEL | BONE_ROOTSEL)) {
+ eboflip = ED_armature_bone_get_mirrored(arm->edbo, ebo);
+
+ if (eboflip) {
+ /* we assume X-axis flipping for now */
+ if (ebo->flag & BONE_TIPSEL) {
+ EditBone *children;
+
+ eboflip->tail[0] = -ebo->tail[0];
+ eboflip->tail[1] = ebo->tail[1];
+ eboflip->tail[2] = ebo->tail[2];
+ eboflip->rad_tail = ebo->rad_tail;
+ eboflip->roll = -ebo->roll;
+
+ /* Also move connected children, in case children's name aren't mirrored properly */
+ for (children = arm->edbo->first; children; children = children->next) {
+ if (children->parent == eboflip && children->flag & BONE_CONNECTED) {
+ copy_v3_v3(children->head, eboflip->tail);
+ children->rad_head = ebo->rad_tail;
+ }
+ }
+ }
+ if (ebo->flag & BONE_ROOTSEL) {
+ eboflip->head[0] = -ebo->head[0];
+ eboflip->head[1] = ebo->head[1];
+ eboflip->head[2] = ebo->head[2];
+ eboflip->rad_head = ebo->rad_head;
+ eboflip->roll = -ebo->roll;
+
+ /* Also move connected parent, in case parent's name isn't mirrored properly */
+ if (eboflip->parent && eboflip->flag & BONE_CONNECTED) {
+ EditBone *parent = eboflip->parent;
+ copy_v3_v3(parent->tail, eboflip->head);
+ parent->rad_tail = ebo->rad_head;
+ }
+ }
+ if (ebo->flag & BONE_SELECTED) {
+ eboflip->dist = ebo->dist;
+ eboflip->roll = -ebo->roll;
+ eboflip->xwidth = ebo->xwidth;
+ eboflip->zwidth = ebo->zwidth;
+ }
+ }
+ }
+ }
+}
+
+/* *************************************************************** */
+/* Armature EditMode Conversions */
+
+/* converts Bones to EditBone list, used for tools as well */
+EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone *actBone)
+{
+ EditBone *eBone;
+ EditBone *eBoneAct = NULL;
+ EditBone *eBoneTest = NULL;
+ Bone *curBone;
+
+ for (curBone = bones->first; curBone; curBone = curBone->next) {
+ eBone = MEM_callocN(sizeof(EditBone), "make_editbone");
+
+ /* Copy relevant data from bone to eBone */
+ eBone->parent = parent;
+ BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name));
+ eBone->flag = curBone->flag;
+
+ /* fix selection flags */
+ if (eBone->flag & BONE_SELECTED) {
+ /* if the bone is selected the copy its root selection to the parents tip */
+ eBone->flag |= BONE_TIPSEL;
+ if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
+ eBone->parent->flag |= BONE_TIPSEL;
+ eBone->flag &= ~BONE_ROOTSEL; /* this is ignored when there is a connected parent, so unset it */
+ }
+ else {
+ eBone->flag |= BONE_ROOTSEL;
+ }
+ }
+ else {
+ /* if the bone is not selected, but connected to its parent
+ * copy the parents tip selection state */
+ if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
+ /* selecting with the mouse gives this behavior */
+ if (eBone->parent->flag & BONE_TIPSEL) {
+ eBone->flag |= BONE_ROOTSEL;
+ }
+ else {
+ eBone->flag &= ~BONE_ROOTSEL;
+ }
+
+ /* probably not selected but just in case */
+ eBone->flag &= ~BONE_TIPSEL;
+ }
+ }
+
+ copy_v3_v3(eBone->head, curBone->arm_head);
+ copy_v3_v3(eBone->tail, curBone->arm_tail);
+ eBone->roll = curBone->arm_roll;
+
+ /* rest of stuff copy */
+ eBone->length = curBone->length;
+ eBone->dist = curBone->dist;
+ eBone->weight = curBone->weight;
+ eBone->xwidth = curBone->xwidth;
+ eBone->zwidth = curBone->zwidth;
+ eBone->ease1 = curBone->ease1;
+ eBone->ease2 = curBone->ease2;
+ eBone->rad_head = curBone->rad_head;
+ eBone->rad_tail = curBone->rad_tail;
+ eBone->segments = curBone->segments;
+ eBone->layer = curBone->layer;
+
+ if (curBone->prop)
+ eBone->prop = IDP_CopyProperty(curBone->prop);
+
+ BLI_addtail(edbo, eBone);
+
+ /* Add children if necessary */
+ if (curBone->childbase.first) {
+ eBoneTest = make_boneList(edbo, &curBone->childbase, eBone, actBone);
+ if (eBoneTest)
+ eBoneAct = eBoneTest;
+ }
+
+ if (curBone == actBone)
+ eBoneAct = eBone;
+ }
+
+ return eBoneAct;
+}
+
+/* nasty stuff for converting roll in editbones into bones */
+/* also sets restposition in armature (arm_mat) */
+static void fix_bonelist_roll(ListBase *bonelist, ListBase *editbonelist)
+{
+ Bone *curBone;
+ EditBone *ebone;
+ float premat[3][3];
+ float postmat[3][3];
+ float difmat[3][3];
+ float imat[3][3];
+ float delta[3];
+
+ for (curBone = bonelist->first; curBone; curBone = curBone->next) {
+ /* sets local matrix and arm_mat (restpos) */
+ BKE_armature_where_is_bone(curBone, curBone->parent);
+
+ /* Find the associated editbone */
+ for (ebone = editbonelist->first; ebone; ebone = ebone->next)
+ if ((Bone *)ebone->temp == curBone)
+ break;
+
+ if (ebone) {
+ /* Get the ebone premat */
+ sub_v3_v3v3(delta, ebone->tail, ebone->head);
+ vec_roll_to_mat3(delta, ebone->roll, premat);
+
+ /* Get the bone postmat */
+ copy_m3_m4(postmat, curBone->arm_mat);
+
+ invert_m3_m3(imat, premat);
+ mul_m3_m3m3(difmat, imat, postmat);
+#if 0
+ printf("Bone %s\n", curBone->name);
+ print_m4("premat", premat);
+ print_m4("postmat", postmat);
+ print_m4("difmat", difmat);
+ printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2])));
+#endif
+ curBone->roll = (float)-atan2(difmat[2][0], difmat[2][2]);
+
+ /* and set restposition again */
+ BKE_armature_where_is_bone(curBone, curBone->parent);
+ }
+ fix_bonelist_roll(&curBone->childbase, editbonelist);
+ }
+}
+
+/* put EditMode back in Object */
+void ED_armature_from_edit(Object *obedit)
+{
+ bArmature *arm = obedit->data;
+ EditBone *eBone, *neBone;
+ Bone *newBone;
+ Object *obt;
+
+ /* armature bones */
+ BKE_armature_bonelist_free(&arm->bonebase);
+
+ /* remove zero sized bones, this gives instable restposes */
+ for (eBone = arm->edbo->first; eBone; eBone = neBone) {
+ float len = len_v3v3(eBone->head, eBone->tail);
+ neBone = eBone->next;
+ if (len <= 0.000001f) { /* FLT_EPSILON is too large? */
+ EditBone *fBone;
+
+ /* Find any bones that refer to this bone */
+ for (fBone = arm->edbo->first; fBone; fBone = fBone->next) {
+ if (fBone->parent == eBone)
+ fBone->parent = eBone->parent;
+ }
+ if (G.debug & G_DEBUG)
+ printf("Warning: removed zero sized bone: %s\n", eBone->name);
+ bone_free(arm, eBone);
+ }
+ }
+
+ /* Copy the bones from the editData into the armature */
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ newBone = MEM_callocN(sizeof(Bone), "bone");
+ eBone->temp = newBone; /* Associate the real Bones with the EditBones */
+
+ BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name));
+ copy_v3_v3(newBone->arm_head, eBone->head);
+ copy_v3_v3(newBone->arm_tail, eBone->tail);
+ newBone->arm_roll = eBone->roll;
+
+ newBone->flag = eBone->flag;
+
+ if (eBone == arm->act_edbone) {
+ /* don't change active selection, this messes up separate which uses
+ * editmode toggle and can separate active bone which is de-selected originally */
+ /* newBone->flag |= BONE_SELECTED; */ /* important, editbones can be active with only 1 point selected */
+ arm->act_edbone = NULL;
+ arm->act_bone = newBone;
+ }
+ newBone->roll = 0.0f;
+
+ newBone->weight = eBone->weight;
+ newBone->dist = eBone->dist;
+
+ newBone->xwidth = eBone->xwidth;
+ newBone->zwidth = eBone->zwidth;
+ newBone->ease1 = eBone->ease1;
+ newBone->ease2 = eBone->ease2;
+ newBone->rad_head = eBone->rad_head;
+ newBone->rad_tail = eBone->rad_tail;
+ newBone->segments = eBone->segments;
+ newBone->layer = eBone->layer;
+
+ if (eBone->prop)
+ newBone->prop = IDP_CopyProperty(eBone->prop);
+ }
+
+ /* Fix parenting in a separate pass to ensure ebone->bone connections
+ * are valid at this point */
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ newBone = (Bone *)eBone->temp;
+ if (eBone->parent) {
+ newBone->parent = (Bone *)eBone->parent->temp;
+ BLI_addtail(&newBone->parent->childbase, newBone);
+
+ {
+ float M_parentRest[3][3];
+ float iM_parentRest[3][3];
+ float delta[3];
+
+ /* Get the parent's matrix (rotation only) */
+ sub_v3_v3v3(delta, eBone->parent->tail, eBone->parent->head);
+ vec_roll_to_mat3(delta, eBone->parent->roll, M_parentRest);
+
+ /* Invert the parent matrix */
+ invert_m3_m3(iM_parentRest, M_parentRest);
+
+ /* Get the new head and tail */
+ sub_v3_v3v3(newBone->head, eBone->head, eBone->parent->tail);
+ sub_v3_v3v3(newBone->tail, eBone->tail, eBone->parent->tail);
+
+ mul_m3_v3(iM_parentRest, newBone->head);
+ mul_m3_v3(iM_parentRest, newBone->tail);
+ }
+ }
+ /* ...otherwise add this bone to the armature's bonebase */
+ else {
+ copy_v3_v3(newBone->head, eBone->head);
+ copy_v3_v3(newBone->tail, eBone->tail);
+ BLI_addtail(&arm->bonebase, newBone);
+ }
+ }
+
+ /* Make a pass through the new armature to fix rolling */
+ /* also builds restposition again (like BKE_armature_where_is) */
+ fix_bonelist_roll(&arm->bonebase, arm->edbo);
+
+ /* so all users of this armature should get rebuilt */
+ for (obt = G.main->object.first; obt; obt = obt->id.next) {
+ if (obt->data == arm)
+ BKE_pose_rebuild(obt, arm);
+ }
+
+ DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+}
+
+void ED_armature_edit_free(struct Object *ob)
+{
+ bArmature *arm = ob->data;
+ EditBone *eBone;
+
+ /* Clear the editbones list */
+ if (arm->edbo) {
+ if (arm->edbo->first) {
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ if (eBone->prop) {
+ IDP_FreeProperty(eBone->prop);
+ MEM_freeN(eBone->prop);
+ }
+ }
+
+ BLI_freelistN(arm->edbo);
+ }
+ MEM_freeN(arm->edbo);
+ arm->edbo = NULL;
+ }
+}
+
+/* Put armature in EditMode */
+void ED_armature_to_edit(Object *ob)
+{
+ bArmature *arm = ob->data;
+
+ ED_armature_edit_free(ob);
+ arm->edbo = MEM_callocN(sizeof(ListBase), "edbo armature");
+ arm->act_edbone = make_boneList(arm->edbo, &arm->bonebase, NULL, arm->act_bone);
+ arm->act_bone = NULL;
+
+// BIF_freeTemplates(); /* force template update when entering editmode */
+}
+
+/* *************************************************************** */
+/* Undo for Armature EditMode*/
+
+typedef struct UndoArmature {
+ EditBone *act_edbone;
+ ListBase lb;
+} UndoArmature;
+
+static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data))
+{
+ UndoArmature *uarm = uarmv;
+ bArmature *arm = armv;
+ EditBone *ebo, *newebo;
+
+ BLI_freelistN(arm->edbo);
+
+ /* copy */
+ for (ebo = uarm->lb.first; ebo; ebo = ebo->next) {
+ newebo = MEM_dupallocN(ebo);
+ ebo->temp = newebo;
+ BLI_addtail(arm->edbo, newebo);
+ }
+
+ /* active bone */
+ if (uarm->act_edbone) {
+ ebo = uarm->act_edbone;
+ arm->act_edbone = ebo->temp;
+ }
+ else
+ arm->act_edbone = NULL;
+
+ /* set pointers */
+ for (newebo = arm->edbo->first; newebo; newebo = newebo->next) {
+ if (newebo->parent) newebo->parent = newebo->parent->temp;
+ }
+ /* be sure they don't hang ever */
+ for (newebo = arm->edbo->first; newebo; newebo = newebo->next) {
+ newebo->temp = NULL;
+ }
+}
+
+static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata))
+{
+ bArmature *arm = armv;
+ UndoArmature *uarm;
+ EditBone *ebo, *newebo;
+
+ uarm = MEM_callocN(sizeof(UndoArmature), "listbase undo");
+
+ /* copy */
+ for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ newebo = MEM_dupallocN(ebo);
+ ebo->temp = newebo;
+ BLI_addtail(&uarm->lb, newebo);
+ }
+
+ /* active bone */
+ if (arm->act_edbone) {
+ ebo = arm->act_edbone;
+ uarm->act_edbone = ebo->temp;
+ }
+
+ /* set pointers */
+ for (newebo = uarm->lb.first; newebo; newebo = newebo->next) {
+ if (newebo->parent) newebo->parent = newebo->parent->temp;
+ }
+
+ return uarm;
+}
+
+static void free_undoBones(void *uarmv)
+{
+ UndoArmature *uarm = uarmv;
+
+ BLI_freelistN(&uarm->lb);
+ MEM_freeN(uarm);
+}
+
+static void *get_armature_edit(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && obedit->type == OB_ARMATURE) {
+ return obedit->data;
+ }
+ return NULL;
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_armature(bContext *C, const char *name)
+{
+ // XXX solve getdata()
+ undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
+}
diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c
deleted file mode 100644
index 2eac6ba87ee..00000000000
--- a/source/blender/editors/armature/editarmature.c
+++ /dev/null
@@ -1,6197 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): Blender Foundation, 2002-2009 full recode.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/armature/editarmature.c
- * \ingroup edarmature
- */
-
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <math.h>
-#include <float.h>
-#include <assert.h>
-
-
-#include "DNA_anim_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-
-#include "BKE_animsys.h"
-#include "BKE_action.h"
-#include "BKE_armature.h"
-#include "BKE_constraint.h"
-#include "BKE_context.h"
-#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_global.h"
-#include "BKE_idprop.h"
-#include "BKE_main.h"
-#include "BKE_object.h"
-#include "BKE_report.h"
-#include "BKE_subsurf.h"
-#include "BKE_modifier.h"
-#include "DNA_object_types.h"
-
-#include "BIF_gl.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_armature.h"
-#include "ED_keyframing.h"
-#include "ED_mesh.h"
-#include "ED_object.h"
-#include "ED_screen.h"
-#include "ED_util.h"
-#include "ED_view3d.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "armature_intern.h"
-#include "meshlaplacian.h"
-
-#if 0
-#include "reeb.h"
-#endif
-
-/* **************** tools on Editmode Armature **************** */
-
-/* Sync selection to parent for connected children */
-void ED_armature_sync_selection(ListBase *edbo)
-{
- EditBone *ebo;
-
- for (ebo = edbo->first; ebo; ebo = ebo->next) {
- /* if bone is not selectable, we shouldn't alter this setting... */
- if ((ebo->flag & BONE_UNSELECTABLE) == 0) {
- if ((ebo->flag & BONE_CONNECTED) && (ebo->parent)) {
- if (ebo->parent->flag & BONE_TIPSEL)
- ebo->flag |= BONE_ROOTSEL;
- else
- ebo->flag &= ~BONE_ROOTSEL;
- }
-
- if ((ebo->flag & BONE_TIPSEL) && (ebo->flag & BONE_ROOTSEL))
- ebo->flag |= BONE_SELECTED;
- else
- ebo->flag &= ~BONE_SELECTED;
- }
- }
-}
-
-void ED_armature_validate_active(struct bArmature *arm)
-{
- EditBone *ebone = arm->act_edbone;
-
- if (ebone) {
- if (ebone->flag & BONE_HIDDEN_A)
- arm->act_edbone = NULL;
- }
-}
-
-static void bone_free(bArmature *arm, EditBone *bone)
-{
- if (arm->act_edbone == bone)
- arm->act_edbone = NULL;
-
- if (bone->prop) {
- IDP_FreeProperty(bone->prop);
- MEM_freeN(bone->prop);
- }
-
- BLI_freelinkN(arm->edbo, bone);
-}
-
-void ED_armature_edit_bone_remove(bArmature *arm, EditBone *exBone)
-{
- EditBone *curBone;
-
- /* Find any bones that refer to this bone */
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (curBone->parent == exBone) {
- curBone->parent = exBone->parent;
- curBone->flag &= ~BONE_CONNECTED;
- }
- }
-
- bone_free(arm, exBone);
-}
-
-/* context: editmode armature */
-EditBone *ED_armature_bone_get_mirrored(ListBase *edbo, EditBone *ebo)
-{
- EditBone *eboflip = NULL;
- char name[MAXBONENAME];
-
- if (ebo == NULL)
- return NULL;
-
- flip_side_name(name, ebo->name, FALSE);
-
- for (eboflip = edbo->first; eboflip; eboflip = eboflip->next) {
- if (ebo != eboflip) {
- if (!strcmp(name, eboflip->name))
- break;
- }
- }
-
- return eboflip;
-}
-
-/* helper function for tools to work on mirrored parts.
- * it leaves mirrored bones selected then too, which is a good indication of what happened */
-static void armature_select_mirrored(bArmature *arm)
-{
- /* Select mirrored bones */
- if (arm->flag & ARM_MIRROR_EDIT) {
- EditBone *curBone, *ebone_mirr;
-
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (arm->layer & curBone->layer) {
- if (curBone->flag & BONE_SELECTED) {
- ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
- if (ebone_mirr)
- ebone_mirr->flag |= BONE_SELECTED;
- }
- }
- }
- }
-
-}
-
-static void armature_tag_select_mirrored(bArmature *arm)
-{
- EditBone *curBone;
-
- /* always untag */
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- curBone->flag &= ~BONE_DONE;
- }
-
- /* Select mirrored bones */
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (arm->layer & curBone->layer) {
- if (curBone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
- EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
- if (ebone_mirr && (ebone_mirr->flag & BONE_SELECTED) == 0) {
- ebone_mirr->flag |= BONE_DONE;
- }
- }
- }
- }
-
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (curBone->flag & BONE_DONE) {
- EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
- curBone->flag |= ebone_mirr->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
- }
- }
- }
-}
-
-
-/* only works when tagged */
-static void armature_tag_unselect(bArmature *arm)
-{
- EditBone *curBone;
-
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (curBone->flag & BONE_DONE) {
- curBone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL | BONE_DONE);
- }
- }
-}
-
-/* converts Bones to EditBone list, used for tools as well */
-EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone *actBone)
-{
- EditBone *eBone;
- EditBone *eBoneAct = NULL;
- EditBone *eBoneTest = NULL;
- Bone *curBone;
-
- for (curBone = bones->first; curBone; curBone = curBone->next) {
- eBone = MEM_callocN(sizeof(EditBone), "make_editbone");
-
- /* Copy relevant data from bone to eBone */
- eBone->parent = parent;
- BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name));
- eBone->flag = curBone->flag;
-
- /* fix selection flags */
-
- if (eBone->flag & BONE_SELECTED) {
- /* if the bone is selected the copy its root selection to the parents tip */
- eBone->flag |= BONE_TIPSEL;
- if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
- eBone->parent->flag |= BONE_TIPSEL;
- eBone->flag &= ~BONE_ROOTSEL; /* this is ignored when there is a connected parent, so unset it */
- }
- else {
- eBone->flag |= BONE_ROOTSEL;
- }
- }
- else {
- /* if the bone is not selected, but connected to its parent
- * copy the parents tip selection state */
- if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
- /* selecting with the mouse gives this behavior */
- if (eBone->parent->flag & BONE_TIPSEL) {
- eBone->flag |= BONE_ROOTSEL;
- }
- else {
- eBone->flag &= ~BONE_ROOTSEL;
- }
-
- /* probably not selected but just in case */
- eBone->flag &= ~BONE_TIPSEL;
- }
- }
-
- copy_v3_v3(eBone->head, curBone->arm_head);
- copy_v3_v3(eBone->tail, curBone->arm_tail);
- eBone->roll = curBone->arm_roll;
-
- /* rest of stuff copy */
- eBone->length = curBone->length;
- eBone->dist = curBone->dist;
- eBone->weight = curBone->weight;
- eBone->xwidth = curBone->xwidth;
- eBone->zwidth = curBone->zwidth;
- eBone->ease1 = curBone->ease1;
- eBone->ease2 = curBone->ease2;
- eBone->rad_head = curBone->rad_head;
- eBone->rad_tail = curBone->rad_tail;
- eBone->segments = curBone->segments;
- eBone->layer = curBone->layer;
-
- if (curBone->prop)
- eBone->prop = IDP_CopyProperty(curBone->prop);
-
- BLI_addtail(edbo, eBone);
-
- /* Add children if necessary */
- if (curBone->childbase.first) {
- eBoneTest = make_boneList(edbo, &curBone->childbase, eBone, actBone);
- if (eBoneTest)
- eBoneAct = eBoneTest;
- }
-
- if (curBone == actBone)
- eBoneAct = eBone;
- }
-
- return eBoneAct;
-}
-
-/* nasty stuff for converting roll in editbones into bones */
-/* also sets restposition in armature (arm_mat) */
-static void fix_bonelist_roll(ListBase *bonelist, ListBase *editbonelist)
-{
- Bone *curBone;
- EditBone *ebone;
- float premat[3][3];
- float postmat[3][3];
- float difmat[3][3];
- float imat[3][3];
- float delta[3];
-
- for (curBone = bonelist->first; curBone; curBone = curBone->next) {
- /* sets local matrix and arm_mat (restpos) */
- BKE_armature_where_is_bone(curBone, curBone->parent);
-
- /* Find the associated editbone */
- for (ebone = editbonelist->first; ebone; ebone = ebone->next)
- if ((Bone *)ebone->temp == curBone)
- break;
-
- if (ebone) {
- /* Get the ebone premat */
- sub_v3_v3v3(delta, ebone->tail, ebone->head);
- vec_roll_to_mat3(delta, ebone->roll, premat);
-
- /* Get the bone postmat */
- copy_m3_m4(postmat, curBone->arm_mat);
-
- invert_m3_m3(imat, premat);
- mul_m3_m3m3(difmat, imat, postmat);
-#if 0
- printf("Bone %s\n", curBone->name);
- print_m4("premat", premat);
- print_m4("postmat", postmat);
- print_m4("difmat", difmat);
- printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2])));
-#endif
- curBone->roll = (float)-atan2(difmat[2][0], difmat[2][2]);
-
- /* and set restposition again */
- BKE_armature_where_is_bone(curBone, curBone->parent);
- }
- fix_bonelist_roll(&curBone->childbase, editbonelist);
- }
-}
-
-/* put EditMode back in Object */
-void ED_armature_from_edit(Object *obedit)
-{
- bArmature *arm = obedit->data;
- EditBone *eBone, *neBone;
- Bone *newBone;
- Object *obt;
-
- /* armature bones */
- BKE_armature_bonelist_free(&arm->bonebase);
-
- /* remove zero sized bones, this gives instable restposes */
- for (eBone = arm->edbo->first; eBone; eBone = neBone) {
- float len = len_v3v3(eBone->head, eBone->tail);
- neBone = eBone->next;
- if (len <= 0.000001f) { /* FLT_EPSILON is too large? */
- EditBone *fBone;
-
- /* Find any bones that refer to this bone */
- for (fBone = arm->edbo->first; fBone; fBone = fBone->next) {
- if (fBone->parent == eBone)
- fBone->parent = eBone->parent;
- }
- if (G.debug & G_DEBUG)
- printf("Warning: removed zero sized bone: %s\n", eBone->name);
- bone_free(arm, eBone);
- }
- }
-
- /* Copy the bones from the editData into the armature */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- newBone = MEM_callocN(sizeof(Bone), "bone");
- eBone->temp = newBone; /* Associate the real Bones with the EditBones */
-
- BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name));
- copy_v3_v3(newBone->arm_head, eBone->head);
- copy_v3_v3(newBone->arm_tail, eBone->tail);
- newBone->arm_roll = eBone->roll;
-
- newBone->flag = eBone->flag;
-
- if (eBone == arm->act_edbone) {
- /* don't change active selection, this messes up separate which uses
- * editmode toggle and can separate active bone which is de-selected originally */
- /* newBone->flag |= BONE_SELECTED; */ /* important, editbones can be active with only 1 point selected */
- arm->act_edbone = NULL;
- arm->act_bone = newBone;
- }
- newBone->roll = 0.0f;
-
- newBone->weight = eBone->weight;
- newBone->dist = eBone->dist;
-
- newBone->xwidth = eBone->xwidth;
- newBone->zwidth = eBone->zwidth;
- newBone->ease1 = eBone->ease1;
- newBone->ease2 = eBone->ease2;
- newBone->rad_head = eBone->rad_head;
- newBone->rad_tail = eBone->rad_tail;
- newBone->segments = eBone->segments;
- newBone->layer = eBone->layer;
-
- if (eBone->prop)
- newBone->prop = IDP_CopyProperty(eBone->prop);
- }
-
- /* Fix parenting in a separate pass to ensure ebone->bone connections
- * are valid at this point */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- newBone = (Bone *)eBone->temp;
- if (eBone->parent) {
- newBone->parent = (Bone *)eBone->parent->temp;
- BLI_addtail(&newBone->parent->childbase, newBone);
-
- {
- float M_parentRest[3][3];
- float iM_parentRest[3][3];
- float delta[3];
-
- /* Get the parent's matrix (rotation only) */
- sub_v3_v3v3(delta, eBone->parent->tail, eBone->parent->head);
- vec_roll_to_mat3(delta, eBone->parent->roll, M_parentRest);
-
- /* Invert the parent matrix */
- invert_m3_m3(iM_parentRest, M_parentRest);
-
- /* Get the new head and tail */
- sub_v3_v3v3(newBone->head, eBone->head, eBone->parent->tail);
- sub_v3_v3v3(newBone->tail, eBone->tail, eBone->parent->tail);
-
- mul_m3_v3(iM_parentRest, newBone->head);
- mul_m3_v3(iM_parentRest, newBone->tail);
- }
- }
- /* ...otherwise add this bone to the armature's bonebase */
- else {
- copy_v3_v3(newBone->head, eBone->head);
- copy_v3_v3(newBone->tail, eBone->tail);
- BLI_addtail(&arm->bonebase, newBone);
- }
- }
-
- /* Make a pass through the new armature to fix rolling */
- /* also builds restposition again (like BKE_armature_where_is) */
- fix_bonelist_roll(&arm->bonebase, arm->edbo);
-
- /* so all users of this armature should get rebuilt */
- for (obt = G.main->object.first; obt; obt = obt->id.next) {
- if (obt->data == arm)
- BKE_pose_rebuild(obt, arm);
- }
-
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
-}
-
-void ED_armature_apply_transform(Object *ob, float mat[4][4])
-{
- EditBone *ebone;
- bArmature *arm = ob->data;
- float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */
- float mat3[3][3];
-
- copy_m3_m4(mat3, mat);
- normalize_m3(mat3);
-
- /* Put the armature into editmode */
- ED_armature_to_edit(ob);
-
- /* Do the rotations */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- float delta[3], tmat[3][3];
-
- /* find the current bone's roll matrix */
- sub_v3_v3v3(delta, ebone->tail, ebone->head);
- vec_roll_to_mat3(delta, ebone->roll, tmat);
-
- /* transform the roll matrix */
- mul_m3_m3m3(tmat, mat3, tmat);
-
- /* transform the bone */
- mul_m4_v3(mat, ebone->head);
- mul_m4_v3(mat, ebone->tail);
-
- /* apply the transfiormed roll back */
- mat3_to_vec_roll(tmat, NULL, &ebone->roll);
-
- ebone->rad_head *= scale;
- ebone->rad_tail *= scale;
- ebone->dist *= scale;
-
- /* we could be smarter and scale by the matrix along the x & z axis */
- ebone->xwidth *= scale;
- ebone->zwidth *= scale;
- }
-
- /* Turn the list into an armature */
- ED_armature_from_edit(ob);
- ED_armature_edit_free(ob);
-}
-
-/* exported for use in editors/object/ */
-/* 0 == do center, 1 == center new, 2 == center cursor */
-void docenter_armature(Scene *scene, Object *ob, float cursor[3], int centermode, int around)
-{
- Object *obedit = scene->obedit; // XXX get from context
- EditBone *ebone;
- bArmature *arm = ob->data;
- float cent[3];
-
- /* Put the armature into editmode */
- if (ob != obedit) {
- ED_armature_to_edit(ob);
- obedit = NULL; /* we cant use this so behave as if there is no obedit */
- }
-
- /* Find the centerpoint */
- if (centermode == 2) {
- copy_v3_v3(cent, cursor);
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_v3(ob->imat, cent);
- }
- else {
- if (around == V3D_CENTROID) {
- int total = 0;
- zero_v3(cent);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- total += 2;
- add_v3_v3(cent, ebone->head);
- add_v3_v3(cent, ebone->tail);
- }
- if (total) {
- mul_v3_fl(cent, 1.0f / (float)total);
- }
- }
- else {
- float min[3], max[3];
- INIT_MINMAX(min, max);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- minmax_v3v3_v3(min, max, ebone->head);
- minmax_v3v3_v3(min, max, ebone->tail);
- }
- mid_v3_v3v3(cent, min, max);
- }
- }
-
- /* Do the adjustments */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- sub_v3_v3(ebone->head, cent);
- sub_v3_v3(ebone->tail, cent);
- }
-
- /* Turn the list into an armature */
- if (obedit == NULL) {
- ED_armature_from_edit(ob);
- ED_armature_edit_free(ob);
- }
-
- /* Adjust object location for new centerpoint */
- if (centermode && obedit == NULL) {
- mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */
- add_v3_v3(ob->loc, cent);
- }
-}
-
-/* ---------------------- */
-
-/* checks if an EditBone with a matching name already, returning the matching bone if it exists */
-static EditBone *editbone_name_exists(ListBase *edbo, const char *name)
-{
- return BLI_findstring(edbo, name, offsetof(EditBone, name));
-}
-
-/* note: there's a unique_bone_name() too! */
-static int editbone_unique_check(void *arg, const char *name)
-{
- struct {ListBase *lb; void *bone; } *data = arg;
- EditBone *dupli = editbone_name_exists(data->lb, name);
- return dupli && dupli != data->bone;
-}
-
-void unique_editbone_name(ListBase *edbo, char *name, EditBone *bone)
-{
- struct {ListBase *lb; void *bone; } data;
- data.lb = edbo;
- data.bone = bone;
-
- BLI_uniquename_cb(editbone_unique_check, &data, "Bone", '.', name, sizeof(bone->name));
-}
-
-/* helper for apply_armature_pose2bones - fixes parenting of objects that are bone-parented to armature */
-static void applyarmature_fix_boneparents(Scene *scene, Object *armob)
-{
- Object workob, *ob;
-
- /* go through all objects in database */
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
- /* if parent is bone in this armature, apply corrections */
- if ((ob->parent == armob) && (ob->partype == PARBONE)) {
- /* apply current transform from parent (not yet destroyed),
- * then calculate new parent inverse matrix
- */
- BKE_object_apply_mat4(ob, ob->obmat, FALSE, FALSE);
-
- BKE_object_workob_calc_parent(scene, ob, &workob);
- invert_m4_m4(ob->parentinv, workob.obmat);
- }
- }
-}
-
-/* set the current pose as the restpose */
-static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object
- bArmature *arm = BKE_armature_from_object(ob);
- bPose *pose;
- bPoseChannel *pchan;
- EditBone *curbone;
-
- /* don't check if editmode (should be done by caller) */
- if (ob->type != OB_ARMATURE)
- return OPERATOR_CANCELLED;
- if (BKE_object_obdata_is_libdata(ob)) {
- BKE_report(op->reports, RPT_ERROR, "Cannot apply pose to lib-linked armature"); /* error_libdata(); */
- return OPERATOR_CANCELLED;
- }
-
- /* helpful warnings... */
- /* TODO: add warnings to be careful about actions, applying deforms first, etc. */
- if (ob->adt && ob->adt->action)
- BKE_report(op->reports, RPT_WARNING,
- "Actions on this armature will be destroyed by this new rest pose as the "
- "transforms stored are relative to the old rest pose");
-
- /* Get editbones of active armature to alter */
- ED_armature_to_edit(ob);
-
- /* get pose of active object and move it out of posemode */
- pose = ob->pose;
-
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- curbone = editbone_name_exists(arm->edbo, pchan->name);
-
- /* simply copy the head/tail values from pchan over to curbone */
- copy_v3_v3(curbone->head, pchan->pose_head);
- copy_v3_v3(curbone->tail, pchan->pose_tail);
-
- /* fix roll:
- * 1. find auto-calculated roll value for this bone now
- * 2. remove this from the 'visual' y-rotation
- */
- {
- float premat[3][3], imat[3][3], pmat[3][3], tmat[3][3];
- float delta[3], eul[3];
-
- /* obtain new auto y-rotation */
- sub_v3_v3v3(delta, curbone->tail, curbone->head);
- vec_roll_to_mat3(delta, 0.0f, premat);
- invert_m3_m3(imat, premat);
-
- /* get pchan 'visual' matrix */
- copy_m3_m4(pmat, pchan->pose_mat);
-
- /* remove auto from visual and get euler rotation */
- mul_m3_m3m3(tmat, imat, pmat);
- mat3_to_eul(eul, tmat);
-
- /* just use this euler-y as new roll value */
- curbone->roll = eul[1];
- }
-
- /* clear transform values for pchan */
- zero_v3(pchan->loc);
- zero_v3(pchan->eul);
- unit_qt(pchan->quat);
- unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
- pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
-
- /* set anim lock */
- curbone->flag |= BONE_UNKEYED;
- }
-
- /* convert editbones back to bones, and then free the edit-data */
- ED_armature_from_edit(ob);
- ED_armature_edit_free(ob);
-
- /* flush positions of posebones */
- BKE_pose_where_is(scene, ob);
-
- /* fix parenting of objects which are bone-parented */
- applyarmature_fix_boneparents(scene, ob);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_armature_apply(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Apply Pose as Rest Pose";
- ot->idname = "POSE_OT_armature_apply";
- ot->description = "Apply the current pose as the new rest pose";
-
- /* callbacks */
- ot->exec = apply_armature_pose2bones_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-/* set the current pose as the restpose */
-static int pose_visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object
-
- /* don't check if editmode (should be done by caller) */
- if (ob->type != OB_ARMATURE)
- return OPERATOR_CANCELLED;
-
- /* loop over all selected pchans
- *
- * TODO, loop over children before parents if multiple bones
- * at once are to be predictable*/
- CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones)
- {
- float delta_mat[4][4];
-
- /* chan_mat already contains the delta transform from rest pose to pose-mode pose
- * as that is baked into there so that B-Bones will work. Once we've set this as the
- * new raw-transform components, don't recalc the poses yet, otherwise IK result will
- * change, thus changing the result we may be trying to record.
- */
- copy_m4_m4(delta_mat, pchan->chan_mat);
- BKE_pchan_apply_mat4(pchan, delta_mat, TRUE);
- }
- CTX_DATA_END;
-
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_visual_transform_apply(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Apply Visual Transform to Pose";
- ot->idname = "POSE_OT_visual_transform_apply";
- ot->description = "Apply final constrained position of pose bones to their transform";
-
- /* callbacks */
- ot->exec = pose_visual_transform_apply_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ---------------------- */
-
-/* Helper function for armature joining - link fixing */
-static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone)
-{
- Object *ob;
- bPose *pose;
- bPoseChannel *pchant;
- bConstraint *con;
-
- /* let's go through all objects in database */
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
- /* do some object-type specific things */
- if (ob->type == OB_ARMATURE) {
- pose = ob->pose;
- for (pchant = pose->chanbase.first; pchant; pchant = pchant->next) {
- for (con = pchant->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == srcArm) {
- if (ct->subtarget[0] == '\0') {
- ct->tar = tarArm;
- }
- else if (strcmp(ct->subtarget, pchan->name) == 0) {
- ct->tar = tarArm;
- BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget));
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
-
- /* action constraint? */
- if (con->type == CONSTRAINT_TYPE_ACTION) {
- bActionConstraint *data = con->data; // XXX old animation system
- bAction *act;
- bActionChannel *achan;
-
- if (data->act) {
- act = data->act;
-
- for (achan = act->chanbase.first; achan; achan = achan->next) {
- if (strcmp(achan->name, pchan->name) == 0)
- BLI_strncpy(achan->name, curbone->name, sizeof(achan->name));
- }
- }
- }
-
- }
- }
- }
-
- /* fix object-level constraints */
- if (ob != srcArm) {
- for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == srcArm) {
- if (ct->subtarget[0] == '\0') {
- ct->tar = tarArm;
- }
- else if (strcmp(ct->subtarget, pchan->name) == 0) {
- ct->tar = tarArm;
- BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget));
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
-
- /* See if an object is parented to this armature */
- if (ob->parent && (ob->parent == srcArm)) {
- /* Is object parented to a bone of this src armature? */
- if (ob->partype == PARBONE) {
- /* bone name in object */
- if (!strcmp(ob->parsubstr, pchan->name))
- BLI_strncpy(ob->parsubstr, curbone->name, sizeof(ob->parsubstr));
- }
-
- /* make tar armature be new parent */
- ob->parent = tarArm;
- }
- }
-}
-
-/* join armature exec is exported for use in object->join objects operator... */
-int join_armature_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- bArmature *arm = (ob) ? ob->data : NULL;
- bPose *pose, *opose;
- bPoseChannel *pchan, *pchann;
- EditBone *curbone;
- float mat[4][4], oimat[4][4];
-
- /* Ensure we're not in editmode and that the active object is an armature*/
- if (!ob || ob->type != OB_ARMATURE)
- return OPERATOR_CANCELLED;
- if (!arm || arm->edbo)
- return OPERATOR_CANCELLED;
-
- /* Get editbones of active armature to add editbones to */
- ED_armature_to_edit(ob);
-
- /* get pose of active object and move it out of posemode */
- pose = ob->pose;
- ob->mode &= ~OB_MODE_POSE;
-
- CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
- {
- if ((base->object->type == OB_ARMATURE) && (base->object != ob)) {
- bArmature *curarm = base->object->data;
-
- /* Make a list of editbones in current armature */
- ED_armature_to_edit(base->object);
-
- /* Get Pose of current armature */
- opose = base->object->pose;
- base->object->mode &= ~OB_MODE_POSE;
- //BASACT->flag &= ~OB_MODE_POSE;
-
- /* Find the difference matrix */
- invert_m4_m4(oimat, ob->obmat);
- mult_m4_m4m4(mat, oimat, base->object->obmat);
-
- /* Copy bones and posechannels from the object to the edit armature */
- for (pchan = opose->chanbase.first; pchan; pchan = pchann) {
- pchann = pchan->next;
- curbone = editbone_name_exists(curarm->edbo, pchan->name);
-
- /* Get new name */
- unique_editbone_name(arm->edbo, curbone->name, NULL);
-
- /* Transform the bone */
- {
- float premat[4][4];
- float postmat[4][4];
- float difmat[4][4];
- float imat[4][4];
- float temp[3][3];
- float delta[3];
-
- /* Get the premat */
- sub_v3_v3v3(delta, curbone->tail, curbone->head);
- vec_roll_to_mat3(delta, curbone->roll, temp);
-
- unit_m4(premat); /* Mat4MulMat34 only sets 3x3 part */
- mul_m4_m3m4(premat, temp, mat);
-
- mul_m4_v3(mat, curbone->head);
- mul_m4_v3(mat, curbone->tail);
-
- /* Get the postmat */
- sub_v3_v3v3(delta, curbone->tail, curbone->head);
- vec_roll_to_mat3(delta, curbone->roll, temp);
- copy_m4_m3(postmat, temp);
-
- /* Find the roll */
- invert_m4_m4(imat, premat);
- mult_m4_m4m4(difmat, imat, postmat);
-
- curbone->roll -= (float)atan2(difmat[2][0], difmat[2][2]);
- }
-
- /* Fix Constraints and Other Links to this Bone and Armature */
- joined_armature_fix_links(ob, base->object, pchan, curbone);
-
- /* Rename pchan */
- BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name));
-
- /* Jump Ship! */
- BLI_remlink(curarm->edbo, curbone);
- BLI_addtail(arm->edbo, curbone);
-
- BLI_remlink(&opose->chanbase, pchan);
- BLI_addtail(&pose->chanbase, pchan);
- BKE_pose_channels_hash_free(opose);
- BKE_pose_channels_hash_free(pose);
- }
-
- ED_base_object_free_and_unlink(bmain, scene, base);
- }
- }
- CTX_DATA_END;
-
- DAG_relations_tag_update(bmain); /* because we removed object(s) */
-
- ED_armature_from_edit(ob);
- ED_armature_edit_free(ob);
-
- WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
-
- return OPERATOR_FINISHED;
-}
-
-/* ---------------------- */
-
-/* Helper function for armature separating - link fixing */
-static void separated_armature_fix_links(Object *origArm, Object *newArm)
-{
- Object *ob;
- bPoseChannel *pchan;
- bConstraint *con;
- ListBase *opchans, *npchans;
-
- /* get reference to list of bones in original and new armatures */
- opchans = &origArm->pose->chanbase;
- npchans = &newArm->pose->chanbase;
-
- /* let's go through all objects in database */
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
- /* do some object-type specific things */
- if (ob->type == OB_ARMATURE) {
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- /* any targets which point to original armature are redirected to the new one only if:
- * - the target isn't origArm/newArm itself
- * - the target is one that can be found in newArm/origArm
- */
- if (ct->subtarget[0] != 0) {
- if (ct->tar == origArm) {
- if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
- ct->tar = newArm;
- }
- }
- else if (ct->tar == newArm) {
- if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
- ct->tar = origArm;
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
- }
- }
-
- /* fix object-level constraints */
- if (ob != origArm) {
- for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- /* any targets which point to original armature are redirected to the new one only if:
- * - the target isn't origArm/newArm itself
- * - the target is one that can be found in newArm/origArm
- */
- if (ct->subtarget[0] != '\0') {
- if (ct->tar == origArm) {
- if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
- ct->tar = newArm;
- }
- }
- else if (ct->tar == newArm) {
- if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
- ct->tar = origArm;
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
- }
-
- /* See if an object is parented to this armature */
- if (ob->parent && (ob->parent == origArm)) {
- /* Is object parented to a bone of this src armature? */
- if ((ob->partype == PARBONE) && (ob->parsubstr[0] != '\0')) {
- if (BLI_findstring(npchans, ob->parsubstr, offsetof(bPoseChannel, name))) {
- ob->parent = newArm;
- }
- }
- }
- }
-}
-
-/* Helper function for armature separating - remove certain bones from the given armature
- * sel: remove selected bones from the armature, otherwise the unselected bones are removed
- * (ob is not in editmode)
- */
-static void separate_armature_bones(Object *ob, short sel)
-{
- bArmature *arm = (bArmature *)ob->data;
- bPoseChannel *pchan, *pchann;
- EditBone *curbone;
-
- /* make local set of editbones to manipulate here */
- ED_armature_to_edit(ob);
-
- /* go through pose-channels, checking if a bone should be removed */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchann) {
- pchann = pchan->next;
- curbone = editbone_name_exists(arm->edbo, pchan->name);
-
- /* check if bone needs to be removed */
- if ( (sel && (curbone->flag & BONE_SELECTED)) ||
- (!sel && !(curbone->flag & BONE_SELECTED)) )
- {
- EditBone *ebo;
- bPoseChannel *pchn;
-
- /* clear the bone->parent var of any bone that had this as its parent */
- for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
- if (ebo->parent == curbone) {
- ebo->parent = NULL;
- ebo->temp = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */
- ebo->flag &= ~BONE_CONNECTED;
- }
- }
-
- /* clear the pchan->parent var of any pchan that had this as its parent */
- for (pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) {
- if (pchn->parent == pchan)
- pchn->parent = NULL;
- }
-
- /* free any of the extra-data this pchan might have */
- BKE_pose_channel_free(pchan);
- BKE_pose_channels_hash_free(ob->pose);
-
- /* get rid of unneeded bone */
- bone_free(arm, curbone);
- BLI_freelinkN(&ob->pose->chanbase, pchan);
- }
- }
-
- /* exit editmode (recalculates pchans too) */
- ED_armature_from_edit(ob);
- ED_armature_edit_free(ob);
-}
-
-/* separate selected bones into their armature */
-static int separate_armature_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- Object *oldob, *newob;
- Base *oldbase, *newbase;
-
- /* sanity checks */
- if (obedit == NULL)
- return OPERATOR_CANCELLED;
-
- /* set wait cursor in case this takes a while */
- WM_cursor_wait(1);
-
- /* we are going to do this as follows (unlike every other instance of separate):
- * 1. exit editmode +posemode for active armature/base. Take note of what this is.
- * 2. duplicate base - BASACT is the new one now
- * 3. for each of the two armatures, enter editmode -> remove appropriate bones -> exit editmode + recalc
- * 4. fix constraint links
- * 5. make original armature active and enter editmode
- */
-
- /* 1) only edit-base selected */
- /* TODO: use context iterators for this? */
- CTX_DATA_BEGIN(C, Base *, base, visible_bases)
- {
- if (base->object == obedit) base->flag |= 1;
- else base->flag &= ~1;
- }
- CTX_DATA_END;
-
- /* 1) store starting settings and exit editmode */
- oldob = obedit;
- oldbase = BASACT;
- oldob->mode &= ~OB_MODE_POSE;
- //oldbase->flag &= ~OB_POSEMODE;
-
- ED_armature_from_edit(obedit);
- ED_armature_edit_free(obedit);
-
- /* 2) duplicate base */
- newbase = ED_object_add_duplicate(bmain, scene, oldbase, USER_DUP_ARM); /* only duplicate linked armature */
- DAG_relations_tag_update(bmain);
-
- newob = newbase->object;
- newbase->flag &= ~SELECT;
-
-
- /* 3) remove bones that shouldn't still be around on both armatures */
- separate_armature_bones(oldob, 1);
- separate_armature_bones(newob, 0);
-
-
- /* 4) fix links before depsgraph flushes */ // err... or after?
- separated_armature_fix_links(oldob, newob);
-
- DAG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */
- DAG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */
-
-
- /* 5) restore original conditions */
- obedit = oldob;
-
- ED_armature_to_edit(obedit);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
-
- /* recalc/redraw + cleanup */
- WM_cursor_wait(0);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_separate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Separate Bones";
- ot->idname = "ARMATURE_OT_separate";
- ot->description = "Isolate selected bones into a separate armature";
-
- /* callbacks */
- ot->invoke = WM_operator_confirm;
- ot->exec = separate_armature_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* **************** END tools on Editmode Armature **************** */
-/* **************** PoseMode & EditMode *************************** */
-
-/* only for opengl selection indices */
-Bone *get_indexed_bone(Object *ob, int index)
-{
- bPoseChannel *pchan;
- if (ob->pose == NULL) return NULL;
- index >>= 16; // bone selection codes use left 2 bytes
-
- pchan = BLI_findlink(&ob->pose->chanbase, index);
- return pchan ? pchan->bone : NULL;
-}
-
-/* See if there are any selected bones in this buffer */
-/* only bones from base are checked on */
-static void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits, short findunsel)
-{
- Object *obedit = scene->obedit; // XXX get from context
- Bone *bone;
- EditBone *ebone;
- void *firstunSel = NULL, *firstSel = NULL, *data;
- unsigned int hitresult;
- short i, takeNext = 0, sel;
-
- for (i = 0; i < hits; i++) {
- hitresult = buffer[3 + (i * 4)];
-
- if (!(hitresult & BONESEL_NOSEL)) { // -1
- if (hitresult & BONESEL_ANY) { // to avoid including objects in selection
-
- hitresult &= ~(BONESEL_ANY);
- /* Determine what the current bone is */
- if (obedit == NULL || base->object != obedit) {
- /* no singular posemode, so check for correct object */
- if (base->selcol == (hitresult & 0xFFFF)) {
- bone = get_indexed_bone(base->object, hitresult);
-
- if (findunsel)
- sel = (bone->flag & BONE_SELECTED);
- else
- sel = !(bone->flag & BONE_SELECTED);
-
- data = bone;
- }
- else {
- data = NULL;
- sel = 0;
- }
- }
- else {
- bArmature *arm = obedit->data;
-
- ebone = BLI_findlink(arm->edbo, hitresult);
- if (findunsel)
- sel = (ebone->flag & BONE_SELECTED);
- else
- sel = !(ebone->flag & BONE_SELECTED);
-
- data = ebone;
- }
-
- if (data) {
- if (sel) {
- if (!firstSel) firstSel = data;
- takeNext = 1;
- }
- else {
- if (!firstunSel)
- firstunSel = data;
- if (takeNext)
- return data;
- }
- }
- }
- }
- }
-
- if (firstunSel)
- return firstunSel;
- else
- return firstSel;
-}
-
-
-
-/* used by posemode as well editmode */
-/* only checks scene->basact! */
-/* x and y are mouse coords (area space) */
-static void *get_nearest_bone(bContext *C, short findunsel, int x, int y)
-{
- ViewContext vc;
- rcti rect;
- unsigned int buffer[MAXPICKBUF];
- short hits;
-
- view3d_set_viewcontext(C, &vc);
-
- // rect.xmin = ... mouseco!
- rect.xmin = rect.xmax = x;
- rect.ymin = rect.ymax = y;
-
- glInitNames();
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
-
- if (hits > 0)
- return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel);
-
- return NULL;
-}
-
-/* Get the first available child of an editbone */
-static EditBone *editbone_get_child(bArmature *arm, EditBone *pabone, short use_visibility)
-{
- EditBone *curbone, *chbone = NULL;
-
- for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
- if (curbone->parent == pabone) {
- if (use_visibility) {
- if ((arm->layer & curbone->layer) && !(pabone->flag & BONE_HIDDEN_A)) {
- chbone = curbone;
- }
- }
- else
- chbone = curbone;
- }
- }
-
- return chbone;
-}
-
-/* **************** END PoseMode & EditMode *************************** */
-/* **************** Posemode stuff ********************** */
-
-
-static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
-{
- Bone *curBone;
-
- /* stop when unconnected child is encontered, or when unselectable bone is encountered */
- if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE))
- return;
-
- /* XXX old cruft! use notifiers instead */
- //select_actionchannel_by_name (ob->action, bone->name, !(shift));
-
- if (extend)
- bone->flag &= ~BONE_SELECTED;
- else
- bone->flag |= BONE_SELECTED;
-
- for (curBone = bone->childbase.first; curBone; curBone = curBone->next)
- selectconnected_posebonechildren(ob, curBone, extend);
-}
-
-/* within active object context */
-/* previously known as "selectconnected_posearmature" */
-static int pose_select_connected_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
- Bone *bone, *curBone, *next = NULL;
- int extend = RNA_boolean_get(op->ptr, "extend");
-
- view3d_operator_needs_opengl(C);
-
- if (extend)
- bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
- else
- bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]);
-
- if (!bone)
- return OPERATOR_CANCELLED;
-
- /* Select parents */
- for (curBone = bone; curBone; curBone = next) {
- /* ignore bone if cannot be selected */
- if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
- // XXX old cruft! use notifiers instead
- //select_actionchannel_by_name (ob->action, curBone->name, !(shift));
-
- if (extend)
- curBone->flag &= ~BONE_SELECTED;
- else
- curBone->flag |= BONE_SELECTED;
-
- if (curBone->flag & BONE_CONNECTED)
- next = curBone->parent;
- else
- next = NULL;
- }
- else
- next = NULL;
- }
-
- /* Select children */
- for (curBone = bone->childbase.first; curBone; curBone = next)
- selectconnected_posebonechildren(ob, curBone, extend);
-
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- return OPERATOR_FINISHED;
-}
-
-static int pose_select_linked_poll(bContext *C)
-{
- return (ED_operator_view3d_active(C) && ED_operator_posemode(C));
-}
-
-void POSE_OT_select_linked(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Connected";
- ot->idname = "POSE_OT_select_linked";
- ot->description = "Select bones related to selected ones by parent/child relationships";
-
- /* api callbacks */
- ot->exec = NULL;
- ot->invoke = pose_select_connected_invoke;
- ot->poll = pose_select_linked_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
-}
-
-/* **************** END Posemode stuff ********************** */
-/* **************** EditMode stuff ********************** */
-
-/* called in space.c */
-/* previously "selectconnected_armature" */
-static int armature_select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- bArmature *arm;
- EditBone *bone, *curBone, *next;
- int extend = RNA_boolean_get(op->ptr, "extend");
- Object *obedit = CTX_data_edit_object(C);
- arm = obedit->data;
-
- view3d_operator_needs_opengl(C);
-
- if (extend)
- bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
- else
- bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]);
-
- if (!bone)
- return OPERATOR_CANCELLED;
-
- /* Select parents */
- for (curBone = bone; curBone; curBone = next) {
- if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
- if (extend) {
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
-
- if (curBone->flag & BONE_CONNECTED)
- next = curBone->parent;
- else
- next = NULL;
- }
-
- /* Select children */
- while (bone) {
- for (curBone = arm->edbo->first; curBone; curBone = next) {
- next = curBone->next;
- if ((curBone->parent == bone) && (curBone->flag & BONE_UNSELECTABLE) == 0) {
- if (curBone->flag & BONE_CONNECTED) {
- if (extend)
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- else
- curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- bone = curBone;
- break;
- }
- else {
- bone = NULL;
- break;
- }
- }
- }
- if (!curBone)
- bone = NULL;
- }
-
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-static int armature_select_linked_poll(bContext *C)
-{
- return (ED_operator_view3d_active(C) && ED_operator_editarmature(C) );
-}
-
-void ARMATURE_OT_select_linked(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Connected";
- ot->idname = "ARMATURE_OT_select_linked";
- ot->description = "Select bones related to selected ones by parent/child relationships";
-
- /* api callbacks */
- ot->exec = NULL;
- ot->invoke = armature_select_linked_invoke;
- ot->poll = armature_select_linked_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
-}
-
-/* does bones and points */
-/* note that BONE ROOT only gets drawn for root bones (or without IK) */
-static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
- ListBase *edbo, int findunsel, int *selmask)
-{
- EditBone *ebone;
- rcti rect;
- unsigned int buffer[MAXPICKBUF];
- unsigned int hitresult, besthitresult = BONESEL_NOSEL;
- int i, mindep = 4;
- short hits;
-
- glInitNames();
-
- rect.xmin = mval[0] - 5;
- rect.xmax = mval[0] + 5;
- rect.ymin = mval[1] - 5;
- rect.ymax = mval[1] + 5;
-
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
- if (hits == 0) {
- rect.xmin = mval[0] - 12;
- rect.xmax = mval[0] + 12;
- rect.ymin = mval[1] - 12;
- rect.ymax = mval[1] + 12;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
- }
- /* See if there are any selected bones in this group */
- if (hits > 0) {
-
- if (hits == 1) {
- if (!(buffer[3] & BONESEL_NOSEL))
- besthitresult = buffer[3];
- }
- else {
- for (i = 0; i < hits; i++) {
- hitresult = buffer[3 + (i * 4)];
- if (!(hitresult & BONESEL_NOSEL)) {
- int dep;
-
- ebone = BLI_findlink(edbo, hitresult & ~BONESEL_ANY);
-
- /* clicks on bone points get advantage */
- if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
- /* but also the unselected one */
- if (findunsel) {
- if ( (hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0)
- dep = 1;
- else if ( (hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0)
- dep = 1;
- else
- dep = 2;
- }
- else dep = 2;
- }
- else {
- /* bone found */
- if (findunsel) {
- if ((ebone->flag & BONE_SELECTED) == 0)
- dep = 2;
- else
- dep = 3;
- }
- else dep = 3;
- }
- if (dep < mindep) {
- mindep = dep;
- besthitresult = hitresult;
- }
- }
- }
- }
-
- if (!(besthitresult & BONESEL_NOSEL)) {
-
- ebone = BLI_findlink(edbo, besthitresult & ~BONESEL_ANY);
-
- *selmask = 0;
- if (besthitresult & BONESEL_ROOT)
- *selmask |= BONE_ROOTSEL;
- if (besthitresult & BONESEL_TIP)
- *selmask |= BONE_TIPSEL;
- if (besthitresult & BONESEL_BONE)
- *selmask |= BONE_SELECTED;
- return ebone;
- }
- }
- *selmask = 0;
- return NULL;
-}
-
-/* previously delete_armature */
-/* only editmode! */
-static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bArmature *arm;
- EditBone *curBone, *ebone_next;
- bConstraint *con;
- Object *obedit = CTX_data_edit_object(C); // XXX get from context
- arm = obedit->data;
-
- /* cancel if nothing selected */
- if (CTX_DATA_COUNT(C, selected_bones) == 0)
- return OPERATOR_CANCELLED;
-
- armature_select_mirrored(arm);
-
- /* First erase any associated pose channel */
- if (obedit->pose) {
- bPoseChannel *pchan, *pchan_next;
- for (pchan = obedit->pose->chanbase.first; pchan; pchan = pchan_next) {
- pchan_next = pchan->next;
- curBone = editbone_name_exists(arm->edbo, pchan->name);
-
- if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
- BKE_pose_channel_free(pchan);
- BKE_pose_channels_hash_free(obedit->pose);
- BLI_freelinkN(&obedit->pose->chanbase, pchan);
- }
- else {
- for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == obedit) {
- if (ct->subtarget[0]) {
- curBone = editbone_name_exists(arm->edbo, ct->subtarget);
- if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
- con->flag |= CONSTRAINT_DISABLE;
- ct->subtarget[0] = 0;
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
- }
- }
-
-
- for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
- ebone_next = curBone->next;
- if (arm->layer & curBone->layer) {
- if (curBone->flag & BONE_SELECTED) {
- if (curBone == arm->act_edbone) arm->act_edbone = NULL;
- ED_armature_edit_bone_remove(arm, curBone);
- }
- }
- }
-
-
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_delete(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Delete Selected Bone(s)";
- ot->idname = "ARMATURE_OT_delete";
- ot->description = "Remove selected bones from the armature";
-
- /* api callbacks */
- ot->invoke = WM_operator_confirm;
- ot->exec = armature_delete_selected_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* toggle==0: deselect
- * toggle==1: swap (based on test)
- * toggle==2: swap (no test), CURRENTLY UNUSED
- */
-void ED_armature_deselect_all(Object *obedit, int toggle)
-{
- bArmature *arm = obedit->data;
- EditBone *eBone;
- int sel = 1;
-
- if (toggle == 1) {
- /* Determine if there are any selected bones
- * and therefore whether we are selecting or deselecting */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- // if (arm->layer & eBone->layer) {
- if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
- sel = 0;
- break;
- }
- // }
- }
- }
- else sel = toggle;
-
- /* Set the flags */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- if (sel == 2) {
- /* invert selection of bone */
- if (EBONE_VISIBLE(arm, eBone)) {
- eBone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (arm->act_edbone == eBone)
- arm->act_edbone = NULL;
- }
- }
- else if (sel == 1) {
- /* select bone */
- if (EBONE_VISIBLE(arm, eBone)) {
- eBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (eBone->parent)
- eBone->parent->flag |= (BONE_TIPSEL);
- }
- }
- else {
- /* deselect bone */
- eBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (arm->act_edbone == eBone)
- arm->act_edbone = NULL;
- }
- }
-
- ED_armature_sync_selection(arm->edbo);
-}
-
-void ED_armature_deselect_all_visible(Object *obedit)
-{
- bArmature *arm = obedit->data;
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- /* first and foremost, bone must be visible and selected */
- if (EBONE_SELECTABLE(arm, ebone)) {
- ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
-
- ED_armature_sync_selection(arm->edbo);
-}
-
-/* accounts for connected parents */
-static int ebone_select_flag(EditBone *ebone)
-{
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) | (ebone->flag & (BONE_SELECTED | BONE_TIPSEL));
- }
- else {
- return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
- }
-}
-
-/* context: editmode armature in view3d */
-int mouse_armature(bContext *C, const int mval[2], int extend, int deselect, int toggle)
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- ViewContext vc;
- EditBone *nearBone = NULL;
- int selmask;
-
- view3d_set_viewcontext(C, &vc);
-
- BIF_sk_selectStroke(C, mval, extend);
-
- nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask);
- if (nearBone) {
-
- if (!extend && !deselect && !toggle)
- ED_armature_deselect_all(obedit, 0);
-
- /* by definition the non-root connected bones have no root point drawn,
- * so a root selection needs to be delivered to the parent tip */
-
- if (selmask & BONE_SELECTED) {
- if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) {
- /* click in a chain */
- if (extend) {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
- }
- else if (deselect) {
- /* deselect this bone */
- nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
- /* only deselect parent tip if it is not selected */
- if (!(nearBone->parent->flag & BONE_SELECTED))
- nearBone->parent->flag &= ~BONE_TIPSEL;
- }
- else if (toggle) {
- /* hold shift inverts this bone's selection */
- if (nearBone->flag & BONE_SELECTED) {
- /* deselect this bone */
- nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
- /* only deselect parent tip if it is not selected */
- if (!(nearBone->parent->flag & BONE_SELECTED))
- nearBone->parent->flag &= ~BONE_TIPSEL;
- }
- else {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
- }
- }
- else {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
- }
- }
- else {
- if (extend) {
- nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (deselect) {
- nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (toggle) {
- /* hold shift inverts this bone's selection */
- if (nearBone->flag & BONE_SELECTED)
- nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
- else
- nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
- }
- else
- nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
- else {
- if (extend)
- nearBone->flag |= selmask;
- else if (deselect)
- nearBone->flag &= ~selmask;
- else if (toggle && (nearBone->flag & selmask))
- nearBone->flag &= ~selmask;
- else
- nearBone->flag |= selmask;
- }
-
- ED_armature_sync_selection(arm->edbo);
-
- if (nearBone) {
- /* then now check for active status */
- if (ebone_select_flag(nearBone)) {
- arm->act_edbone = nearBone;
- }
- }
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
- return 1;
- }
-
- return 0;
-}
-
-void ED_armature_edit_free(struct Object *ob)
-{
- bArmature *arm = ob->data;
- EditBone *eBone;
-
- /* Clear the editbones list */
- if (arm->edbo) {
- if (arm->edbo->first) {
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- if (eBone->prop) {
- IDP_FreeProperty(eBone->prop);
- MEM_freeN(eBone->prop);
- }
- }
-
- BLI_freelistN(arm->edbo);
- }
- MEM_freeN(arm->edbo);
- arm->edbo = NULL;
- }
-}
-
-/* Put armature in EditMode */
-void ED_armature_to_edit(Object *ob)
-{
- bArmature *arm = ob->data;
-
- ED_armature_edit_free(ob);
- arm->edbo = MEM_callocN(sizeof(ListBase), "edbo armature");
- arm->act_edbone = make_boneList(arm->edbo, &arm->bonebase, NULL, arm->act_bone);
- arm->act_bone = NULL;
-
-// BIF_freeTemplates(); /* force template update when entering editmode */
-}
-
-
-/* adjust bone roll to align Z axis with vector
- * vec is in local space and is normalized
- */
-
-float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const short axis_only)
-{
- float mat[3][3], nor[3];
-
- sub_v3_v3v3(nor, bone->tail, bone->head);
- vec_roll_to_mat3(nor, 0.0f, mat);
-
- /* check the bone isn't aligned with the axis */
- if (!is_zero_v3(align_axis) && angle_v3v3(align_axis, mat[2]) > FLT_EPSILON) {
- float vec[3], align_axis_proj[3], roll;
-
- /* project the new_up_axis along the normal */
- project_v3_v3v3(vec, align_axis, nor);
- sub_v3_v3v3(align_axis_proj, align_axis, vec);
-
- if (axis_only) {
- if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI / 2.0)) {
- negate_v3(align_axis_proj);
- }
- }
-
- roll = angle_v3v3(align_axis_proj, mat[2]);
-
- cross_v3_v3v3(vec, mat[2], align_axis_proj);
-
- if (dot_v3v3(vec, nor) < 0) {
- roll = -roll;
- }
-
- return roll;
- }
-
- return 0.0f;
-}
-
-
-static EnumPropertyItem prop_calc_roll_types[] = {
- {0, "X", 0, "X Axis", ""},
- {1, "Y", 0, "Y Axis", ""},
- {2, "Z", 0, "Z Axis", ""},
- {5, "ACTIVE", 0, "Active Bone", ""},
- {6, "VIEW", 0, "View Axis", ""},
- {7, "CURSOR", 0, "Cursor", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-
-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");
- const short axis_only = RNA_boolean_get(op->ptr, "axis_only");
- const short axis_flip = RNA_boolean_get(op->ptr, "axis_flip");
-
- float imat[3][3];
-
- bArmature *arm = ob->data;
- EditBone *ebone;
-
- copy_m3_m4(imat, ob->obmat);
- invert_m3(imat);
-
- if (type == 7) { /* Cursor */
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C); /* can be NULL */
- float cursor_local[3];
- const float *cursor = give_cursor(scene, v3d);
-
-
- copy_v3_v3(cursor_local, cursor);
- mul_m3_v3(imat, cursor_local);
-
- /* cursor */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
- float cursor_rel[3];
- sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
- if (axis_flip) negate_v3(cursor_rel);
- ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only);
- }
- }
- }
- else {
- float vec[3] = {0.0f, 0.0f, 0.0f};
- if (type == 6) { /* View */
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (rv3d == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No region view3d available");
- return OPERATOR_CANCELLED;
- }
-
- copy_v3_v3(vec, rv3d->viewinv[2]);
- mul_m3_v3(imat, vec);
- }
- else if (type == 5) {
- float mat[3][3], nor[3];
- ebone = (EditBone *)arm->act_edbone;
- if (ebone == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active bone set");
- return OPERATOR_CANCELLED;
- }
-
- sub_v3_v3v3(nor, ebone->tail, ebone->head);
- vec_roll_to_mat3(nor, ebone->roll, mat);
- copy_v3_v3(vec, mat[2]);
- }
- else { /* Axis */
- assert(type >= 0 && type <= 5);
- if (type < 3) vec[type] = 1.0f;
- else vec[type - 2] = -1.0f;
- mul_m3_v3(imat, vec);
- }
-
- if (axis_flip) negate_v3(vec);
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
- /* roll func is a callback which assumes that all is well */
- ebone->roll = ED_rollBoneToVector(ebone, vec, axis_only);
- }
- }
- }
-
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
- EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, ebone);
- if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
- ebone->roll = -ebone_mirr->roll;
- }
- }
- }
- }
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Recalculate Roll";
- ot->idname = "ARMATURE_OT_calculate_roll";
- ot->description = "Automatically fix alignment of select bones' axes";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_calc_roll_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, 0, "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");
-}
-
-/* **************** undo for armatures ************** */
-
-typedef struct UndoArmature {
- EditBone *act_edbone;
- ListBase lb;
-} UndoArmature;
-
-static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data))
-{
- UndoArmature *uarm = uarmv;
- bArmature *arm = armv;
- EditBone *ebo, *newebo;
-
- BLI_freelistN(arm->edbo);
-
- /* copy */
- for (ebo = uarm->lb.first; ebo; ebo = ebo->next) {
- newebo = MEM_dupallocN(ebo);
- ebo->temp = newebo;
- BLI_addtail(arm->edbo, newebo);
- }
-
- /* active bone */
- if (uarm->act_edbone) {
- ebo = uarm->act_edbone;
- arm->act_edbone = ebo->temp;
- }
- else
- arm->act_edbone = NULL;
-
- /* set pointers */
- for (newebo = arm->edbo->first; newebo; newebo = newebo->next) {
- if (newebo->parent) newebo->parent = newebo->parent->temp;
- }
- /* be sure they don't hang ever */
- for (newebo = arm->edbo->first; newebo; newebo = newebo->next) {
- newebo->temp = NULL;
- }
-}
-
-static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata))
-{
- bArmature *arm = armv;
- UndoArmature *uarm;
- EditBone *ebo, *newebo;
-
- uarm = MEM_callocN(sizeof(UndoArmature), "listbase undo");
-
- /* copy */
- for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
- newebo = MEM_dupallocN(ebo);
- ebo->temp = newebo;
- BLI_addtail(&uarm->lb, newebo);
- }
-
- /* active bone */
- if (arm->act_edbone) {
- ebo = arm->act_edbone;
- uarm->act_edbone = ebo->temp;
- }
-
- /* set pointers */
- for (newebo = uarm->lb.first; newebo; newebo = newebo->next) {
- if (newebo->parent) newebo->parent = newebo->parent->temp;
- }
-
- return uarm;
-}
-
-static void free_undoBones(void *uarmv)
-{
- UndoArmature *uarm = uarmv;
-
- BLI_freelistN(&uarm->lb);
- MEM_freeN(uarm);
-}
-
-static void *get_armature_edit(bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- if (obedit && obedit->type == OB_ARMATURE) {
- return obedit->data;
- }
- return NULL;
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_armature(bContext *C, const char *name)
-{
- // XXX solve getdata()
- undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
-}
-
-
-
-/* **************** END EditMode stuff ********************** */
-/* *************** Adding stuff in editmode *************** */
-
-/* default bone add, returns it selected, but without tail set */
-/* XXX should be used everywhere, now it mallocs bones still locally in functions */
-EditBone *ED_armature_edit_bone_add(bArmature *arm, const char *name)
-{
- EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone");
-
- BLI_strncpy(bone->name, name, sizeof(bone->name));
- unique_editbone_name(arm->edbo, bone->name, NULL);
-
- BLI_addtail(arm->edbo, bone);
-
- bone->flag |= BONE_TIPSEL;
- bone->weight = 1.0f;
- bone->dist = 0.25f;
- bone->xwidth = 0.1f;
- bone->zwidth = 0.1f;
- bone->ease1 = 1.0f;
- bone->ease2 = 1.0f;
- bone->rad_head = 0.10f;
- bone->rad_tail = 0.05f;
- bone->segments = 1;
- bone->layer = arm->layer;
-
- return bone;
-}
-
-/* v3d and rv3d are allowed to be NULL */
-void add_primitive_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d)
-{
- Object *obedit = scene->obedit; // XXX get from context
- bArmature *arm = obedit->data;
- float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
- EditBone *bone;
-
- /* Get inverse point for head and orientation for tail */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d));
-
- if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
- copy_m3_m4(obmat, rv3d->viewmat);
- else unit_m3(obmat);
-
- copy_m3_m4(viewmat, obedit->obmat);
- mul_m3_m3m3(totmat, obmat, viewmat);
- invert_m3_m3(imat, totmat);
-
- ED_armature_deselect_all(obedit, 0);
-
- /* Create a bone */
- bone = ED_armature_edit_bone_add(arm, "Bone");
-
- arm->act_edbone = bone;
-
- copy_v3_v3(bone->head, curs);
-
- if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
- add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1
- else
- add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z
-}
-
-
-/* previously addvert_armature */
-/* the ctrl-click method */
-static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
-{
- View3D *v3d;
- bArmature *arm;
- EditBone *ebone, *newbone, *flipbone;
- float mat[3][3], imat[3][3];
- const float *curs;
- int a, to_root = 0;
- Object *obedit;
- Scene *scene;
-
- scene = CTX_data_scene(C);
- v3d = CTX_wm_view3d(C);
- obedit = CTX_data_edit_object(C);
- arm = obedit->data;
-
- /* find the active or selected bone */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_TIPSEL || arm->act_edbone == ebone)
- break;
- }
- }
-
- if (ebone == NULL) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_ROOTSEL || arm->act_edbone == ebone)
- break;
- }
- }
- if (ebone == NULL)
- return OPERATOR_CANCELLED;
-
- to_root = 1;
- }
-
- ED_armature_deselect_all(obedit, 0);
-
- /* we re-use code for mirror editing... */
- flipbone = NULL;
- if (arm->flag & ARM_MIRROR_EDIT)
- flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone);
-
- for (a = 0; a < 2; a++) {
- if (a == 1) {
- if (flipbone == NULL)
- break;
- else {
- SWAP(EditBone *, flipbone, ebone);
- }
- }
-
- newbone = ED_armature_edit_bone_add(arm, ebone->name);
- arm->act_edbone = newbone;
-
- if (to_root) {
- copy_v3_v3(newbone->head, ebone->head);
- newbone->rad_head = ebone->rad_tail;
- newbone->parent = ebone->parent;
- }
- else {
- copy_v3_v3(newbone->head, ebone->tail);
- newbone->rad_head = ebone->rad_tail;
- newbone->parent = ebone;
- newbone->flag |= BONE_CONNECTED;
- }
-
- curs = give_cursor(scene, v3d);
- copy_v3_v3(newbone->tail, curs);
- sub_v3_v3v3(newbone->tail, newbone->tail, obedit->obmat[3]);
-
- if (a == 1)
- newbone->tail[0] = -newbone->tail[0];
-
- copy_m3_m4(mat, obedit->obmat);
- invert_m3_m3(imat, mat);
- mul_m3_v3(imat, newbone->tail);
-
- newbone->length = len_v3v3(newbone->head, newbone->tail);
- newbone->rad_tail = newbone->length * 0.05f;
- newbone->dist = newbone->length * 0.25f;
-
- }
-
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-static int armature_click_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- /* TODO most of this code is copied from set3dcursor_invoke,
- * it would be better to reuse code in set3dcursor_invoke */
-
- /* temporarily change 3d cursor position */
- Scene *scene;
- ARegion *ar;
- View3D *v3d;
- float *fp, tvec[3], oldcurs[3], mval_f[2];
- int retv;
-
- scene = CTX_data_scene(C);
- ar = CTX_wm_region(C);
- v3d = CTX_wm_view3d(C);
-
- fp = give_cursor(scene, v3d);
-
- copy_v3_v3(oldcurs, fp);
-
- VECCOPY2D(mval_f, event->mval);
- ED_view3d_win_to_3d(ar, fp, mval_f, tvec);
- copy_v3_v3(fp, tvec);
-
- /* extrude to the where new cursor is and store the operation result */
- retv = armature_click_extrude_exec(C, op);
-
- /* restore previous 3d cursor position */
- copy_v3_v3(fp, oldcurs);
-
- return retv;
-}
-
-void ARMATURE_OT_click_extrude(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Click-Extrude";
- ot->idname = "ARMATURE_OT_click_extrude";
- ot->description = "Create a new bone going from the last selected joint to the mouse position";
-
- /* api callbacks */
- ot->invoke = armature_click_extrude_invoke;
- ot->exec = armature_click_extrude_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
-}
-
-/* adds an EditBone between the nominated locations (should be in the right space) */
-static EditBone *add_points_bone(Object *obedit, float head[], float tail[])
-{
- EditBone *ebo;
-
- ebo = ED_armature_edit_bone_add(obedit->data, "Bone");
-
- copy_v3_v3(ebo->head, head);
- copy_v3_v3(ebo->tail, tail);
-
- return ebo;
-}
-
-
-static EditBone *get_named_editbone(ListBase *edbo, char *name)
-{
- EditBone *eBone;
-
- if (name) {
- for (eBone = edbo->first; eBone; eBone = eBone->next) {
- if (!strcmp(name, eBone->name))
- return eBone;
- }
- }
-
- return NULL;
-}
-
-/* Call this before doing any duplications
- * */
-void preEditBoneDuplicate(ListBase *editbones)
-{
- EditBone *eBone;
-
- /* clear temp */
- for (eBone = editbones->first; eBone; eBone = eBone->next) {
- eBone->temp = NULL;
- }
-}
-
-/*
- * Note: When duplicating cross objects, editbones here is the list of bones
- * from the SOURCE object but ob is the DESTINATION object
- * */
-void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Object *src_ob, Object *dst_ob)
-{
- /* If an edit bone has been duplicated, lets
- * update it's constraints if the subtarget
- * they point to has also been duplicated
- */
- EditBone *oldtarget, *newtarget;
- bPoseChannel *pchan;
- bConstraint *curcon;
- ListBase *conlist;
-
- if ( (pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name)) ) {
- if ( (conlist = &pchan->constraints) ) {
- for (curcon = conlist->first; curcon; curcon = curcon->next) {
- /* does this constraint have a subtarget in
- * this armature?
- */
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if ((ct->tar == src_ob) && (ct->subtarget[0])) {
- ct->tar = dst_ob; /* update target */
- oldtarget = get_named_editbone(editbones, ct->subtarget);
- if (oldtarget) {
- /* was the subtarget bone duplicated too? If
- * so, update the constraint to point at the
- * duplicate of the old subtarget.
- */
- if (oldtarget->temp) {
- newtarget = (EditBone *) oldtarget->temp;
- BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
- }
- }
- }
-}
-
-void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob)
-{
- updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob);
-}
-
-
-EditBone *duplicateEditBoneObjects(EditBone *curBone, const char *name, ListBase *editbones,
- Object *src_ob, Object *dst_ob)
-{
- EditBone *eBone = MEM_mallocN(sizeof(EditBone), "addup_editbone");
-
- /* Copy data from old bone to new bone */
- memcpy(eBone, curBone, sizeof(EditBone));
-
- curBone->temp = eBone;
- eBone->temp = curBone;
-
- if (name != NULL) {
- BLI_strncpy(eBone->name, name, sizeof(eBone->name));
- }
-
- unique_editbone_name(editbones, eBone->name, NULL);
- BLI_addtail(editbones, eBone);
-
- /* copy the ID property */
- if (curBone->prop)
- eBone->prop = IDP_CopyProperty(curBone->prop);
-
- /* Lets duplicate the list of constraints that the
- * current bone has.
- */
- if (src_ob->pose) {
- bPoseChannel *chanold, *channew;
-
- chanold = BKE_pose_channel_verify(src_ob->pose, curBone->name);
- if (chanold) {
- /* WARNING: this creates a new posechannel, but there will not be an attached bone
- * yet as the new bones created here are still 'EditBones' not 'Bones'.
- */
- channew = BKE_pose_channel_verify(dst_ob->pose, eBone->name);
-
- if (channew) {
- BKE_pose_channel_copy_data(channew, chanold);
- }
- }
- }
-
- return eBone;
-}
-
-EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editbones, Object *ob)
-{
- return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
-}
-
-/* previously adduplicate_armature */
-static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bArmature *arm;
- EditBone *eBone = NULL;
- EditBone *curBone;
- EditBone *firstDup = NULL; /* The beginning of the duplicated bones in the edbo list */
-
- Object *obedit = CTX_data_edit_object(C);
- arm = obedit->data;
-
- /* cancel if nothing selected */
- if (CTX_DATA_COUNT(C, selected_bones) == 0)
- return OPERATOR_CANCELLED;
-
- ED_armature_sync_selection(arm->edbo); // XXX why is this needed?
-
- preEditBoneDuplicate(arm->edbo);
-
- /* Select mirrored bones */
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
- eBone = ED_armature_bone_get_mirrored(arm->edbo, curBone);
- if (eBone)
- eBone->flag |= BONE_SELECTED;
- }
- }
- }
- }
-
-
- /* Find the selected bones and duplicate them as needed */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
-
- eBone = duplicateEditBone(curBone, curBone->name, arm->edbo, obedit);
-
- if (!firstDup)
- firstDup = eBone;
-
- }
- }
- }
-
- /* Run though the list and fix the pointers */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
- eBone = (EditBone *) curBone->temp;
-
- if (!curBone->parent) {
- /* If this bone has no parent,
- * Set the duplicate->parent to NULL
- */
- eBone->parent = NULL;
- }
- else if (curBone->parent->temp) {
- /* If this bone has a parent that was duplicated,
- * Set the duplicate->parent to the curBone->parent->temp
- */
- eBone->parent = (EditBone *)curBone->parent->temp;
- }
- else {
- /* If this bone has a parent that IS not selected,
- * Set the duplicate->parent to the curBone->parent
- */
- eBone->parent = (EditBone *) curBone->parent;
- eBone->flag &= ~BONE_CONNECTED;
- }
-
- /* Lets try to fix any constraint subtargets that might
- * have been duplicated
- */
- updateDuplicateSubtarget(eBone, arm->edbo, obedit);
- }
- }
- }
-
- /* correct the active bone */
- if (arm->act_edbone) {
- eBone = arm->act_edbone;
- if (eBone->temp)
- arm->act_edbone = eBone->temp;
- }
-
- /* Deselect the old bones and select the new ones */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone))
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
-
- ED_armature_validate_active(arm);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-
-void ARMATURE_OT_duplicate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Duplicate Selected Bone(s)";
- ot->idname = "ARMATURE_OT_duplicate";
- ot->description = "Make copies of the selected bones within the same armature";
-
- /* api callbacks */
- ot->exec = armature_duplicate_selected_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-/* *************** END Adding stuff in editmode *************** */
-/* ************** Add/Remove stuff in editmode **************** */
-
-/* temporary data-structure for merge/fill bones */
-typedef struct EditBonePoint {
- struct EditBonePoint *next, *prev;
-
- EditBone *head_owner; /* EditBone which uses this point as a 'head' point */
- EditBone *tail_owner; /* EditBone which uses this point as a 'tail' point */
-
- float vec[3]; /* the actual location of the point in local/EditMode space */
-} EditBonePoint;
-
-/* find chain-tips (i.e. bones without children) */
-static void chains_find_tips(ListBase *edbo, ListBase *list)
-{
- EditBone *curBone, *ebo;
- LinkData *ld;
-
- /* note: this is potentially very slow ... there's got to be a better way */
- for (curBone = edbo->first; curBone; curBone = curBone->next) {
- short stop = 0;
-
- /* is this bone contained within any existing chain? (skip if so) */
- for (ld = list->first; ld; ld = ld->next) {
- for (ebo = ld->data; ebo; ebo = ebo->parent) {
- if (ebo == curBone) {
- stop = 1;
- break;
- }
- }
-
- if (stop) break;
- }
- /* skip current bone if it is part of an existing chain */
- if (stop) continue;
-
- /* is any existing chain part of the chain formed by this bone? */
- stop = 0;
- for (ebo = curBone->parent; ebo; ebo = ebo->parent) {
- for (ld = list->first; ld; ld = ld->next) {
- if (ld->data == ebo) {
- ld->data = curBone;
- stop = 1;
- break;
- }
- }
-
- if (stop) break;
- }
- /* current bone has already been added to a chain? */
- if (stop) continue;
-
- /* add current bone to a new chain */
- ld = MEM_callocN(sizeof(LinkData), "BoneChain");
- ld->data = curBone;
- BLI_addtail(list, ld);
- }
-}
-
-/* --------------------- */
-
-static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points)
-{
- EditBonePoint *ebp;
- float vec[3];
- short found = 0;
-
- if (eb_tail) {
- copy_v3_v3(vec, ebo->tail);
- }
- else {
- copy_v3_v3(vec, ebo->head);
- }
-
- for (ebp = points->first; ebp; ebp = ebp->next) {
- if (equals_v3v3(ebp->vec, vec)) {
- if (eb_tail) {
- if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) {
- /* so this bone's tail owner is this bone */
- ebp->tail_owner = ebo;
- found = 1;
- break;
- }
- }
- else {
- if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) {
- /* so this bone's head owner is this bone */
- ebp->head_owner = ebo;
- found = 1;
- break;
- }
- }
- }
- }
-
- /* allocate a new point if no existing point was related */
- if (found == 0) {
- ebp = MEM_callocN(sizeof(EditBonePoint), "EditBonePoint");
-
- if (eb_tail) {
- copy_v3_v3(ebp->vec, ebo->tail);
- ebp->tail_owner = ebo;
- }
- else {
- copy_v3_v3(ebp->vec, ebo->head);
- ebp->head_owner = ebo;
- }
-
- BLI_addtail(points, ebp);
- }
-}
-
-/* bone adding between selected joints */
-static int armature_fill_bones_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = (obedit) ? obedit->data : NULL;
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- ListBase points = {NULL, NULL};
- int count;
-
- /* sanity checks */
- if (ELEM(NULL, obedit, arm))
- return OPERATOR_CANCELLED;
-
- /* loop over all bones, and only consider if visible */
- CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
- {
- if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL))
- fill_add_joint(ebone, 0, &points);
- if (ebone->flag & BONE_TIPSEL)
- fill_add_joint(ebone, 1, &points);
- }
- CTX_DATA_END;
-
- /* the number of joints determines how we fill:
- * 1) between joint and cursor (joint=head, cursor=tail)
- * 2) between the two joints (order is dependent on active-bone/hierachy)
- * 3+) error (a smarter method involving finding chains needs to be worked out
- */
- count = BLI_countlist(&points);
-
- if (count == 0) {
- BKE_report(op->reports, RPT_ERROR, "No joints selected");
- return OPERATOR_CANCELLED;
- }
- else if (count == 1) {
- EditBonePoint *ebp;
- float curs[3];
-
- /* Get Points - selected joint */
- ebp = (EditBonePoint *)points.first;
-
- /* Get points - cursor (tail) */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d));
-
- /* Create a bone */
- /* newbone = */ add_points_bone(obedit, ebp->vec, curs);
- }
- else if (count == 2) {
- EditBonePoint *ebp, *ebp2;
- float head[3], tail[3];
- short headtail = 0;
-
- /* check that the points don't belong to the same bone */
- ebp = (EditBonePoint *)points.first;
- ebp2 = ebp->next;
-
- if ((ebp->head_owner == ebp2->tail_owner) && (ebp->head_owner != NULL)) {
- BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
- if ((ebp->tail_owner == ebp2->head_owner) && (ebp->tail_owner != NULL)) {
- BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
-
- /* find which one should be the 'head' */
- if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) {
- /* rule: whichever one is closer to 3d-cursor */
- float curs[3];
- float vecA[3], vecB[3];
- float distA, distB;
-
- /* get cursor location */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d));
-
- /* get distances */
- sub_v3_v3v3(vecA, ebp->vec, curs);
- sub_v3_v3v3(vecB, ebp2->vec, curs);
- distA = len_v3(vecA);
- distB = len_v3(vecB);
-
- /* compare distances - closer one therefore acts as direction for bone to go */
- headtail = (distA < distB) ? 2 : 1;
- }
- else if (ebp->head_owner) {
- headtail = 1;
- }
- else if (ebp2->head_owner) {
- headtail = 2;
- }
-
- /* assign head/tail combinations */
- if (headtail == 2) {
- copy_v3_v3(head, ebp->vec);
- copy_v3_v3(tail, ebp2->vec);
- }
- else if (headtail == 1) {
- copy_v3_v3(head, ebp2->vec);
- copy_v3_v3(tail, ebp->vec);
- }
-
- /* add new bone and parent it to the appropriate end */
- if (headtail) {
- EditBone *newbone = add_points_bone(obedit, head, tail);
-
- /* do parenting (will need to set connected flag too) */
- if (headtail == 2) {
- /* ebp tail or head - tail gets priority */
- if (ebp->tail_owner)
- newbone->parent = ebp->tail_owner;
- else
- newbone->parent = ebp->head_owner;
- }
- else {
- /* ebp2 tail or head - tail gets priority */
- if (ebp2->tail_owner)
- newbone->parent = ebp2->tail_owner;
- else
- newbone->parent = ebp2->head_owner;
- }
-
- newbone->flag |= BONE_CONNECTED;
- }
- }
- else {
- /* FIXME.. figure out a method for multiple bones */
- BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count);
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
-
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
-
- /* free points */
- BLI_freelistN(&points);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_fill(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Fill Between Joints";
- ot->idname = "ARMATURE_OT_fill";
- ot->description = "Add bone between selected joint(s) and/or 3D-Cursor";
-
- /* callbacks */
- ot->exec = armature_fill_bones_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* --------------------- */
-
-/* this function merges between two bones, removes them and those in-between,
- * and adjusts the parent relationships for those in-between
- */
-static void bones_merge(Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains)
-{
- bArmature *arm = obedit->data;
- EditBone *ebo, *ebone, *newbone;
- LinkData *chain;
- float head[3], tail[3];
-
- /* check if same bone */
- if (start == end) {
- if (G.debug & G_DEBUG) {
- printf("Error: same bone!\n");
- printf("\tstart = %s, end = %s\n", start->name, end->name);
- }
- }
-
- /* step 1: add a new bone
- * - head = head/tail of start (default head)
- * - tail = head/tail of end (default tail)
- * - parent = parent of start
- */
- if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) {
- copy_v3_v3(head, start->tail);
- }
- else {
- copy_v3_v3(head, start->head);
- }
- if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) {
- copy_v3_v3(tail, end->head);
- }
- else {
- copy_v3_v3(tail, end->tail);
- }
- newbone = add_points_bone(obedit, head, tail);
- newbone->parent = start->parent;
-
- /* TODO, copy more things to the new bone */
- newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE |
- BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE);
-
- /* step 2a: reparent any side chains which may be parented to any bone in the chain of bones to merge
- * - potentially several tips for side chains leading to some tree exist...
- */
- for (chain = chains->first; chain; chain = chain->next) {
- /* traverse down chain until we hit the bottom or if we run into the tip of the chain of bones we're
- * merging (need to stop in this case to avoid corrupting this chain too!)
- */
- for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) {
- short found = 0;
-
- /* check if this bone is parented to one in the merging chain
- * ! WATCHIT: must only go check until end of checking chain
- */
- for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) {
- /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */
- if (ebone->parent == ebo) {
- ebone->parent = newbone;
- found = 1;
- break;
- }
- }
-
- /* carry on to the next tip now */
- if (found)
- break;
- }
- }
-
- /* step 2b: parent child of end to newbone (child from this chain) */
- if (endchild)
- endchild->parent = newbone;
-
- /* step 3: delete all bones between and including start and end */
- for (ebo = end; ebo; ebo = ebone) {
- ebone = (ebo == start) ? (NULL) : (ebo->parent);
- bone_free(arm, ebo);
- }
-
- newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
- ED_armature_sync_selection(arm->edbo);
-}
-
-
-static int armature_merge_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = (obedit) ? obedit->data : NULL;
- short type = RNA_enum_get(op->ptr, "type");
-
- /* sanity checks */
- if (ELEM(NULL, obedit, arm))
- return OPERATOR_CANCELLED;
-
- /* for now, there's only really one type of merging that's performed... */
- if (type == 1) {
- /* go down chains, merging bones */
- ListBase chains = {NULL, NULL};
- LinkData *chain, *nchain;
- EditBone *ebo;
-
- armature_tag_select_mirrored(arm);
-
- /* get chains (ends on chains) */
- chains_find_tips(arm->edbo, &chains);
- if (chains.first == NULL) return OPERATOR_CANCELLED;
-
- /* each 'chain' is the last bone in the chain (with no children) */
- for (chain = chains.first; chain; chain = nchain) {
- EditBone *bstart = NULL, *bend = NULL;
- EditBone *bchild = NULL, *child = NULL;
-
- /* temporarily remove chain from list of chains */
- nchain = chain->next;
- BLI_remlink(&chains, chain);
-
- /* only consider bones that are visible and selected */
- for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
- /* check if visible + selected */
- if (EBONE_VISIBLE(arm, ebo) &&
- ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
- (ebo->flag & BONE_SELECTED) )
- {
- /* set either end or start (end gets priority, unless it is already set) */
- if (bend == NULL) {
- bend = ebo;
- bchild = child;
- }
- else
- bstart = ebo;
- }
- else {
- /* chain is broken... merge any continous segments then clear */
- if (bstart && bend)
- bones_merge(obedit, bstart, bend, bchild, &chains);
-
- bstart = NULL;
- bend = NULL;
- bchild = NULL;
- }
- }
-
- /* merge from bstart to bend if something not merged */
- if (bstart && bend)
- bones_merge(obedit, bstart, bend, bchild, &chains);
-
- /* put back link */
- BLI_insertlinkbefore(&chains, nchain, chain);
- }
-
- armature_tag_unselect(arm);
-
- BLI_freelistN(&chains);
- }
-
- /* updates */
- ED_armature_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_merge(wmOperatorType *ot)
-{
- static EnumPropertyItem merge_types[] = {
- {1, "WITHIN_CHAIN", 0, "Within Chains", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Merge Bones";
- ot->idname = "ARMATURE_OT_merge";
- ot->description = "Merge continuous chains of selected bones";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_merge_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", merge_types, 0, "Type", "");
-}
-
-/* ************** END Add/Remove stuff in editmode ************ */
-/* *************** Tools in editmode *********** */
-
-static int armature_hide_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone;
- const int invert = RNA_boolean_get(op->ptr, "unselected") ? BONE_SELECTED : 0;
-
- /* cancel if nothing selected */
- if (CTX_DATA_COUNT(C, selected_bones) == 0)
- return OPERATOR_CANCELLED;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if ((ebone->flag & BONE_SELECTED) != invert) {
- ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- ebone->flag |= BONE_HIDDEN_A;
- }
- }
- }
- ED_armature_validate_active(arm);
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_hide(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Hide Selected Bones";
- ot->idname = "ARMATURE_OT_hide";
- ot->description = "Tag selected bones to not be visible in Edit Mode";
-
- /* api callbacks */
- ot->exec = armature_hide_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
-}
-
-static int armature_reveal_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (arm->layer & ebone->layer) {
- if (ebone->flag & BONE_HIDDEN_A) {
- ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- ebone->flag &= ~BONE_HIDDEN_A;
- }
- }
- }
- ED_armature_validate_active(arm);
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_reveal(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Reveal Bones";
- ot->idname = "ARMATURE_OT_reveal";
- ot->description = "Unhide all bones that have been tagged to be hidden in Edit Mode";
-
- /* api callbacks */
- ot->exec = armature_reveal_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
-}
-#if 0 // remove this?
-static void hide_selected_armature_bones(Scene *scene)
-{
- Object *obedit = scene->obedit; // XXX get from context
- bArmature *arm = obedit->data;
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_SELECTED) {
- ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- ebone->flag |= BONE_HIDDEN_A;
- }
- }
- }
- ED_armature_validate_active(arm);
- ED_armature_sync_selection(arm->edbo);
-}
-
-static void hide_unselected_armature_bones(Scene *scene)
-{
- Object *obedit = scene->obedit; // XXX get from context
- bArmature *arm = obedit->data;
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- bArmature *arm = obedit->data;
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL)) {
- /* pass */
- }
- else {
- ebone->flag |= BONE_HIDDEN_A;
- }
- }
- }
-
- ED_armature_validate_active(arm);
- ED_armature_sync_selection(arm->edbo);
-}
-
-void show_all_armature_bones(Scene *scene)
-{
- Object *obedit = scene->obedit; // XXX get from context
- bArmature *arm = obedit->data;
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (arm->layer & ebone->layer) {
- if (ebone->flag & BONE_HIDDEN_A) {
- ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- ebone->flag &= ~BONE_HIDDEN_A;
- }
- }
- }
- ED_armature_validate_active(arm);
- ED_armature_sync_selection(arm->edbo);
-}
-#endif
-
-/* previously extrude_armature */
-/* context; editmode armature */
-/* if forked && mirror-edit: makes two bones with flipped names */
-static int armature_extrude_exec(bContext *C, wmOperator *op)
-{
- Object *obedit;
- bArmature *arm;
- EditBone *newbone, *ebone, *flipbone, *first = NULL;
- int a, totbone = 0, do_extrude;
- int forked = RNA_boolean_get(op->ptr, "forked");
-
- obedit = CTX_data_edit_object(C);
- arm = obedit->data;
-
- /* since we allow root extrude too, we have to make sure selection is OK */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_ROOTSEL) {
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- if (ebone->parent->flag & BONE_TIPSEL)
- ebone->flag &= ~BONE_ROOTSEL;
- }
- }
- }
- }
-
- /* Duplicate the necessary bones */
- for (ebone = arm->edbo->first; ((ebone) && (ebone != first)); ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- /* we extrude per definition the tip */
- do_extrude = FALSE;
- if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED)) {
- do_extrude = TRUE;
- }
- else if (ebone->flag & BONE_ROOTSEL) {
- /* but, a bone with parent deselected we do the root... */
- if (ebone->parent && (ebone->parent->flag & BONE_TIPSEL)) {
- /* pass */
- }
- else {
- do_extrude = 2;
- }
- }
-
- if (do_extrude) {
- /* we re-use code for mirror editing... */
- flipbone = NULL;
- if (arm->flag & ARM_MIRROR_EDIT) {
- flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone);
- if (flipbone) {
- forked = 0; // we extrude 2 different bones
- if (flipbone->flag & (BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED))
- /* don't want this bone to be selected... */
- flipbone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- }
- if ((flipbone == NULL) && (forked))
- flipbone = ebone;
- }
-
- for (a = 0; a < 2; a++) {
- if (a == 1) {
- if (flipbone == NULL)
- break;
- else {
- SWAP(EditBone *, flipbone, ebone);
- }
- }
-
- totbone++;
- newbone = MEM_callocN(sizeof(EditBone), "extrudebone");
-
- if (do_extrude == TRUE) {
- copy_v3_v3(newbone->head, ebone->tail);
- copy_v3_v3(newbone->tail, newbone->head);
- newbone->parent = ebone;
-
- newbone->flag = ebone->flag & (BONE_TIPSEL | BONE_RELATIVE_PARENTING); // copies it, in case mirrored bone
-
- if (newbone->parent) newbone->flag |= BONE_CONNECTED;
- }
- else {
- copy_v3_v3(newbone->head, ebone->head);
- copy_v3_v3(newbone->tail, ebone->head);
- newbone->parent = ebone->parent;
-
- newbone->flag = BONE_TIPSEL;
-
- if (newbone->parent && (ebone->flag & BONE_CONNECTED)) {
- newbone->flag |= BONE_CONNECTED;
- }
- }
-
- newbone->weight = ebone->weight;
- newbone->dist = ebone->dist;
- newbone->xwidth = ebone->xwidth;
- newbone->zwidth = ebone->zwidth;
- newbone->ease1 = ebone->ease1;
- newbone->ease2 = ebone->ease2;
- newbone->rad_head = ebone->rad_tail; // don't copy entire bone...
- newbone->rad_tail = ebone->rad_tail;
- newbone->segments = 1;
- newbone->layer = ebone->layer;
-
- BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name));
-
- if (flipbone && forked) { // only set if mirror edit
- if (strlen(newbone->name) < 30) {
- if (a == 0) strcat(newbone->name, "_L");
- else strcat(newbone->name, "_R");
- }
- }
- unique_editbone_name(arm->edbo, newbone->name, NULL);
-
- /* Add the new bone to the list */
- BLI_addtail(arm->edbo, newbone);
- if (!first)
- first = newbone;
-
- /* restore ebone if we were flipping */
- if (a == 1 && flipbone)
- SWAP(EditBone *, flipbone, ebone);
- }
- }
-
- /* Deselect the old bone */
- ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- }
- }
- /* if only one bone, make this one active */
- if (totbone == 1 && first) arm->act_edbone = first;
-
- if (totbone == 0) return OPERATOR_CANCELLED;
-
- /* Transform the endpoints */
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_extrude(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Extrude";
- ot->idname = "ARMATURE_OT_extrude";
- ot->description = "Create new bones from the selected joints";
-
- /* api callbacks */
- ot->exec = armature_extrude_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- RNA_def_boolean(ot->srna, "forked", 0, "Forked", "");
-}
-/* ********************** Bone Add ********************/
-
-/*op makes a new bone and returns it with its tip selected */
-
-static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
-{
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- Object *obedit = CTX_data_edit_object(C);
- EditBone *bone;
- float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
- char name[MAXBONENAME];
-
- RNA_string_get(op->ptr, "name", name);
-
- copy_v3_v3(curs, give_cursor(CTX_data_scene(C), CTX_wm_view3d(C)));
-
- /* Get inverse point for head and orientation for tail */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_m4_v3(obedit->imat, curs);
-
- if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
- copy_m3_m4(obmat, rv3d->viewmat);
- else unit_m3(obmat);
-
- copy_m3_m4(viewmat, obedit->obmat);
- mul_m3_m3m3(totmat, obmat, viewmat);
- invert_m3_m3(imat, totmat);
-
- ED_armature_deselect_all(obedit, 0);
-
- /* Create a bone */
- bone = ED_armature_edit_bone_add(obedit->data, name);
-
- copy_v3_v3(bone->head, curs);
-
- if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
- add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1
- else
- add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_bone_primitive_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Bone";
- ot->idname = "ARMATURE_OT_bone_primitive_add";
- ot->description = "Add a new bone located at the 3D-Cursor";
-
- /* api callbacks */
- ot->exec = armature_bone_primitive_add_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_string(ot->srna, "name", "Bone", MAXBONENAME, "Name", "Name of the newly created bone");
-
-}
-
-
-/* ----------- */
-
-/* Subdivide Operators:
- * This group of operators all use the same 'exec' callback, but they are called
- * through several different operators - a combined menu (which just calls the exec in the
- * appropriate ways), and two separate ones.
- */
-
-static int armature_subdivide_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *newbone, *tbone;
- int cuts, i;
-
- /* there may not be a number_cuts property defined (for 'simple' subdivide) */
- cuts = RNA_int_get(op->ptr, "number_cuts");
-
- /* loop over all editable bones */
- // XXX the old code did this in reverse order though!
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- for (i = cuts + 1; i > 1; i--) {
- /* compute cut ratio first */
- float cutratio = 1.0f / (float)i;
- float cutratioI = 1.0f - cutratio;
-
- float val1[3];
- float val2[3];
- float val3[3];
-
- newbone = MEM_mallocN(sizeof(EditBone), "ebone subdiv");
- *newbone = *ebone;
- BLI_addtail(arm->edbo, newbone);
-
- /* calculate location of newbone->head */
- copy_v3_v3(val1, ebone->head);
- copy_v3_v3(val2, ebone->tail);
- copy_v3_v3(val3, newbone->head);
-
- val3[0] = val1[0] * cutratio + val2[0] * cutratioI;
- val3[1] = val1[1] * cutratio + val2[1] * cutratioI;
- val3[2] = val1[2] * cutratio + val2[2] * cutratioI;
-
- copy_v3_v3(newbone->head, val3);
- copy_v3_v3(newbone->tail, ebone->tail);
- copy_v3_v3(ebone->tail, newbone->head);
-
- newbone->rad_head = 0.5f * (ebone->rad_head + ebone->rad_tail);
- ebone->rad_tail = newbone->rad_head;
-
- newbone->flag |= BONE_CONNECTED;
-
- unique_editbone_name(arm->edbo, newbone->name, NULL);
-
- /* correct parent bones */
- for (tbone = arm->edbo->first; tbone; tbone = tbone->next) {
- if (tbone->parent == ebone)
- tbone->parent = newbone;
- }
- newbone->parent = ebone;
- }
- }
- CTX_DATA_END;
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_subdivide(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Subdivide Multi";
- ot->idname = "ARMATURE_OT_subdivide";
- ot->description = "Break selected bones into chains of smaller bones";
-
- /* api callbacks */
- ot->exec = armature_subdivide_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* Properties */
- prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
- /* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-/* ----------- */
-
-/* Switch Direction operator:
- * Currently, this does not use context loops, as context loops do not make it
- * easy to retrieve any hierarchical/chain relationships which are necessary for
- * this to be done easily.
- */
-
-/* helper to clear BONE_TRANSFORM flags */
-static void armature_clear_swap_done_flags(bArmature *arm)
-{
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- ebone->flag &= ~BONE_TRANSFORM;
- }
-}
-
-static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- ListBase chains = {NULL, NULL};
- LinkData *chain;
-
- /* get chains of bones (ends on chains) */
- chains_find_tips(arm->edbo, &chains);
- if (chains.first == NULL) return OPERATOR_CANCELLED;
-
- /* ensure that mirror bones will also be operated on */
- armature_tag_select_mirrored(arm);
-
- /* clear BONE_TRANSFORM flags
- * - used to prevent duplicate/cancelling operations from occurring [#34123]
- * - BONE_DONE cannot be used here as that's already used for mirroring
- */
- armature_clear_swap_done_flags(arm);
-
- /* loop over chains, only considering selected and visible bones */
- for (chain = chains.first; chain; chain = chain->next) {
- EditBone *ebo, *child = NULL, *parent = NULL;
-
- /* loop over bones in chain */
- for (ebo = chain->data; ebo; ebo = parent) {
- /* parent is this bone's original parent
- * - we store this, as the next bone that is checked is this one
- * but the value of ebo->parent may change here...
- */
- parent = ebo->parent;
-
- /* skip bone if already handled... [#34123] */
- if ((ebo->flag & BONE_TRANSFORM) == 0) {
- /* only if selected and editable */
- if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
- /* swap head and tail coordinates */
- SWAP(float, ebo->head[0], ebo->tail[0]);
- SWAP(float, ebo->head[1], ebo->tail[1]);
- SWAP(float, ebo->head[2], ebo->tail[2]);
-
- /* do parent swapping:
- * - use 'child' as new parent
- * - connected flag is only set if points are coincidental
- */
- ebo->parent = child;
- if ((child) && equals_v3v3(ebo->head, child->tail))
- ebo->flag |= BONE_CONNECTED;
- else
- ebo->flag &= ~BONE_CONNECTED;
-
- /* get next bones
- * - child will become the new parent of next bone
- */
- child = ebo;
- }
- else {
- /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it
- * as it will be facing in opposite direction
- */
- if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
- ebo->parent = NULL;
- ebo->flag &= ~BONE_CONNECTED;
- }
-
- /* get next bones
- * - child will become new parent of next bone (not swapping occurred,
- * so set to NULL to prevent infinite-loop)
- */
- child = NULL;
- }
-
- /* tag as done (to prevent double-swaps) */
- ebo->flag |= BONE_TRANSFORM;
- }
- }
- }
-
- /* free chains */
- BLI_freelistN(&chains);
-
- /* clear temp flags */
- armature_clear_swap_done_flags(arm);
- armature_tag_unselect(arm);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_switch_direction(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Switch Direction";
- ot->idname = "ARMATURE_OT_switch_direction";
- ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)";
-
- /* api callbacks */
- ot->exec = armature_switch_direction_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-/* ***************** Parenting *********************** */
-
-/* armature parenting options */
-#define ARM_PAR_CONNECT 1
-#define ARM_PAR_OFFSET 2
-
-/* check for null, before calling! */
-static void bone_connect_to_existing_parent(EditBone *bone)
-{
- bone->flag |= BONE_CONNECTED;
- copy_v3_v3(bone->head, bone->parent->tail);
- bone->rad_head = bone->parent->rad_tail;
-}
-
-static void bone_connect_to_new_parent(ListBase *edbo, EditBone *selbone, EditBone *actbone, short mode)
-{
- EditBone *ebone;
- float offset[3];
-
- if ((selbone->parent) && (selbone->flag & BONE_CONNECTED))
- selbone->parent->flag &= ~(BONE_TIPSEL);
-
- /* make actbone the parent of selbone */
- selbone->parent = actbone;
-
- /* in actbone tree we cannot have a loop */
- for (ebone = actbone->parent; ebone; ebone = ebone->parent) {
- if (ebone->parent == selbone) {
- ebone->parent = NULL;
- ebone->flag &= ~BONE_CONNECTED;
- }
- }
-
- if (mode == ARM_PAR_CONNECT) {
- /* Connected: Child bones will be moved to the parent tip */
- selbone->flag |= BONE_CONNECTED;
- sub_v3_v3v3(offset, actbone->tail, selbone->head);
-
- copy_v3_v3(selbone->head, actbone->tail);
- selbone->rad_head = actbone->rad_tail;
-
- add_v3_v3(selbone->tail, offset);
-
- /* offset for all its children */
- for (ebone = edbo->first; ebone; ebone = ebone->next) {
- EditBone *par;
-
- for (par = ebone->parent; par; par = par->parent) {
- if (par == selbone) {
- add_v3_v3(ebone->head, offset);
- add_v3_v3(ebone->tail, offset);
- break;
- }
- }
- }
- }
- else {
- /* Offset: Child bones will retain their distance from the parent tip */
- selbone->flag &= ~BONE_CONNECTED;
- }
-}
-
-static EnumPropertyItem prop_editarm_make_parent_types[] = {
- {ARM_PAR_CONNECT, "CONNECTED", 0, "Connected", ""},
- {ARM_PAR_OFFSET, "OFFSET", 0, "Keep Offset", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-static int armature_parent_set_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- EditBone *actbone = CTX_data_active_bone(C);
- EditBone *actmirb = NULL;
- short val = RNA_enum_get(op->ptr, "type");
-
- /* there must be an active bone */
- if (actbone == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
- return OPERATOR_CANCELLED;
- }
- else if (arm->flag & ARM_MIRROR_EDIT) {
- /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
- * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
- * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
- * This is useful for arm-chains, for example parenting lower arm to upper arm
- * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
- * then just use actbone. Useful when doing upper arm to spine.
- */
- actmirb = ED_armature_bone_get_mirrored(arm->edbo, actbone);
- if (actmirb == NULL)
- actmirb = actbone;
- }
-
- /* if there is only 1 selected bone, we assume that that is the active bone,
- * since a user will need to have clicked on a bone (thus selecting it) to make it active
- */
- if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) {
- /* When only the active bone is selected, and it has a parent,
- * connect it to the parent, as that is the only possible outcome.
- */
- if (actbone->parent) {
- bone_connect_to_existing_parent(actbone);
-
- if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
- bone_connect_to_existing_parent(actmirb);
- }
- }
- else {
- /* Parent 'selected' bones to the active one
- * - the context iterator contains both selected bones and their mirrored copies,
- * so we assume that unselected bones are mirrored copies of some selected bone
- * - since the active one (and/or its mirror) will also be selected, we also need
- * to check that we are not trying to operate on them, since such an operation
- * would cause errors
- */
-
- /* parent selected bones to the active one */
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- if (ELEM(ebone, actbone, actmirb) == 0) {
- if (ebone->flag & BONE_SELECTED)
- bone_connect_to_new_parent(arm->edbo, ebone, actbone, val);
- else
- bone_connect_to_new_parent(arm->edbo, ebone, actmirb, val);
- }
- }
- CTX_DATA_END;
- }
-
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
-{
- EditBone *actbone = CTX_data_active_bone(C);
- uiPopupMenu *pup = uiPupMenuBegin(C, "Make Parent ", ICON_NONE);
- uiLayout *layout = uiPupMenuLayout(pup);
- int allchildbones = 0;
-
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- if (ebone != actbone) {
- if (ebone->parent != actbone) allchildbones = 1;
- }
- }
- CTX_DATA_END;
-
- uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT);
-
- /* ob becomes parent, make the associated menus */
- if (allchildbones)
- uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET);
-
- uiPupMenuEnd(C, pup);
-
- return OPERATOR_CANCELLED;
-}
-
-void ARMATURE_OT_parent_set(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Make Parent";
- ot->idname = "ARMATURE_OT_parent_set";
- ot->description = "Set the active bone as the parent of the selected bones";
-
- /* api callbacks */
- ot->invoke = armature_parent_set_invoke;
- ot->exec = armature_parent_set_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(ot->srna, "type", prop_editarm_make_parent_types, 0, "ParentType", "Type of parenting");
-}
-
-static EnumPropertyItem prop_editarm_clear_parent_types[] = {
- {1, "CLEAR", 0, "Clear Parent", ""},
- {2, "DISCONNECT", 0, "Disconnect Bone", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-static void editbone_clear_parent(EditBone *ebone, int mode)
-{
- if (ebone->parent) {
- /* for nice selection */
- ebone->parent->flag &= ~(BONE_TIPSEL);
- }
-
- if (mode == 1) ebone->parent = NULL;
- ebone->flag &= ~BONE_CONNECTED;
-}
-
-static int armature_parent_clear_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- int val = RNA_enum_get(op->ptr, "type");
-
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- editbone_clear_parent(ebone, val);
- }
- CTX_DATA_END;
-
- ED_armature_sync_selection(arm->edbo);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_parent_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Parent";
- ot->idname = "ARMATURE_OT_parent_clear";
- ot->description = "Remove the parent-child relationship between selected bones and their parents";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_parent_clear_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- ot->prop = RNA_def_enum(ot->srna, "type", prop_editarm_clear_parent_types, 0, "ClearType", "What way to clear parenting");
-}
-
-/* **************** Selections ******************/
-
-static int armature_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
-{
- /* Set the flags */
- CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
- {
- /* ignore bone if selection can't change */
- if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
- /* select bone */
- ebone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
- CTX_DATA_END;
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_select_inverse(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Inverse";
- ot->idname = "ARMATURE_OT_select_inverse";
- ot->description = "Flip the selection status of bones (selected -> unselected, unselected -> selected)";
-
- /* api callbacks */
- ot->exec = armature_select_inverse_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
-}
-static int armature_de_select_all_exec(bContext *C, wmOperator *op)
-{
- int action = RNA_enum_get(op->ptr, "action");
-
- if (action == SEL_TOGGLE) {
- action = SEL_SELECT;
- /* Determine if there are any selected bones
- * And therefore whether we are selecting or deselecting */
- if (CTX_DATA_COUNT(C, selected_bones) > 0)
- action = SEL_DESELECT;
- }
-
- /* Set the flags */
- CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
- {
- /* ignore bone if selection can't change */
- if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
- switch (action) {
- case SEL_SELECT:
- ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (ebone->parent)
- ebone->parent->flag |= (BONE_TIPSEL);
- break;
- case SEL_DESELECT:
- ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- break;
- case SEL_INVERT:
- if (ebone->flag & BONE_SELECTED) {
- ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (ebone->parent)
- ebone->parent->flag |= (BONE_TIPSEL);
- }
- break;
- }
- }
- }
- CTX_DATA_END;
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_select_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "(De)select All";
- ot->idname = "ARMATURE_OT_select_all";
- ot->description = "Toggle selection status of all bones";
-
- /* api callbacks */
- ot->exec = armature_de_select_all_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- WM_operator_properties_select_all(ot);
-}
-
-enum {
- SIMEDBONE_LENGTH = 1,
- SIMEDBONE_DIRECTION,
- SIMEDBONE_PREFIX,
- SIMEDBONE_SUFFIX,
- SIMEDBONE_LAYER
-};
-
-static EnumPropertyItem prop_similar_types[] = {
- {SIMEDBONE_LENGTH, "LENGTH", 0, "Length", ""},
- {SIMEDBONE_DIRECTION, "DIRECTION", 0, "Direction (Y axis)", ""},
- {SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""},
- {SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""},
- {SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-/* could be used in more places */
-static void ED_armature_edit_bone_select(EditBone *ebone)
-{
- BLI_assert((ebone->flag & BONE_UNSELECTABLE) == 0);
- ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
-
- if ((ebone->flag & BONE_CONNECTED) && (ebone->parent != NULL)) {
- ebone->parent->flag |= BONE_TIPSEL;
- }
-}
-
-static void select_similar_length(bArmature *arm, EditBone *ebone_act, const float thresh)
-{
- EditBone *ebone;
-
- /* thresh is always relative to current length */
- const float len_min = ebone_act->length / (1.0f + thresh);
- const float len_max = ebone_act->length * (1.0f + thresh);
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- if ((ebone->length >= len_min) &&
- (ebone->length <= len_max))
- {
- ED_armature_edit_bone_select(ebone);
- }
- }
- }
-}
-
-static void select_similar_direction(bArmature *arm, EditBone *ebone_act, const float thresh)
-{
- EditBone *ebone;
- float dir_act[3];
- sub_v3_v3v3(dir_act, ebone_act->head, ebone_act->tail);
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- float dir[3];
- sub_v3_v3v3(dir, ebone->head, ebone->tail);
-
- if (angle_v3v3(dir_act, dir) / (float)M_PI < thresh) {
- ED_armature_edit_bone_select(ebone);
- }
- }
- }
-}
-
-static void select_similar_layer(bArmature *arm, EditBone *ebone_act)
-{
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- if (ebone->layer & ebone_act->layer) {
- ED_armature_edit_bone_select(ebone);
- }
- }
- }
-}
-
-static void select_similar_prefix(bArmature *arm, EditBone *ebone_act)
-{
- EditBone *ebone;
-
- char body_tmp[MAX_VGROUP_NAME];
- char prefix_act[MAX_VGROUP_NAME];
-
- BKE_deform_split_prefix(ebone_act->name, prefix_act, body_tmp);
-
- if (prefix_act[0] == '\0')
- return;
-
- /* Find matches */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- char prefix_other[MAX_VGROUP_NAME];
- BKE_deform_split_prefix(ebone->name, prefix_other, body_tmp);
- if (!strcmp(prefix_act, prefix_other)) {
- ED_armature_edit_bone_select(ebone);
- }
- }
- }
-}
-
-static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
-{
- EditBone *ebone;
-
- char body_tmp[MAX_VGROUP_NAME];
- char suffix_act[MAX_VGROUP_NAME];
-
- BKE_deform_split_suffix(ebone_act->name, body_tmp, suffix_act);
-
- if (suffix_act[0] == '\0')
- return;
-
- /* Find matches */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- char suffix_other[MAX_VGROUP_NAME];
- BKE_deform_split_suffix(ebone->name, body_tmp, suffix_other);
- if (!strcmp(suffix_act, suffix_other)) {
- ED_armature_edit_bone_select(ebone);
- }
- }
- }
-}
-
-static int armature_select_similar_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone_act = CTX_data_active_bone(C);
-
- /* Get props */
- int type = RNA_enum_get(op->ptr, "type");
- float thresh = RNA_float_get(op->ptr, "threshold");
-
- /* Check for active bone */
- if (ebone_act == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
- return OPERATOR_CANCELLED;
- }
-
- switch (type) {
- case SIMEDBONE_LENGTH:
- select_similar_length(arm, ebone_act, thresh);
- break;
- case SIMEDBONE_DIRECTION:
- select_similar_direction(arm, ebone_act, thresh);
- break;
- case SIMEDBONE_PREFIX:
- select_similar_prefix(arm, ebone_act);
- break;
- case SIMEDBONE_SUFFIX:
- select_similar_suffix(arm, ebone_act);
- break;
- case SIMEDBONE_LAYER:
- select_similar_layer(arm, ebone_act);
- break;
- }
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_select_similar(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Similar";
- ot->idname = "ARMATURE_OT_select_similar";
-
- /* callback functions */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_select_similar_exec;
- ot->poll = ED_operator_editarmature;
- ot->description = "Select similar bones by property types";
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, 0, "Type", "");
- RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
-}
-
-/* ********************* select hierarchy operator ************** */
-
-static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- Object *ob;
- bArmature *arm;
- EditBone *curbone, *pabone, *chbone;
- int direction = RNA_enum_get(op->ptr, "direction");
- int add_to_sel = RNA_boolean_get(op->ptr, "extend");
-
- ob = obedit;
- arm = (bArmature *)ob->data;
-
- for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
- /* only work on bone if it is visible and its selection can change */
- if (EBONE_SELECTABLE(arm, curbone)) {
- if (curbone == arm->act_edbone) {
- if (direction == BONE_SELECT_PARENT) {
- if (curbone->parent == NULL) continue;
- else pabone = curbone->parent;
-
- if (EBONE_VISIBLE(arm, pabone)) {
- pabone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_edbone = pabone;
- if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL;
-
- if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- break;
- }
-
- }
- else { // BONE_SELECT_CHILD
- chbone = editbone_get_child(arm, curbone, 1);
- if (chbone == NULL) continue;
-
- if (EBONE_SELECTABLE(arm, chbone)) {
- chbone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_edbone = chbone;
-
- if (!add_to_sel) {
- curbone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL);
- if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL;
- }
- break;
- }
- }
- }
- }
- }
-
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_select_hierarchy(wmOperatorType *ot)
-{
- static EnumPropertyItem direction_items[] = {
- {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
- {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Select Hierarchy";
- ot->idname = "ARMATURE_OT_select_hierarchy";
- ot->description = "Select immediate parent/children of selected bones";
-
- /* api callbacks */
- ot->exec = armature_select_hierarchy_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "direction", direction_items,
- BONE_SELECT_PARENT, "Direction", "");
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
-}
-
-/* ***************** EditBone Alignment ********************* */
-
-/* helper to fix a ebone position if its parent has moved due to alignment*/
-static void fix_connected_bone(EditBone *ebone)
-{
- float diff[3];
-
- if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || equals_v3v3(ebone->parent->tail, ebone->head))
- return;
-
- /* if the parent has moved we translate child's head and tail accordingly*/
- sub_v3_v3v3(diff, ebone->parent->tail, ebone->head);
- add_v3_v3(ebone->head, diff);
- add_v3_v3(ebone->tail, diff);
- return;
-}
-
-/* helper to recursively find chains of connected bones starting at ebone and fix their position */
-static void fix_editbone_connected_children(ListBase *edbo, EditBone *ebone)
-{
- EditBone *selbone;
-
- for (selbone = edbo->first; selbone; selbone = selbone->next) {
- if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
- fix_connected_bone(selbone);
- fix_editbone_connected_children(edbo, selbone);
- }
- }
- return;
-}
-
-static void bone_align_to_bone(ListBase *edbo, EditBone *selbone, EditBone *actbone)
-{
- float selboneaxis[3], actboneaxis[3], length;
-
- sub_v3_v3v3(actboneaxis, actbone->tail, actbone->head);
- normalize_v3(actboneaxis);
-
- sub_v3_v3v3(selboneaxis, selbone->tail, selbone->head);
- length = len_v3(selboneaxis);
-
- mul_v3_fl(actboneaxis, length);
- add_v3_v3v3(selbone->tail, selbone->head, actboneaxis);
- selbone->roll = actbone->roll;
-
- /* if the bone being aligned has connected descendants they must be moved
- * according to their parent new position, otherwise they would be left
- * in an inconsistent state: connected but away from the parent*/
- fix_editbone_connected_children(edbo, selbone);
- return;
-}
-
-static int armature_align_bones_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- EditBone *actbone = CTX_data_active_bone(C);
- EditBone *actmirb = NULL;
-
- /* there must be an active bone */
- if (actbone == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
- return OPERATOR_CANCELLED;
- }
- else if (arm->flag & ARM_MIRROR_EDIT) {
- /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
- * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
- * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
- * This is useful for arm-chains, for example parenting lower arm to upper arm
- * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
- * then just use actbone. Useful when doing upper arm to spine.
- */
- actmirb = ED_armature_bone_get_mirrored(arm->edbo, actbone);
- if (actmirb == NULL)
- actmirb = actbone;
- }
-
- /* if there is only 1 selected bone, we assume that that is the active bone,
- * since a user will need to have clicked on a bone (thus selecting it) to make it active
- */
- if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) {
- /* When only the active bone is selected, and it has a parent,
- * align it to the parent, as that is the only possible outcome.
- */
- if (actbone->parent) {
- bone_align_to_bone(arm->edbo, actbone, actbone->parent);
-
- if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
- bone_align_to_bone(arm->edbo, actmirb, actmirb->parent);
- }
- }
- else {
- /* Align 'selected' bones to the active one
- * - the context iterator contains both selected bones and their mirrored copies,
- * so we assume that unselected bones are mirrored copies of some selected bone
- * - since the active one (and/or its mirror) will also be selected, we also need
- * to check that we are not trying to operate on them, since such an operation
- * would cause errors
- */
-
- /* align selected bones to the active one */
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- if (ELEM(ebone, actbone, actmirb) == 0) {
- if (ebone->flag & BONE_SELECTED)
- bone_align_to_bone(arm->edbo, ebone, actbone);
- else
- bone_align_to_bone(arm->edbo, ebone, actmirb);
- }
- }
- CTX_DATA_END;
- }
-
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_align(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Align Bones";
- ot->idname = "ARMATURE_OT_align";
- ot->description = "Align selected bones to the active bone (or to their parent)";
-
- /* api callbacks */
- ot->invoke = WM_operator_confirm;
- ot->exec = armature_align_bones_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ***************** Pose tools ********************* */
-
-/* XXX bone_looper is only to be used when we want to access settings
- * (i.e. editability/visibility/selected) that context doesn't offer */
-static int bone_looper(Object *ob, Bone *bone, void *data,
- int (*bone_func)(Object *, Bone *, void *))
-{
- /* We want to apply the function bone_func to every bone
- * in an armature -- feed bone_looper the first bone and
- * a pointer to the bone_func and watch it go!. The int count
- * can be useful for counting bones with a certain property
- * (e.g. skinnable)
- */
- int count = 0;
-
- if (bone) {
- /* only do bone_func if the bone is non null */
- count += bone_func(ob, bone, data);
-
- /* try to execute bone_func for the first child */
- count += bone_looper(ob, bone->childbase.first, data, bone_func);
-
- /* try to execute bone_func for the next bone at this
- * depth of the recursion.
- */
- count += bone_looper(ob, bone->next, data, bone_func);
- }
-
- return count;
-}
-
-/* called from editview.c, for mode-less pose selection */
-/* assumes scene obact and basact is still on old situation */
-int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits,
- short extend, short deselect, short toggle)
-{
- Object *ob = base->object;
- Bone *nearBone;
-
- if (!ob || !ob->pose) return 0;
-
- nearBone = get_bone_from_selectbuffer(scene, base, buffer, hits, 1);
-
- /* if the bone cannot be affected, don't do anything */
- if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
- Object *ob_act = OBACT;
- bArmature *arm = ob->data;
-
- /* since we do unified select, we don't shift+select a bone if the
- * armature object was not active yet.
- * note, special exception for armature mode so we can do multi-select
- * we could check for multi-select explicitly but think its fine to
- * always give predictable behavior in weight paint mode - campbell */
- if ((!extend && !deselect && !toggle) ||
- ((ob_act && (ob_act != ob) && (ob_act->mode & OB_MODE_WEIGHT_PAINT) == 0)))
- {
- ED_pose_deselectall(ob, 0);
- nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = nearBone;
- }
- else {
- if (extend) {
- nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = nearBone;
- }
- else if (deselect) {
- nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (toggle) {
- if (nearBone->flag & BONE_SELECTED) {
- /* if not active, we make it active */
- if (nearBone != arm->act_bone) {
- arm->act_bone = nearBone;
- }
- else {
- nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
- else {
- nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = nearBone;
- }
- }
- }
-
- if (ob_act) {
- /* in weightpaint we select the associated vertex group too */
- if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
- if (nearBone == arm->act_bone) {
- ED_vgroup_select_by_name(ob_act, nearBone->name);
- DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
- }
- }
- /* if there are some dependencies for visualizing armature state
- * (e.g. Mask Modifier in 'Armature' mode), force update
- */
- else if (arm->flag & ARM_HAS_VIZ_DEPS) {
- DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
- }
- }
- }
-
- return nearBone != NULL;
-}
-
-/* test==0: deselect all
- * test==1: swap select (apply to all the opposite of current situation)
- * test==2: only clear active tag
- * test==3: swap select (no test / inverse selection status of all independently)
- */
-void ED_pose_deselectall(Object *ob, int test)
-{
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
- int selectmode = 0;
-
- /* we call this from outliner too */
- if (ob->pose == NULL) {
- return;
- }
-
- /* Determine if we're selecting or deselecting */
- if (test == 1) {
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (PBONE_VISIBLE(arm, pchan->bone)) {
- if (pchan->bone->flag & BONE_SELECTED)
- break;
- }
- }
-
- if (pchan == NULL)
- selectmode = 1;
- }
- else if (test == 2)
- selectmode = 2;
-
- /* Set the flags accordingly */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* ignore the pchan if it isn't visible or if its selection cannot be changed */
- if ((pchan->bone->layer & arm->layer) && !(pchan->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
- if (test == 3) {
- pchan->bone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- if (selectmode == 0) pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- else if (selectmode == 1) pchan->bone->flag |= BONE_SELECTED;
- }
- }
- }
-}
-
-static int bone_skinnable_cb(Object *ob, Bone *bone, void *datap)
-{
- /* Bones that are deforming
- * are regarded to be "skinnable" and are eligible for
- * auto-skinning.
- *
- * This function performs 2 functions:
- *
- * a) It returns 1 if the bone is skinnable.
- * If we loop over all bones with this
- * function, we can count the number of
- * skinnable bones.
- * b) If the pointer data is non null,
- * it is treated like a handle to a
- * bone pointer -- the bone pointer
- * is set to point at this bone, and
- * the pointer the handle points to
- * is incremented to point to the
- * next member of an array of pointers
- * to bones. This way we can loop using
- * this function to construct an array of
- * pointers to bones that point to all
- * skinnable bones.
- */
- Bone ***hbone;
- int a, segments;
- struct { Object *armob; void *list; int heat; } *data = datap;
-
- if (!(ob->mode & OB_MODE_WEIGHT_PAINT) || !(bone->flag & BONE_HIDDEN_P)) {
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name))
- segments = bone->segments;
- else
- segments = 1;
-
- if (data->list != NULL) {
- hbone = (Bone ***) &data->list;
-
- for (a = 0; a < segments; a++) {
- **hbone = bone;
- ++*hbone;
- }
- }
- return segments;
- }
- }
- return 0;
-}
-
-static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
-{
- /* This group creates a vertex group to ob that has the
- * same name as bone (provided the bone is skinnable).
- * If such a vertex group aleady exist the routine exits.
- */
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (!defgroup_find_name(ob, bone->name)) {
- ED_vgroup_add_name(ob, bone->name);
- return 1;
- }
- }
- return 0;
-}
-
-static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
-{
- /* Bones that are deforming
- * are regarded to be "skinnable" and are eligible for
- * auto-skinning.
- *
- * This function performs 2 functions:
- *
- * a) If the bone is skinnable, it creates
- * a vertex group for ob that has
- * the name of the skinnable bone
- * (if one doesn't exist already).
- * b) If the pointer data is non null,
- * it is treated like a handle to a
- * bDeformGroup pointer -- the
- * bDeformGroup pointer is set to point
- * to the deform group with the bone's
- * name, and the pointer the handle
- * points to is incremented to point to the
- * next member of an array of pointers
- * to bDeformGroups. This way we can loop using
- * this function to construct an array of
- * pointers to bDeformGroups, all with names
- * of skinnable bones.
- */
- bDeformGroup ***hgroup, *defgroup = NULL;
- int a, segments;
- struct { Object *armob; void *list; int heat; } *data = datap;
- int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
- bArmature *arm = data->armob->data;
-
- if (!wpmode || !(bone->flag & BONE_HIDDEN_P)) {
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name))
- segments = bone->segments;
- else
- segments = 1;
-
- if (!wpmode || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED)))
- if (!(defgroup = defgroup_find_name(ob, bone->name)))
- defgroup = ED_vgroup_add_name(ob, bone->name);
-
- if (data->list != NULL) {
- hgroup = (bDeformGroup ***) &data->list;
-
- for (a = 0; a < segments; a++) {
- **hgroup = defgroup;
- ++*hgroup;
- }
- }
- return segments;
- }
- }
- return 0;
-}
-
-static void add_vgroups__mapFunc(void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
-{
- /* DerivedMesh mapFunc for getting final coords in weight paint mode */
-
- float (*verts)[3] = userData;
- copy_v3_v3(verts[index], co);
-}
-
-static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist,
- bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
- float (*root)[3], float (*tip)[3], int *selected, float scale)
-{
- /* Create vertex group weights from envelopes */
-
- Bone *bone;
- bDeformGroup *dgroup;
- float distance;
- int i, iflip, j;
-
- /* for each vertex in the mesh */
- for (i = 0; i < mesh->totvert; i++) {
- iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i) : 0;
-
- /* for each skinnable bone */
- for (j = 0; j < numbones; ++j) {
- if (!selected[j])
- continue;
-
- bone = bonelist[j];
- dgroup = dgrouplist[j];
-
- /* store the distance-factor from the vertex to the bone */
- distance = distfactor_to_bone(verts[i], root[j], tip[j],
- bone->rad_head * scale, bone->rad_tail * scale, bone->dist * scale);
-
- /* add the vert to the deform group if (weight != 0.0) */
- if (distance != 0.0f)
- ED_vgroup_vert_add(ob, dgroup, i, distance, WEIGHT_REPLACE);
- else
- ED_vgroup_vert_remove(ob, dgroup, i);
-
- /* do same for mirror */
- if (dgroupflip && dgroupflip[j] && iflip >= 0) {
- if (distance != 0.0f)
- ED_vgroup_vert_add(ob, dgroupflip[j], iflip, distance,
- WEIGHT_REPLACE);
- else
- ED_vgroup_vert_remove(ob, dgroupflip[j], iflip);
- }
- }
- }
-}
-
-static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par, int heat, int mirror)
-{
- /* This functions implements the automatic computation of vertex group
- * weights, either through envelopes or using a heat equilibrium.
- *
- * This function can be called both when parenting a mesh to an armature,
- * or in weightpaint + posemode. In the latter case selection is taken
- * into account and vertex weights can be mirrored.
- *
- * The mesh vertex positions used are either the final deformed coords
- * from the derivedmesh in weightpaint mode, the final subsurf coords
- * when parenting, or simply the original mesh coords.
- */
-
- bArmature *arm = par->data;
- Bone **bonelist, *bone;
- bDeformGroup **dgrouplist, **dgroupflip;
- bDeformGroup *dgroup;
- bPoseChannel *pchan;
- Mesh *mesh;
- Mat4 *bbone = NULL;
- float (*root)[3], (*tip)[3], (*verts)[3];
- int *selected;
- int numbones, vertsfilled = 0, i, j, segments = 0;
- int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
- struct { Object *armob; void *list; int heat; } looper_data;
-
- looper_data.armob = par;
- looper_data.heat = heat;
- looper_data.list = NULL;
-
- /* count the number of skinnable bones */
- numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
-
- if (numbones == 0)
- return;
-
- if (ED_vgroup_data_create(ob->data) == FALSE)
- return;
-
- /* create an array of pointer to bones that are skinnable
- * and fill it with all of the skinnable bones */
- bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist");
- looper_data.list = bonelist;
- bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
-
- /* create an array of pointers to the deform groups that
- * correspond to the skinnable bones (creating them
- * as necessary. */
- dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist");
- dgroupflip = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgroupflip");
-
- looper_data.list = dgrouplist;
- bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb);
-
- /* create an array of root and tip positions transformed into
- * global coords */
- root = MEM_callocN(numbones * sizeof(float) * 3, "root");
- tip = MEM_callocN(numbones * sizeof(float) * 3, "tip");
- selected = MEM_callocN(numbones * sizeof(int), "selected");
-
- for (j = 0; j < numbones; ++j) {
- bone = bonelist[j];
- dgroup = dgrouplist[j];
-
- /* handle bbone */
- if (heat) {
- if (segments == 0) {
- segments = 1;
- bbone = NULL;
-
- if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) {
- if (bone->segments > 1) {
- segments = bone->segments;
- bbone = b_bone_spline_setup(pchan, 1);
- }
- }
- }
-
- segments--;
- }
-
- /* compute root and tip */
- if (bbone) {
- mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
- if ((segments + 1) < bone->segments) {
- mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
- }
- else {
- copy_v3_v3(tip[j], bone->arm_tail);
- }
- }
- else {
- copy_v3_v3(root[j], bone->arm_head);
- copy_v3_v3(tip[j], bone->arm_tail);
- }
-
- mul_m4_v3(par->obmat, root[j]);
- mul_m4_v3(par->obmat, tip[j]);
-
- /* set selected */
- if (wpmode) {
- if ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))
- selected[j] = 1;
- }
- else
- selected[j] = 1;
-
- /* find flipped group */
- if (dgroup && mirror) {
- char name[MAXBONENAME];
-
- // 0 = don't strip off number extensions
- flip_side_name(name, dgroup->name, FALSE);
- dgroupflip[j] = defgroup_find_name(ob, name);
- }
- }
-
- /* create verts */
- mesh = (Mesh *)ob->data;
- verts = MEM_callocN(mesh->totvert * sizeof(*verts), "closestboneverts");
-
- if (wpmode) {
- /* if in weight paint mode, use final verts from derivedmesh */
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
-
- if (dm->foreachMappedVert) {
- dm->foreachMappedVert(dm, add_vgroups__mapFunc, (void *)verts);
- vertsfilled = 1;
- }
-
- dm->release(dm);
- }
- else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
- /* is subsurf on? Lets use the verts on the limit surface then.
- * = same amount of vertices as mesh, but vertices moved to the
- * subsurfed position, like for 'optimal'. */
- subsurf_calculate_limit_positions(mesh, verts);
- vertsfilled = 1;
- }
-
- /* transform verts to global space */
- for (i = 0; i < mesh->totvert; i++) {
- if (!vertsfilled)
- copy_v3_v3(verts[i], mesh->mvert[i].co);
- mul_m4_v3(ob->obmat, verts[i]);
- }
-
- /* compute the weights based on gathered vertices and bones */
- if (heat) {
- const char *error = NULL;
- heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip,
- root, tip, selected, &error);
-
- if (error) {
- BKE_report(reports, RPT_WARNING, error);
- }
- }
- else {
- envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist,
- dgroupflip, root, tip, selected, mat4_to_scale(par->obmat));
- }
-
- /* only generated in some cases but can call anyway */
- mesh_octree_table(ob, NULL, NULL, 'e');
-
- /* free the memory allocated */
- MEM_freeN(bonelist);
- MEM_freeN(dgrouplist);
- MEM_freeN(dgroupflip);
- MEM_freeN(root);
- MEM_freeN(tip);
- MEM_freeN(selected);
- MEM_freeN(verts);
-}
-
-void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par, int mode, int mirror)
-{
- /* Lets try to create some vertex groups
- * based on the bones of the parent armature.
- */
- bArmature *arm = par->data;
-
- if (mode == ARM_GROUPS_NAME) {
- const int defbase_tot = BLI_countlist(&ob->defbase);
- int defbase_add;
- /* Traverse the bone list, trying to create empty vertex
- * groups corresponding to the bone.
- */
- defbase_add = bone_looper(ob, arm->bonebase.first, NULL, vgroup_add_unique_bone_cb);
-
- if (defbase_add) {
- /* its possible there are DWeight's outside the range of the current
- * objects deform groups, in this case the new groups wont be empty [#33889] */
- ED_vgroup_data_clamp_range(ob->data, defbase_tot);
- }
- }
- else if (mode == ARM_GROUPS_ENVELOPE || mode == ARM_GROUPS_AUTO) {
- /* Traverse the bone list, trying to create vertex groups
- * that are populated with the vertices for which the
- * bone is closest.
- */
- add_verts_to_dgroups(reports, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror);
- }
-}
-/* ************* Clear Pose *****************************/
-
-/* clear scale of pose-channel */
-static void pchan_clear_scale(bPoseChannel *pchan)
-{
- if ((pchan->protectflag & OB_LOCK_SCALEX) == 0)
- pchan->size[0] = 1.0f;
- if ((pchan->protectflag & OB_LOCK_SCALEY) == 0)
- pchan->size[1] = 1.0f;
- if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0)
- pchan->size[2] = 1.0f;
-}
-
-/* clear location of pose-channel */
-static void pchan_clear_loc(bPoseChannel *pchan)
-{
- if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
- pchan->loc[0] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
- pchan->loc[1] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
- pchan->loc[2] = 0.0f;
-}
-
-/* clear rotation of pose-channel */
-static void pchan_clear_rot(bPoseChannel *pchan)
-{
- if (pchan->protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) {
- /* check if convert to eulers for locking... */
- if (pchan->protectflag & OB_LOCK_ROT4D) {
- /* perform clamping on a component by component basis */
- if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
- pchan->rotAngle = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
- pchan->rotAxis[0] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
- pchan->rotAxis[1] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
- pchan->rotAxis[2] = 0.0f;
-
- /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */
- if (IS_EQF(pchan->rotAxis[0], pchan->rotAxis[1]) && IS_EQF(pchan->rotAxis[1], pchan->rotAxis[2]))
- pchan->rotAxis[1] = 1.0f;
- }
- else if (pchan->rotmode == ROT_MODE_QUAT) {
- if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
- pchan->quat[0] = 1.0f;
- if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
- pchan->quat[1] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
- pchan->quat[2] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
- pchan->quat[3] = 0.0f;
- }
- else {
- /* the flag may have been set for the other modes, so just ignore the extra flag... */
- if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
- pchan->eul[0] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
- pchan->eul[1] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
- pchan->eul[2] = 0.0f;
- }
- }
- else {
- /* perform clamping using euler form (3-components) */
- float eul[3], oldeul[3], quat1[4] = {0};
- float qlen = 0.0f;
-
- if (pchan->rotmode == ROT_MODE_QUAT) {
- qlen = normalize_qt_qt(quat1, pchan->quat);
- quat_to_eul(oldeul, quat1);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
- }
- else {
- copy_v3_v3(oldeul, pchan->eul);
- }
-
- eul[0] = eul[1] = eul[2] = 0.0f;
-
- if (pchan->protectflag & OB_LOCK_ROTX)
- eul[0] = oldeul[0];
- if (pchan->protectflag & OB_LOCK_ROTY)
- eul[1] = oldeul[1];
- if (pchan->protectflag & OB_LOCK_ROTZ)
- eul[2] = oldeul[2];
-
- if (pchan->rotmode == ROT_MODE_QUAT) {
- eul_to_quat(pchan->quat, eul);
-
- /* restore original quat size */
- mul_qt_fl(pchan->quat, qlen);
-
- /* quaternions flip w sign to accumulate rotations correctly */
- if ((quat1[0] < 0.0f && pchan->quat[0] > 0.0f) || (quat1[0] > 0.0f && pchan->quat[0] < 0.0f)) {
- mul_qt_fl(pchan->quat, -1.0f);
- }
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
- }
- else {
- copy_v3_v3(pchan->eul, eul);
- }
- }
- } /* Duplicated in source/blender/editors/object/object_transform.c */
- else {
- if (pchan->rotmode == ROT_MODE_QUAT) {
- unit_qt(pchan->quat);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* by default, make rotation of 0 radians around y-axis (roll) */
- unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
- }
- else {
- zero_v3(pchan->eul);
- }
- }
-}
-
-/* clear loc/rot/scale of pose-channel */
-static void pchan_clear_transforms(bPoseChannel *pchan)
-{
- pchan_clear_loc(pchan);
- pchan_clear_rot(pchan);
- pchan_clear_scale(pchan);
-}
-
-/* --------------- */
-
-/* generic exec for clear-pose operators */
-static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op,
- void (*clear_func)(bPoseChannel *), const char default_ksName[])
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- short autokey = 0;
-
- /* sanity checks */
- if (ELEM(NULL, clear_func, default_ksName)) {
- BKE_report(op->reports, RPT_ERROR, "Programming error: missing clear transform function or keying set name");
- return OPERATOR_CANCELLED;
- }
-
- /* only clear relevant transforms for selected bones */
- CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones)
- {
- /* run provided clearing function */
- clear_func(pchan);
-
- /* do auto-keyframing as appropriate */
- if (autokeyframe_cfra_can_key(scene, &ob->id)) {
- /* clear any unkeyed tags */
- if (pchan->bone)
- pchan->bone->flag &= ~BONE_UNKEYED;
-
- /* tag for autokeying later */
- autokey = 1;
- }
- else {
- /* add unkeyed tags */
- if (pchan->bone)
- pchan->bone->flag |= BONE_UNKEYED;
- }
- }
- CTX_DATA_END;
-
- /* perform autokeying on the bones if needed */
- if (autokey) {
- /* get KeyingSet to use */
- KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
-
- /* insert keyframes */
- ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
-
- /* now recalculate paths */
- if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS))
- ED_pose_recalculate_paths(scene, ob);
- }
-
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
-
- return OPERATOR_FINISHED;
-}
-
-/* --------------- */
-
-static int pose_clear_scale_exec(bContext *C, wmOperator *op)
-{
- return pose_clear_transform_generic_exec(C, op, pchan_clear_scale, ANIM_KS_SCALING_ID);
-}
-
-void POSE_OT_scale_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Pose Scale";
- ot->idname = "POSE_OT_scale_clear";
- ot->description = "Reset scaling of selected bones to their default values";
-
- /* api callbacks */
- ot->exec = pose_clear_scale_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-static int pose_clear_rot_exec(bContext *C, wmOperator *op)
-{
- return pose_clear_transform_generic_exec(C, op, pchan_clear_rot, ANIM_KS_ROTATION_ID);
-}
-
-void POSE_OT_rot_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Pose Rotation";
- ot->idname = "POSE_OT_rot_clear";
- ot->description = "Reset rotations of selected bones to their default values";
-
- /* api callbacks */
- ot->exec = pose_clear_rot_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-static int pose_clear_loc_exec(bContext *C, wmOperator *op)
-{
- return pose_clear_transform_generic_exec(C, op, pchan_clear_loc, ANIM_KS_LOCATION_ID);
-}
-
-void POSE_OT_loc_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Pose Location";
- ot->idname = "POSE_OT_loc_clear";
- ot->description = "Reset locations of selected bones to their default values";
-
- /* api callbacks */
- ot->exec = pose_clear_loc_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-static int pose_clear_transforms_exec(bContext *C, wmOperator *op)
-{
- return pose_clear_transform_generic_exec(C, op, pchan_clear_transforms, ANIM_KS_LOC_ROT_SCALE_ID);
-}
-
-void POSE_OT_transforms_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Pose Transforms";
- ot->idname = "POSE_OT_transforms_clear";
- ot->description = "Reset location, rotation, and scaling of selected bones to their default values";
-
- /* api callbacks */
- ot->exec = pose_clear_transforms_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ***************** selections ********************** */
-
-static int pose_de_select_all_exec(bContext *C, wmOperator *op)
-{
- int action = RNA_enum_get(op->ptr, "action");
-
- Scene *scene = CTX_data_scene(C);
- Object *ob = ED_object_context(C);
- bArmature *arm = ob->data;
- int multipaint = scene->toolsettings->multipaint;
-
- if (action == SEL_TOGGLE) {
- action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT;
- }
-
- /* Set the flags */
- CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones)
- {
- /* select pchan only if selectable, but deselect works always */
- switch (action) {
- case SEL_SELECT:
- if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
- pchan->bone->flag |= BONE_SELECTED;
- break;
- case SEL_DESELECT:
- pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- break;
- case SEL_INVERT:
- if (pchan->bone->flag & BONE_SELECTED) {
- pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- pchan->bone->flag |= BONE_SELECTED;
- }
- break;
- }
- }
- CTX_DATA_END;
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
-
- /* weightpaint or mask modifiers need depsgraph updates */
- if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_select_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "(De)select All";
- ot->idname = "POSE_OT_select_all";
- ot->description = "Toggle selection status of all bones";
-
- /* api callbacks */
- ot->exec = pose_de_select_all_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- WM_operator_properties_select_all(ot);
-}
-
-static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
- bPoseChannel *pchan, *parent;
-
- /* Determine if there is an active bone */
- pchan = CTX_data_active_pose_bone(C);
- if (pchan) {
- parent = pchan->parent;
- if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
- parent->bone->flag |= BONE_SELECTED;
- arm->act_bone = parent->bone;
- }
- else {
- return OPERATOR_CANCELLED;
- }
- }
- else {
- return OPERATOR_CANCELLED;
- }
-
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_select_parent(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Parent Bone";
- ot->idname = "POSE_OT_select_parent";
- ot->description = "Select bones that are parents of the currently selected bones";
-
- /* api callbacks */
- ot->exec = pose_select_parent_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
-}
-
-/* ************* hide/unhide pose bones ******************* */
-
-static int hide_selected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
-{
- bArmature *arm = ob->data;
-
- if (arm->layer & bone->layer) {
- if (bone->flag & BONE_SELECTED) {
- bone->flag |= BONE_HIDDEN_P;
- bone->flag &= ~BONE_SELECTED;
- if (arm->act_bone == bone)
- arm->act_bone = NULL;
- }
- }
- return 0;
-}
-
-static int hide_unselected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
-{
- bArmature *arm = ob->data;
-
- if (arm->layer & bone->layer) {
- /* hrm... typo here? */
- if ((bone->flag & BONE_SELECTED) == 0) {
- bone->flag |= BONE_HIDDEN_P;
- if (arm->act_bone == bone)
- arm->act_bone = NULL;
- }
- }
- return 0;
-}
-
-/* active object is armature in posemode, poll checked */
-static int pose_hide_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = ob->data;
-
- if (RNA_boolean_get(op->ptr, "unselected"))
- bone_looper(ob, arm->bonebase.first, NULL, hide_unselected_pose_bone_cb);
- else
- bone_looper(ob, arm->bonebase.first, NULL, hide_selected_pose_bone_cb);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_hide(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Hide Selected";
- ot->idname = "POSE_OT_hide";
- ot->description = "Tag selected bones to not be visible in Pose Mode";
-
- /* api callbacks */
- ot->exec = pose_hide_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "");
-}
-
-static int show_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
-{
- bArmature *arm = ob->data;
-
- if (arm->layer & bone->layer) {
- if (bone->flag & BONE_HIDDEN_P) {
- bone->flag &= ~BONE_HIDDEN_P;
- bone->flag |= BONE_SELECTED;
- }
- }
-
- return 0;
-}
-
-/* active object is armature in posemode, poll checked */
-static int pose_reveal_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = ob->data;
-
- bone_looper(ob, arm->bonebase.first, NULL, show_pose_bone_cb);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_reveal(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Reveal Selected";
- ot->idname = "POSE_OT_reveal";
- ot->description = "Unhide all bones that have been tagged to be hidden in Pose Mode";
-
- /* api callbacks */
- ot->exec = pose_reveal_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ************* RENAMING DISASTERS ************ */
-
-static int bone_unique_check(void *arg, const char *name)
-{
- return BKE_armature_find_bone_name((bArmature *)arg, name) != NULL;
-}
-
-static void unique_bone_name(bArmature *arm, char *name)
-{
- BLI_uniquename_cb(bone_unique_check, (void *)arm, "Bone", '.', name, sizeof(((Bone *)NULL)->name));
-}
-
-/* helper call for armature_bone_rename */
-static void constraint_bone_name_fix(Object *ob, ListBase *conlist, char *oldname, char *newname)
-{
- bConstraint *curcon;
- bConstraintTarget *ct;
-
- for (curcon = conlist->first; curcon; curcon = curcon->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon);
- ListBase targets = {NULL, NULL};
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == ob) {
- if (!strcmp(ct->subtarget, oldname) )
- BLI_strncpy(ct->subtarget, newname, MAXBONENAME);
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
- }
-}
-
-/* called by UI for renaming a bone */
-/* warning: make sure the original bone was not renamed yet! */
-/* seems messy, but thats what you get with not using pointers but channel names :) */
-void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *newnamep)
-{
- Object *ob;
- char newname[MAXBONENAME];
- char oldname[MAXBONENAME];
-
- /* names better differ! */
- if (strncmp(oldnamep, newnamep, MAXBONENAME)) {
-
- /* we alter newname string... so make copy */
- BLI_strncpy(newname, newnamep, MAXBONENAME);
- /* we use oldname for search... so make copy */
- BLI_strncpy(oldname, oldnamep, MAXBONENAME);
-
- /* now check if we're in editmode, we need to find the unique name */
- if (arm->edbo) {
- EditBone *eBone = editbone_name_exists(arm->edbo, oldname);
-
- if (eBone) {
- unique_editbone_name(arm->edbo, newname, NULL);
- BLI_strncpy(eBone->name, newname, MAXBONENAME);
- }
- else return;
- }
- else {
- Bone *bone = BKE_armature_find_bone_name(arm, oldname);
-
- if (bone) {
- unique_bone_name(arm, newname);
- BLI_strncpy(bone->name, newname, MAXBONENAME);
- }
- else return;
- }
-
- /* do entire dbase - objects */
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
- ModifierData *md;
-
- /* we have the object using the armature */
- if (arm == ob->data) {
- Object *cob;
-
- /* Rename the pose channel, if it exists */
- if (ob->pose) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, oldname);
- if (pchan) {
- BLI_strncpy(pchan->name, newname, MAXBONENAME);
-
- if (ob->pose->chanhash) {
- GHash *gh = ob->pose->chanhash;
-
- /* remove the old hash entry, and replace with the new name */
- BLI_ghash_remove(gh, oldname, NULL, NULL);
- BLI_ghash_insert(gh, pchan->name, pchan);
- }
- }
- }
-
- /* Update any object constraints to use the new bone name */
- for (cob = G.main->object.first; cob; cob = cob->id.next) {
- if (cob->constraints.first)
- constraint_bone_name_fix(ob, &cob->constraints, oldname, newname);
- if (cob->pose) {
- bPoseChannel *pchan;
- for (pchan = cob->pose->chanbase.first; pchan; pchan = pchan->next) {
- constraint_bone_name_fix(ob, &pchan->constraints, oldname, newname);
- }
- }
- }
- }
-
- /* See if an object is parented to this armature */
- if (ob->parent && (ob->parent->data == arm)) {
- if (ob->partype == PARBONE) {
- /* bone name in object */
- if (!strcmp(ob->parsubstr, oldname))
- BLI_strncpy(ob->parsubstr, newname, MAXBONENAME);
- }
- }
-
- if (modifiers_usesArmature(ob, arm)) {
- bDeformGroup *dg = defgroup_find_name(ob, oldname);
- if (dg) {
- BLI_strncpy(dg->name, newname, MAXBONENAME);
- }
- }
-
- /* fix modifiers that might be using this name */
- for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Hook) {
- HookModifierData *hmd = (HookModifierData *)md;
-
- /* uses armature, so may use the affected bone name */
- if (hmd->object && (hmd->object->data == arm)) {
- if (!strcmp(hmd->subtarget, oldname))
- BLI_strncpy(hmd->subtarget, newname, MAXBONENAME);
- }
- }
- }
- }
-
- /* 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]
- */
- {
-
- BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname);
- }
-
- /* correct view locking */
- {
- bScreen *screen;
- for (screen = G.main->screen.first; screen; screen = screen->id.next) {
- ScrArea *sa;
- /* add regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- 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)) {
- BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME);
- }
- }
- }
- }
- }
- }
- }
- }
-}
-
-
-static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm;
- char newname[MAXBONENAME];
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
- arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- flip_side_name(newname, ebone->name, TRUE); // 1 = do strip off number extensions
- ED_armature_bone_rename(arm, ebone->name, newname);
- }
- CTX_DATA_END;
-
- /* since we renamed stuff... */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_flip_names(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Flip Names";
- ot->idname = "ARMATURE_OT_flip_names";
- ot->description = "Flips (and corrects) the axis suffixes of the names of selected bones";
-
- /* api callbacks */
- ot->exec = armature_flip_names_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-static int armature_autoside_names_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm;
- char newname[MAXBONENAME];
- short axis = RNA_enum_get(op->ptr, "type");
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
- arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- BLI_strncpy(newname, ebone->name, sizeof(newname));
- if (bone_autoside_name(newname, 1, axis, ebone->head[axis], ebone->tail[axis]))
- ED_armature_bone_rename(arm, ebone->name, newname);
- }
- CTX_DATA_END;
-
- /* since we renamed stuff... */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_autoside_names(wmOperatorType *ot)
-{
- static EnumPropertyItem axis_items[] = {
- {0, "XAXIS", 0, "X-Axis", "Left/Right"},
- {1, "YAXIS", 0, "Y-Axis", "Front/Back"},
- {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "AutoName by Axis";
- ot->idname = "ARMATURE_OT_autoside_names";
- ot->description = "Automatically renames the selected bones according to which side of the target axis they fall on";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_autoside_names_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* settings */
- ot->prop = RNA_def_enum(ot->srna, "type", axis_items, 0, "Axis", "Axis tag names with");
-}
-
-
-
-/* if editbone (partial) selected, copy data */
-/* context; editmode armature, with mirror editing enabled */
-void transform_armature_mirror_update(Object *obedit)
-{
- bArmature *arm = obedit->data;
- EditBone *ebo, *eboflip;
-
- for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
- /* no layer check, correct mirror is more important */
- if (ebo->flag & (BONE_TIPSEL | BONE_ROOTSEL)) {
- eboflip = ED_armature_bone_get_mirrored(arm->edbo, ebo);
-
- if (eboflip) {
- /* we assume X-axis flipping for now */
- if (ebo->flag & BONE_TIPSEL) {
- EditBone *children;
-
- eboflip->tail[0] = -ebo->tail[0];
- eboflip->tail[1] = ebo->tail[1];
- eboflip->tail[2] = ebo->tail[2];
- eboflip->rad_tail = ebo->rad_tail;
- eboflip->roll = -ebo->roll;
-
- /* Also move connected children, in case children's name aren't mirrored properly */
- for (children = arm->edbo->first; children; children = children->next) {
- if (children->parent == eboflip && children->flag & BONE_CONNECTED) {
- copy_v3_v3(children->head, eboflip->tail);
- children->rad_head = ebo->rad_tail;
- }
- }
- }
- if (ebo->flag & BONE_ROOTSEL) {
- eboflip->head[0] = -ebo->head[0];
- eboflip->head[1] = ebo->head[1];
- eboflip->head[2] = ebo->head[2];
- eboflip->rad_head = ebo->rad_head;
- eboflip->roll = -ebo->roll;
-
- /* Also move connected parent, in case parent's name isn't mirrored properly */
- if (eboflip->parent && eboflip->flag & BONE_CONNECTED) {
- EditBone *parent = eboflip->parent;
- copy_v3_v3(parent->tail, eboflip->head);
- parent->rad_tail = ebo->rad_head;
- }
- }
- if (ebo->flag & BONE_SELECTED) {
- eboflip->dist = ebo->dist;
- eboflip->roll = -ebo->roll;
- eboflip->xwidth = ebo->xwidth;
- eboflip->zwidth = ebo->zwidth;
- }
- }
- }
- }
-}
-
-
-/*****************************************************************************************************/
-/*************************************** SKELETON GENERATOR ******************************************/
-/*****************************************************************************************************/
-
-#if 0
-
-/**************************************** SUBDIVISION ALGOS ******************************************/
-
-EditBone *subdivideByAngle(Scene *scene, Object *obedit, ReebArc *arc, ReebNode *head, ReebNode *tail)
-{
- bArmature *arm = obedit->data;
- EditBone *lastBone = NULL;
-
- if (scene->toolsettings->skgen_options & SKGEN_CUT_ANGLE) {
- ReebArcIterator arc_iter;
- BArcIterator *iter = (BArcIterator *)&arc_iter;
- float *previous = NULL, *current = NULL;
- EditBone *child = NULL;
- EditBone *parent = NULL;
- EditBone *root = NULL;
- float angleLimit = (float)cos(scene->toolsettings->skgen_angle_limit * M_PI / 180.0f);
-
- parent = ED_armature_edit_bone_add(arm, "Bone");
- parent->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
- copy_v3_v3(parent->head, head->p);
-
- root = parent;
-
- initArcIterator(iter, arc, head);
- IT_next(iter);
- previous = iter->p;
-
- for (IT_next(iter);
- IT_stopped(iter) == 0;
- previous = iter->p, IT_next(iter))
- {
- float vec1[3], vec2[3];
- float len1, len2;
-
- current = iter->p;
-
- sub_v3_v3v3(vec1, previous, parent->head);
- sub_v3_v3v3(vec2, current, previous);
-
- len1 = normalize_v3(vec1);
- len2 = normalize_v3(vec2);
-
- if (len1 > 0.0f && len2 > 0.0f && dot_v3v3(vec1, vec2) < angleLimit) {
- copy_v3_v3(parent->tail, previous);
-
- child = ED_armature_edit_bone_add(arm, "Bone");
- copy_v3_v3(child->head, parent->tail);
- child->parent = parent;
- child->flag |= BONE_CONNECTED | BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
-
- parent = child; /* new child is next parent */
- }
- }
- copy_v3_v3(parent->tail, tail->p);
-
- /* If the bone wasn't subdivided, delete it and return NULL
- * to let subsequent subdivision methods do their thing.
- * */
- if (parent == root) {
- if (parent == arm->act_edbone) arm->act_edbone = NULL;
- ED_armature_edit_bone_remove(arm, parent);
- parent = NULL;
- }
-
- lastBone = parent; /* set last bone in the chain */
- }
-
- return lastBone;
-}
-
-EditBone *test_subdivideByCorrelation(Scene *scene, Object *obedit, ReebArc *arc, ReebNode *head, ReebNode *tail)
-{
- EditBone *lastBone = NULL;
-
- if (scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION) {
- float invmat[4][4] = MAT4_UNITY;
- float tmat[3][3] = MAT3_UNITY;
- ReebArcIterator arc_iter;
- BArcIterator *iter = (BArcIterator *)&arc_iter;
- bArmature *arm = obedit->data;
-
- initArcIterator(iter, arc, head);
-
- lastBone = subdivideArcBy(arm, arm->edbo, iter, invmat, tmat, nextAdaptativeSubdivision);
- }
-
- return lastBone;
-}
-
-float arcLengthRatio(ReebArc *arc)
-{
- float arcLength = 0.0f;
- float embedLength = 0.0f;
- int i;
-
- arcLength = len_v3v3(arc->head->p, arc->tail->p);
-
- if (arc->bcount > 0) {
- /* Add the embedding */
- for (i = 1; i < arc->bcount; i++) {
- embedLength += len_v3v3(arc->buckets[i - 1].p, arc->buckets[i].p);
- }
- /* Add head and tail -> embedding vectors */
- embedLength += len_v3v3(arc->head->p, arc->buckets[0].p);
- embedLength += len_v3v3(arc->tail->p, arc->buckets[arc->bcount - 1].p);
- }
- else {
- embedLength = arcLength;
- }
-
- return embedLength / arcLength;
-}
-
-EditBone *test_subdivideByLength(Scene *scene, Object *obedit, ReebArc *arc, ReebNode *head, ReebNode *tail)
-{
- EditBone *lastBone = NULL;
- if ((scene->toolsettings->skgen_options & SKGEN_CUT_LENGTH) &&
- arcLengthRatio(arc) >= G.scene->toolsettings->skgen_length_ratio)
- {
- float invmat[4][4] = MAT4_UNITY;
- float tmat[3][3] = MAT3_UNITY;
- ReebArcIterator arc_iter;
- BArcIterator *iter = (BArcIterator *)&arc_iter;
- bArmature *arm = obedit->data;
-
- initArcIterator(iter, arc, head);
-
- lastBone = subdivideArcBy(arm, arm->edbo, iter, invmat, tmat, nextLengthSubdivision);
- }
-
- return lastBone;
-}
-
-/***************************************** MAIN ALGORITHM ********************************************/
-
-void generateSkeletonFromReebGraph(Scene *scene, ReebGraph *rg)
-{
- Object *obedit = scene->obedit; // XXX get from context
- GHash *arcBoneMap = NULL;
- ReebArc *arc = NULL;
- ReebNode *node = NULL;
- Object *src = NULL;
- Object *dst = NULL;
-
- src = scene->basact->object;
-
- if (obedit != NULL) {
- ED_armature_from_edit(obedit);
- ED_armature_edit_free(obedit);
- }
-
- dst = BKE_object_add(scene, OB_ARMATURE);
- ED_object_base_init_transform(NULL, scene->basact, NULL, NULL); // XXX NULL is C, loc, rot
- obedit = scene->basact->object;
-
- /* Copy orientation from source */
- copy_v3_v3(dst->loc, src->obmat[3]);
- mat4_to_eul(dst->rot, src->obmat);
- mat4_to_size(dst->size, src->obmat);
-
- BKE_object_where_is_calc(scene, obedit);
-
- ED_armature_to_edit(obedit);
-
- arcBoneMap = BLI_ghash_ptr_new("SkeletonFromReebGraph gh");
-
- BLI_markdownSymmetry((BGraph *)rg, rg->nodes.first, scene->toolsettings->skgen_symmetry_limit);
-
- for (arc = rg->arcs.first; arc; arc = arc->next)
- {
- EditBone *lastBone = NULL;
- ReebNode *head, *tail;
- int i;
-
- /* Find out the direction of the arc through simple heuristics (in order of priority) :
- *
- * 1- Arcs on primary symmetry axis (symmetry == 1) point up (head: high weight -> tail: low weight)
- * 2- Arcs starting on a primary axis point away from it (head: node on primary axis)
- * 3- Arcs point down (head: low weight -> tail: high weight)
- *
- * Finally, the arc direction is stored in its flag: 1 (low -> high), -1 (high -> low)
- */
-
- /* if arc is a symmetry axis, internal bones go up the tree */
- if (arc->symmetry_level == 1 && arc->tail->degree != 1) {
- head = arc->tail;
- tail = arc->head;
-
- arc->flag = -1; /* mark arc direction */
- }
- /* Bones point AWAY from the symmetry axis */
- else if (arc->head->symmetry_level == 1) {
- head = arc->head;
- tail = arc->tail;
-
- arc->flag = 1; /* mark arc direction */
- }
- else if (arc->tail->symmetry_level == 1) {
- head = arc->tail;
- tail = arc->head;
-
- arc->flag = -1; /* mark arc direction */
- }
- /* otherwise, always go from low weight to high weight */
- else {
- head = arc->head;
- tail = arc->tail;
-
- arc->flag = 1; /* mark arc direction */
- }
-
- /* Loop over subdivision methods */
- for (i = 0; lastBone == NULL && i < SKGEN_SUB_TOTAL; i++) {
- switch (scene->toolsettings->skgen_subdivisions[i]) {
- case SKGEN_SUB_LENGTH:
- lastBone = test_subdivideByLength(scene, obedit, arc, head, tail);
- break;
- case SKGEN_SUB_ANGLE:
- lastBone = subdivideByAngle(scene, obedit, arc, head, tail);
- break;
- case SKGEN_SUB_CORRELATION:
- lastBone = test_subdivideByCorrelation(scene, obedit, arc, head, tail);
- break;
- }
- }
-
- if (lastBone == NULL) {
- EditBone *bone;
- bone = ED_armature_edit_bone_add(obedit->data, "Bone");
- bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
-
- copy_v3_v3(bone->head, head->p);
- copy_v3_v3(bone->tail, tail->p);
-
- /* set first and last bone, since there's only one */
- lastBone = bone;
- }
-
- BLI_ghash_insert(arcBoneMap, arc, lastBone);
- }
-
- /* Second pass, setup parent relationship between arcs */
- for (node = rg->nodes.first; node; node = node->next)
- {
- ReebArc *incomingArc = NULL;
- int i;
-
- for (i = 0; i < node->degree; i++) {
- arc = (ReebArc *)node->arcs[i];
-
- /* if arc is incoming into the node */
- if ((arc->head == node && arc->flag == -1) ||
- (arc->tail == node && arc->flag == 1))
- {
- if (incomingArc == NULL) {
- incomingArc = arc;
- /* loop further to make sure there's only one incoming arc */
- }
- else {
- /* skip this node if more than one incomingArc */
- incomingArc = NULL;
- break; /* No need to look further, we are skipping already */
- }
- }
- }
-
- if (incomingArc != NULL) {
- EditBone *parentBone = BLI_ghash_lookup(arcBoneMap, incomingArc);
-
- /* Look for outgoing arcs and parent their bones */
- for (i = 0; i < node->degree; i++)
- {
- arc = node->arcs[i];
-
- /* if arc is outgoing from the node */
- if ((arc->head == node && arc->flag == 1) || (arc->tail == node && arc->flag == -1)) {
- EditBone *childBone = BLI_ghash_lookup(arcBoneMap, arc);
-
- /* find the root bone */
- while (childBone->parent != NULL)
- {
- childBone = childBone->parent;
- }
-
- childBone->parent = parentBone;
- childBone->flag |= BONE_CONNECTED;
- }
- }
- }
- }
-
- BLI_ghash_free(arcBoneMap, NULL, NULL);
-}
-
-void generateSkeleton(Scene *scene)
-{
- ReebGraph *reebg;
-
-// setcursor_space(SPACE_VIEW3D, CURSOR_WAIT);
-
- reebg = BIF_ReebGraphFromEditMesh();
-
- generateSkeletonFromReebGraph(scene, reebg);
-
- REEB_freeGraph(reebg);
-
- //setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
-}
-
-#endif
diff --git a/source/blender/editors/armature/editarmature_generate.c b/source/blender/editors/armature/editarmature_generate.c
index 979c352c4b2..89772d38e8f 100644
--- a/source/blender/editors/armature/editarmature_generate.c
+++ b/source/blender/editors/armature/editarmature_generate.c
@@ -30,24 +30,13 @@
* \ingroup edarmature
*/
-
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
-
#include "DNA_scene_types.h"
#include "DNA_armature_types.h"
-#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_graph.h"
-#include "BLI_utildefines.h"
-
-
#include "ED_armature.h"
-#include "armature_intern.h"
#include "BIF_generate.h"
void setBoneRollFromNormal(EditBone *bone, const float no[3], float UNUSED(invmat[4][4]), float tmat[3][3])
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
index 3e34a4c6808..62cce6b2c1e 100644
--- a/source/blender/editors/armature/editarmature_retarget.c
+++ b/source/blender/editors/armature/editarmature_retarget.c
@@ -25,12 +25,6 @@
* \ingroup edarmature
*/
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
#include "MEM_guardedalloc.h"
#include "PIL_time.h"
@@ -42,11 +36,6 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-#include "BLI_graph.h"
-#include "BLI_rand.h"
-#include "BLI_threads.h"
#include "BKE_constraint.h"
#include "BKE_armature.h"
@@ -57,8 +46,6 @@
#include "BIF_retarget.h"
-#include "reeb.h" /* FIX ME */
-
#include "armature_intern.h"
/************ RIG RETARGET DATA STRUCTURES ***************/
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index b61aa86a52f..ec96c574f75 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -22,10 +22,6 @@
* \ingroup edarmature
*/
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
#include "MEM_guardedalloc.h"
#include "DNA_object_types.h"
@@ -37,9 +33,6 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
-#include "BLI_graph.h"
-#include "BLI_ghash.h"
#include "BLF_translation.h"
@@ -60,8 +53,6 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "reeb.h"
-
typedef int (*GestureDetectFct)(bContext *, SK_Gesture *, SK_Sketch *);
typedef void (*GestureApplyFct)(bContext *, SK_Gesture *, SK_Sketch *);
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index a7e84d590b5..3ac514f1465 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -30,18 +30,12 @@
* \ingroup edarmature
*/
-
-#include <math.h>
-#include <string.h>
-
#include "MEM_guardedalloc.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
-#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_edgehash.h"
#include "BLI_memarena.h"
@@ -59,8 +53,6 @@
#include "ONL_opennl.h"
-#include "BLO_sys_types.h" // for intptr_t support
-
#include "ED_mesh.h"
#include "ED_armature.h"
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
new file mode 100644
index 00000000000..3d1d5d2f6ba
--- /dev/null
+++ b/source/blender/editors/armature/pose_edit.c
@@ -0,0 +1,1180 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Ton Roosendaal, Blender Foundation '05, full recode.
+ * Joshua Leung
+ * Reevan McKay (original NaN code)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Pose Mode API's and Operators for Pose Mode armatures
+ */
+
+/** \file blender/editors/armature/pose_edit.c
+ * \ingroup edarmature
+ */
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_keyframing.h"
+#include "ED_screen.h"
+#include "ED_object.h"
+
+#include "UI_interface.h"
+
+#include "armature_intern.h"
+
+/* matches logic with ED_operator_posemode_context() */
+Object *ED_pose_object_from_context(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ Object *ob;
+
+ /* since this call may also be used from the buttons window, we need to check for where to get the object */
+ if (sa && sa->spacetype == SPACE_BUTS) {
+ ob = ED_object_context(C);
+ }
+ else {
+ ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ }
+
+ return ob;
+}
+
+/* This function is used to process the necessary updates for */
+void ED_armature_enter_posemode(bContext *C, Base *base)
+{
+ ReportList *reports = CTX_wm_reports(C);
+ Object *ob = base->object;
+
+ if (ob->id.lib) {
+ BKE_report(reports, RPT_WARNING, "Cannot pose libdata");
+ return;
+ }
+
+ switch (ob->type) {
+ case OB_ARMATURE:
+ ob->restore_mode = ob->mode;
+ ob->mode |= OB_MODE_POSE;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
+
+ break;
+ default:
+ return;
+ }
+
+ /* XXX: disabled as this would otherwise cause a nasty loop... */
+ //ED_object_toggle_modes(C, ob->mode);
+}
+
+void ED_armature_exit_posemode(bContext *C, Base *base)
+{
+ if (base) {
+ Object *ob = base->object;
+
+ ob->restore_mode = ob->mode;
+ ob->mode &= ~OB_MODE_POSE;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+ }
+}
+
+/* if a selected or active bone is protected, throw error (oonly if warn == 1) and return 1 */
+/* only_selected == 1: the active bone is allowed to be protected */
+#if 0 /* UNUSED 2.5 */
+static short pose_has_protected_selected(Object *ob, short warn)
+{
+ /* check protection */
+ if (ob->proxy) {
+ bPoseChannel *pchan;
+ bArmature *arm = ob->data;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone && (pchan->bone->layer & arm->layer)) {
+ if (pchan->bone->layer & arm->layer_protected) {
+ if (pchan->bone->flag & BONE_SELECTED)
+ break;
+ }
+ }
+ }
+ if (pchan) {
+ if (warn) error("Cannot change Proxy protected bones");
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
+/* only for real IK, not for auto-IK */
+static int pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan, int level)
+{
+ bConstraint *con;
+ Bone *bone;
+
+ /* No need to check if constraint is active (has influence),
+ * since all constraints with CONSTRAINT_IK_AUTO are active */
+ for (con = pchan->constraints.first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data = con->data;
+ if (data->rootbone == 0 || data->rootbone > level) {
+ if ((data->flag & CONSTRAINT_IK_AUTO) == 0)
+ return 1;
+ }
+ }
+ }
+ for (bone = pchan->bone->childbase.first; bone; bone = bone->next) {
+ pchan = BKE_pose_channel_find_name(ob->pose, bone->name);
+ if (pchan && pose_channel_in_IK_chain(ob, pchan, level + 1))
+ return 1;
+ }
+ return 0;
+}
+
+int ED_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
+{
+ return pose_channel_in_IK_chain(ob, pchan, 0);
+}
+
+/* ********************************************** */
+/* Motion Paths */
+
+/* For the object with pose/action: update paths for those that have got them
+ * This should selectively update paths that exist...
+ *
+ * To be called from various tools that do incremental updates
+ */
+void ED_pose_recalculate_paths(Scene *scene, Object *ob)
+{
+ ListBase targets = {NULL, NULL};
+
+ /* set flag to force recalc, then grab the relevant bones to target */
+ ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
+ animviz_get_object_motionpaths(ob, &targets);
+
+ /* recalculate paths, then free */
+ animviz_calc_motionpaths(scene, &targets);
+ BLI_freelistN(&targets);
+}
+
+
+/* show popup to determine settings */
+static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ /* set default settings from existing/stored settings */
+ {
+ bAnimVizSettings *avs = &ob->pose->avs;
+ PointerRNA avs_ptr;
+
+ RNA_int_set(op->ptr, "start_frame", avs->path_sf);
+ RNA_int_set(op->ptr, "end_frame", avs->path_ef);
+
+ RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
+ RNA_enum_set(op->ptr, "bake_location", RNA_enum_get(&avs_ptr, "bake_location"));
+ }
+
+ /* show popup dialog to allow editing of range... */
+ // FIXME: hardcoded dimensions here are just arbitrary
+ return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 10 * UI_UNIT_Y);
+}
+
+/* For the object with pose/action: create path curves for selected bones
+ * This recalculates the WHOLE path within the pchan->pathsf and pchan->pathef range
+ */
+static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ Scene *scene = CTX_data_scene(C);
+
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ /* grab baking settings from operator settings */
+ {
+ bAnimVizSettings *avs = &ob->pose->avs;
+ PointerRNA avs_ptr;
+
+ avs->path_sf = RNA_int_get(op->ptr, "start_frame");
+ avs->path_ef = RNA_int_get(op->ptr, "end_frame");
+
+ RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
+ RNA_enum_set(&avs_ptr, "bake_location", RNA_enum_get(op->ptr, "bake_location"));
+ }
+
+ /* set up path data for bones being calculated */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ /* verify makes sure that the selected bone has a bone with the appropriate settings */
+ animviz_verify_motionpaths(op->reports, scene, ob, pchan);
+ }
+ CTX_DATA_END;
+
+ /* calculate the bones that now have motionpaths... */
+ /* TODO: only make for the selected bones? */
+ ED_pose_recalculate_paths(scene, ob);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_paths_calculate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Calculate Bone Paths";
+ ot->idname = "POSE_OT_paths_calculate";
+ ot->description = "Calculate paths for the selected bones";
+
+ /* api callbacks */
+ ot->invoke = pose_calculate_paths_invoke;
+ ot->exec = pose_calculate_paths_exec;
+ ot->poll = ED_operator_posemode_exclusive;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_int(ot->srna, "start_frame", 1, MINAFRAME, MAXFRAME, "Start",
+ "First frame to calculate bone paths on", MINFRAME, MAXFRAME / 2.0);
+ RNA_def_int(ot->srna, "end_frame", 250, MINAFRAME, MAXFRAME, "End",
+ "Last frame to calculate bone paths on", MINFRAME, MAXFRAME / 2.0);
+
+ RNA_def_enum(ot->srna, "bake_location", motionpath_bake_location_items, 0,
+ "Bake Location",
+ "Which point on the bones is used when calculating paths");
+}
+
+/* --------- */
+
+static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ Scene *scene = CTX_data_scene(C);
+
+ if (ELEM(NULL, ob, scene))
+ return OPERATOR_CANCELLED;
+
+ /* calculate the bones that now have motionpaths... */
+ /* TODO: only make for the selected bones? */
+ ED_pose_recalculate_paths(scene, ob);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_paths_update(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Update Bone Paths";
+ ot->idname = "POSE_OT_paths_update";
+ ot->description = "Recalculate paths for bones that already have them";
+
+ /* api callbakcs */
+ ot->exec = pose_update_paths_exec;
+ ot->poll = ED_operator_posemode_exclusive; /* TODO: this should probably check for active bone and/or existing paths */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* --------- */
+
+/* for the object with pose/action: clear path curves for selected bones only */
+static void ED_pose_clear_paths(Object *ob)
+{
+ bPoseChannel *pchan;
+ short skipped = 0;
+
+ if (ELEM(NULL, ob, ob->pose))
+ return;
+
+ /* free the motionpath blocks, but also take note of whether we skipped some... */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->mpath) {
+ if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
+ animviz_free_motionpath(pchan->mpath);
+ pchan->mpath = NULL;
+ }
+ else
+ skipped = 1;
+ }
+ }
+
+ /* if we didn't skip any, we shouldn't have any paths left */
+ if (skipped == 0)
+ ob->pose->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS;
+}
+
+/* operator callback for this */
+static int pose_clear_paths_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+
+ /* only continue if there's an object */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ /* use the backend function for this */
+ ED_pose_clear_paths(ob);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_paths_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Bone Paths";
+ ot->idname = "POSE_OT_paths_clear";
+ ot->description = "Clear path caches for selected bones";
+
+ /* api callbacks */
+ ot->exec = pose_clear_paths_exec;
+ ot->poll = ED_operator_posemode_exclusive;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************************** */
+#if 0 /* UNUSED 2.5 */
+static void pose_copy_menu(Scene *scene)
+{
+ Object *obedit = scene->obedit; // XXX context
+ Object *ob = OBACT;
+ bArmature *arm;
+ bPoseChannel *pchan, *pchanact;
+ short nr = 0;
+ int i = 0;
+
+ /* paranoia checks */
+ if (ELEM(NULL, ob, ob->pose)) return;
+ if ((ob == obedit) || (ob->mode & OB_MODE_POSE) == 0) return;
+
+ pchan = BKE_pose_channel_active(ob);
+
+ if (pchan == NULL) return;
+ pchanact = pchan;
+ arm = ob->data;
+
+ /* if proxy-protected bones selected, some things (such as locks + displays) shouldn't be changeable,
+ * but for constraints (just add local constraints)
+ */
+ if (pose_has_protected_selected(ob, 0)) {
+ i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
+ if (i < 25)
+ nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5");
+ else
+ nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4");
+ }
+ else {
+ i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
+ if (i < 25)
+ nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5|%l|Transform Locks %x6|IK Limits %x7|Bone Shape %x8");
+ else
+ nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|%l|Transform Locks %x6|IK Limits %x7|Bone Shape %x8");
+ }
+
+ if (nr <= 0)
+ return;
+
+ if (nr != 5) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((arm->layer & pchan->bone->layer) &&
+ (pchan->bone->flag & BONE_SELECTED) &&
+ (pchan != pchanact) )
+ {
+ switch (nr) {
+ case 1: /* Local Location */
+ copy_v3_v3(pchan->loc, pchanact->loc);
+ break;
+ case 2: /* Local Rotation */
+ copy_qt_qt(pchan->quat, pchanact->quat);
+ copy_v3_v3(pchan->eul, pchanact->eul);
+ break;
+ case 3: /* Local Size */
+ copy_v3_v3(pchan->size, pchanact->size);
+ break;
+ case 4: /* All Constraints */
+ {
+ ListBase tmp_constraints = {NULL, NULL};
+
+ /* copy constraints to tmpbase and apply 'local' tags before
+ * appending to list of constraints for this channel
+ */
+ BKE_copy_constraints(&tmp_constraints, &pchanact->constraints, TRUE);
+ if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
+ bConstraint *con;
+
+ /* add proxy-local tags */
+ for (con = tmp_constraints.first; con; con = con->next)
+ con->flag |= CONSTRAINT_PROXY_LOCAL;
+ }
+ BLI_movelisttolist(&pchan->constraints, &tmp_constraints);
+
+ /* update flags (need to add here, not just copy) */
+ pchan->constflag |= pchanact->constflag;
+
+ if (ob->pose)
+ ob->pose->flag |= POSE_RECALC;
+ }
+ break;
+ case 6: /* Transform Locks */
+ pchan->protectflag = pchanact->protectflag;
+ break;
+ case 7: /* IK (DOF) settings */
+ {
+ pchan->ikflag = pchanact->ikflag;
+ copy_v3_v3(pchan->limitmin, pchanact->limitmin);
+ copy_v3_v3(pchan->limitmax, pchanact->limitmax);
+ copy_v3_v3(pchan->stiffness, pchanact->stiffness);
+ pchan->ikstretch = pchanact->ikstretch;
+ pchan->ikrotweight = pchanact->ikrotweight;
+ pchan->iklinweight = pchanact->iklinweight;
+ }
+ break;
+ case 8: /* Custom Bone Shape */
+ pchan->custom = pchanact->custom;
+ break;
+ case 9: /* Visual Location */
+ BKE_armature_loc_pose_to_bone(pchan, pchanact->pose_mat[3], pchan->loc);
+ break;
+ case 10: /* Visual Rotation */
+ {
+ float delta_mat[4][4];
+
+ BKE_armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat);
+
+ if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ float tmp_quat[4];
+
+ /* need to convert to quat first (in temp var)... */
+ mat4_to_quat(tmp_quat, delta_mat);
+ quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, tmp_quat);
+ }
+ else if (pchan->rotmode == ROT_MODE_QUAT)
+ mat4_to_quat(pchan->quat, delta_mat);
+ else
+ mat4_to_eulO(pchan->eul, pchan->rotmode, delta_mat);
+ }
+ break;
+ case 11: /* Visual Size */
+ {
+ float delta_mat[4][4], size[4];
+
+ BKE_armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat);
+ mat4_to_size(size, delta_mat);
+ copy_v3_v3(pchan->size, size);
+ }
+ }
+ }
+ }
+ }
+ else { /* constraints, optional (note: max we can have is 24 constraints) */
+ bConstraint *con, *con_back;
+ int const_toggle[24] = {0}; /* XXX, initialize as 0 to quiet errors */
+ ListBase const_copy = {NULL, NULL};
+
+ BLI_duplicatelist(&const_copy, &(pchanact->constraints));
+
+ /* build the puplist of constraints */
+ for (con = pchanact->constraints.first, i = 0; con; con = con->next, i++) {
+ const_toggle[i] = 1;
+// add_numbut(i, TOG|INT, con->name, 0, 0, &(const_toggle[i]), "");
+ }
+
+// if (!do_clever_numbuts("Select Constraints", i, REDRAW)) {
+// BLI_freelistN(&const_copy);
+// return;
+// }
+
+ /* now build a new listbase from the options selected */
+ for (i = 0, con = const_copy.first; con; i++) {
+ /* if not selected, free/remove it from the list */
+ if (!const_toggle[i]) {
+ con_back = con->next;
+ BLI_freelinkN(&const_copy, con);
+ con = con_back;
+ }
+ else
+ con = con->next;
+ }
+
+ /* Copy the temo listbase to the selected posebones */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((arm->layer & pchan->bone->layer) &&
+ (pchan->bone->flag & BONE_SELECTED) &&
+ (pchan != pchanact) )
+ {
+ ListBase tmp_constraints = {NULL, NULL};
+
+ /* copy constraints to tmpbase and apply 'local' tags before
+ * appending to list of constraints for this channel
+ */
+ BKE_copy_constraints(&tmp_constraints, &const_copy, TRUE);
+ if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
+ /* add proxy-local tags */
+ for (con = tmp_constraints.first; con; con = con->next)
+ con->flag |= CONSTRAINT_PROXY_LOCAL;
+ }
+ BLI_movelisttolist(&pchan->constraints, &tmp_constraints);
+
+ /* update flags (need to add here, not just copy) */
+ pchan->constflag |= pchanact->constflag;
+ }
+ }
+ BLI_freelistN(&const_copy);
+ BKE_pose_update_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */
+
+ if (ob->pose)
+ ob->pose->flag |= POSE_RECALC;
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations
+
+ BIF_undo_push("Copy Pose Attributes");
+
+}
+#endif
+
+/* ********************************************** */
+
+static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm;
+
+ /* paranoia checks */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+ arm = ob->data;
+
+ /* loop through selected bones, auto-naming them */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ char newname[MAXBONENAME];
+ flip_side_name(newname, pchan->name, TRUE);
+ ED_armature_bone_rename(arm, pchan->name, newname);
+ }
+ CTX_DATA_END;
+
+ /* since we renamed stuff... */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_flip_names(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flip Names";
+ ot->idname = "POSE_OT_flip_names";
+ ot->description = "Flips (and corrects) the axis suffixes of the the names of selected bones";
+
+ /* api callbacks */
+ ot->exec = pose_flip_names_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ------------------ */
+
+static int pose_autoside_names_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm;
+ char newname[MAXBONENAME];
+ short axis = RNA_enum_get(op->ptr, "axis");
+
+ /* paranoia checks */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+ arm = ob->data;
+
+ /* loop through selected bones, auto-naming them */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ BLI_strncpy(newname, pchan->name, sizeof(newname));
+ if (bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis]))
+ ED_armature_bone_rename(arm, pchan->name, newname);
+ }
+ CTX_DATA_END;
+
+ /* since we renamed stuff... */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_autoside_names(wmOperatorType *ot)
+{
+ static EnumPropertyItem axis_items[] = {
+ {0, "XAXIS", 0, "X-Axis", "Left/Right"},
+ {1, "YAXIS", 0, "Y-Axis", "Front/Back"},
+ {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "AutoName by Axis";
+ ot->idname = "POSE_OT_autoside_names";
+ ot->description = "Automatically renames the selected bones according to which side of the target axis they fall on";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = pose_autoside_names_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* settings */
+ ot->prop = RNA_def_enum(ot->srna, "axis", axis_items, 0, "Axis", "Axis tag names with");
+}
+
+/* ********************************************** */
+
+static int pose_bone_rotmode_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ int mode = RNA_enum_get(op->ptr, "type");
+
+ /* set rotation mode of selected bones */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ pchan->rotmode = mode;
+ }
+ CTX_DATA_END;
+
+ /* notifiers and updates */
+ DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_rotation_mode_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Rotation Mode";
+ ot->idname = "POSE_OT_rotation_mode_set";
+ ot->description = "Set the rotation representation used by selected bones";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = pose_bone_rotmode_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", posebone_rotmode_items, 0, "Rotation Mode", "");
+}
+
+/* ********************************************** */
+
+/* Show all armature layers */
+static int pose_armature_layers_showall_poll(bContext *C)
+{
+ /* this single operator can be used in posemode OR editmode for armatures */
+ return ED_operator_posemode(C) || ED_operator_editarmature(C);
+}
+
+static int pose_armature_layers_showall_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = (ob) ? ob->data : NULL;
+ PointerRNA ptr;
+ int maxLayers = (RNA_boolean_get(op->ptr, "all")) ? 32 : 16;
+ int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+ int i;
+
+ /* sanity checking */
+ if (arm == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* use RNA to set the layers
+ * although it would be faster to just set directly using bitflags, we still
+ * need to setup a RNA pointer so that we get the "update" callbacks for free...
+ */
+ RNA_id_pointer_create(&arm->id, &ptr);
+
+ for (i = 0; i < maxLayers; i++)
+ layers[i] = 1;
+
+ RNA_boolean_set_array(&ptr, "layers", layers);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ /* done */
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_layers_show_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Show All Layers";
+ ot->idname = "ARMATURE_OT_layers_show_all";
+ ot->description = "Make all armature layers visible";
+
+ /* callbacks */
+ ot->exec = pose_armature_layers_showall_exec;
+ ot->poll = pose_armature_layers_showall_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All Layers", "Enable all layers or just the first 16 (top row)");
+}
+
+/* ------------------- */
+
+/* Present a popup to get the layers that should be used */
+static int pose_armature_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = (ob) ? ob->data : NULL;
+ PointerRNA ptr;
+ int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+
+ /* sanity checking */
+ if (arm == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* get RNA pointer to armature data to use that to retrieve the layers as ints to init the operator */
+ RNA_id_pointer_create((ID *)arm, &ptr);
+ RNA_boolean_get_array(&ptr, "layers", layers);
+ RNA_boolean_set_array(op->ptr, "layers", layers);
+
+ /* part to sync with other similar operators... */
+ return WM_operator_props_popup(C, op, evt);
+}
+
+/* Set the visible layers for the active armature (edit and pose modes) */
+static int pose_armature_layers_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ PointerRNA ptr;
+ int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+
+ if (ELEM(NULL, ob, ob->data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* get the values set in the operator properties */
+ RNA_boolean_get_array(op->ptr, "layers", layers);
+
+ /* get pointer for armature, and write data there... */
+ RNA_id_pointer_create((ID *)ob->data, &ptr);
+ RNA_boolean_set_array(&ptr, "layers", layers);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void POSE_OT_armature_layers(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Armature Layers";
+ ot->idname = "POSE_OT_armature_layers";
+ ot->description = "Change the visible armature layers";
+
+ /* callbacks */
+ ot->invoke = pose_armature_layers_invoke;
+ ot->exec = pose_armature_layers_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
+}
+
+void ARMATURE_OT_armature_layers(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Armature Layers";
+ ot->idname = "ARMATURE_OT_armature_layers";
+ ot->description = "Change the visible armature layers";
+
+ /* callbacks */
+ ot->invoke = pose_armature_layers_invoke;
+ ot->exec = pose_armature_layers_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
+}
+
+/* ------------------- */
+
+/* Present a popup to get the layers that should be used */
+static int pose_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+{
+ int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+
+ /* get layers that are active already */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ short bit;
+
+ /* loop over the bits for this pchan's layers, adding layers where they're needed */
+ for (bit = 0; bit < 32; bit++) {
+ if (pchan->bone->layer & (1 << bit))
+ layers[bit] = 1;
+ }
+ }
+ CTX_DATA_END;
+
+ /* copy layers to operator */
+ RNA_boolean_set_array(op->ptr, "layers", layers);
+
+ /* part to sync with other similar operators... */
+ return WM_operator_props_popup(C, op, evt);
+}
+
+/* Set the visible layers for the active armature (edit and pose modes) */
+static int pose_bone_layers_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ PointerRNA ptr;
+ int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+
+ if (ob == NULL || ob->data == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* get the values set in the operator properties */
+ RNA_boolean_get_array(op->ptr, "layers", layers);
+
+ /* set layers of pchans based on the values set in the operator props */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ /* get pointer for pchan, and write flags this way */
+ RNA_pointer_create((ID *)ob->data, &RNA_Bone, pchan->bone, &ptr);
+ RNA_boolean_set_array(&ptr, "layers", layers);
+ }
+ CTX_DATA_END;
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_bone_layers(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Bone Layers";
+ ot->idname = "POSE_OT_bone_layers";
+ ot->description = "Change the layers that the selected bones belong to";
+
+ /* callbacks */
+ ot->invoke = pose_bone_layers_invoke;
+ ot->exec = pose_bone_layers_exec;
+ ot->poll = ED_operator_posemode_exclusive;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
+}
+
+/* ------------------- */
+
+/* Present a popup to get the layers that should be used */
+static int armature_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+{
+ int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+
+ /* get layers that are active already */
+ CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones)
+ {
+ short bit;
+
+ /* loop over the bits for this pchan's layers, adding layers where they're needed */
+ for (bit = 0; bit < 32; bit++) {
+ if (ebone->layer & (1 << bit))
+ layers[bit] = 1;
+ }
+ }
+ CTX_DATA_END;
+
+ /* copy layers to operator */
+ RNA_boolean_set_array(op->ptr, "layers", layers);
+
+ /* part to sync with other similar operators... */
+ return WM_operator_props_popup(C, op, evt);
+}
+
+/* Set the visible layers for the active armature (edit and pose modes) */
+static int armature_bone_layers_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = (ob) ? ob->data : NULL;
+ PointerRNA ptr;
+ int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+
+ /* get the values set in the operator properties */
+ RNA_boolean_get_array(op->ptr, "layers", layers);
+
+ /* set layers of pchans based on the values set in the operator props */
+ CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones)
+ {
+ /* get pointer for pchan, and write flags this way */
+ RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr);
+ RNA_boolean_set_array(&ptr, "layers", layers);
+ }
+ CTX_DATA_END;
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_bone_layers(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Bone Layers";
+ ot->idname = "ARMATURE_OT_bone_layers";
+ ot->description = "Change the layers that the selected bones belong to";
+
+ /* callbacks */
+ ot->invoke = armature_bone_layers_invoke;
+ ot->exec = armature_bone_layers_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
+}
+
+/* ********************************************** */
+/* Show/Hide Bones */
+
+static int hide_selected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
+{
+ bArmature *arm = ob->data;
+
+ if (arm->layer & bone->layer) {
+ if (bone->flag & BONE_SELECTED) {
+ bone->flag |= BONE_HIDDEN_P;
+ bone->flag &= ~BONE_SELECTED;
+ if (arm->act_bone == bone)
+ arm->act_bone = NULL;
+ }
+ }
+ return 0;
+}
+
+static int hide_unselected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
+{
+ bArmature *arm = ob->data;
+
+ if (arm->layer & bone->layer) {
+ /* hrm... typo here? */
+ if ((bone->flag & BONE_SELECTED) == 0) {
+ bone->flag |= BONE_HIDDEN_P;
+ if (arm->act_bone == bone)
+ arm->act_bone = NULL;
+ }
+ }
+ return 0;
+}
+
+/* active object is armature in posemode, poll checked */
+static int pose_hide_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = ob->data;
+
+ if (RNA_boolean_get(op->ptr, "unselected"))
+ bone_looper(ob, arm->bonebase.first, NULL, hide_unselected_pose_bone_cb);
+ else
+ bone_looper(ob, arm->bonebase.first, NULL, hide_selected_pose_bone_cb);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hide Selected";
+ ot->idname = "POSE_OT_hide";
+ ot->description = "Tag selected bones to not be visible in Pose Mode";
+
+ /* api callbacks */
+ ot->exec = pose_hide_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "");
+}
+
+static int show_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
+{
+ bArmature *arm = ob->data;
+
+ if (arm->layer & bone->layer) {
+ if (bone->flag & BONE_HIDDEN_P) {
+ bone->flag &= ~BONE_HIDDEN_P;
+ bone->flag |= BONE_SELECTED;
+ }
+ }
+
+ return 0;
+}
+
+/* active object is armature in posemode, poll checked */
+static int pose_reveal_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = ob->data;
+
+ bone_looper(ob, arm->bonebase.first, NULL, show_pose_bone_cb);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_reveal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Reveal Selected";
+ ot->idname = "POSE_OT_reveal";
+ ot->description = "Unhide all bones that have been tagged to be hidden in Pose Mode";
+
+ /* api callbacks */
+ ot->exec = pose_reveal_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************************** */
+/* Flip Quats */
+
+static int pose_flip_quats_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
+
+ /* loop through all selected pchans, flipping and keying (as needed) */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ /* only if bone is using quaternion rotation */
+ if (pchan->rotmode == ROT_MODE_QUAT) {
+ /* quaternions have 720 degree range */
+ negate_v4(pchan->quat);
+
+ ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers and updates */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_quaternions_flip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flip Quats";
+ ot->idname = "POSE_OT_quaternions_flip";
+ ot->description = "Flip quaternion values to achieve desired rotations, while maintaining the same orientations";
+
+ /* callbacks */
+ ot->exec = pose_flip_quats_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
new file mode 100644
index 00000000000..06a88f013d7
--- /dev/null
+++ b/source/blender/editors/armature/pose_group.c
@@ -0,0 +1,523 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation
+ * All rights reserved.
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Implementation of Bone Groups operators and editing API's
+ */
+
+/** \file blender/editors/armature/pose_group.c
+ * \ingroup edarmature
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_action.h"
+#include "BKE_context.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "armature_intern.h"
+
+/* ********************************************** */
+/* Bone Groups */
+
+static int pose_group_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_pose_object_from_context(C);
+
+ /* only continue if there's an object */
+ if (ob == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* for now, just call the API function for this */
+ BKE_pose_add_group(ob);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Bone Group";
+ ot->idname = "POSE_OT_group_add";
+ ot->description = "Add a new bone group";
+
+ /* api callbacks */
+ ot->exec = pose_group_add_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int pose_group_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_pose_object_from_context(C);
+
+ /* only continue if there's an object */
+ if (ob == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* for now, just call the API function for this */
+ BKE_pose_remove_group(ob);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Bone Group";
+ ot->idname = "POSE_OT_group_remove";
+ ot->description = "Remove the active bone group";
+
+ /* api callbacks */
+ ot->exec = pose_group_remove_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ------------ */
+
+/* invoke callback which presents a list of bone-groups for the user to choose from */
+static int pose_groups_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
+{
+ Object *ob = ED_pose_object_from_context(C);
+ bPose *pose;
+
+ uiPopupMenu *pup;
+ uiLayout *layout;
+ bActionGroup *grp;
+ int i;
+
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+ pose = ob->pose;
+
+ /* if there's no active group (or active is invalid), create a new menu to find it */
+ if (pose->active_group <= 0) {
+ /* create a new menu, and start populating it with group names */
+ pup = uiPupMenuBegin(C, op->type->name, ICON_NONE);
+ layout = uiPupMenuLayout(pup);
+
+ /* special entry - allow to create new group, then use that
+ * (not to be used for removing though)
+ */
+ if (strstr(op->idname, "assign")) {
+ uiItemIntO(layout, "New Group", ICON_NONE, op->idname, "type", 0);
+ uiItemS(layout);
+ }
+
+ /* add entries for each group */
+ for (grp = pose->agroups.first, i = 1; grp; grp = grp->next, i++)
+ uiItemIntO(layout, grp->name, ICON_NONE, op->idname, "type", i);
+
+ /* finish building the menu, and process it (should result in calling self again) */
+ uiPupMenuEnd(C, pup);
+
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* just use the active group index, and call the exec callback for the calling operator */
+ RNA_int_set(op->ptr, "type", pose->active_group);
+ return op->type->exec(C, op);
+ }
+}
+
+/* Assign selected pchans to the bone group that the user selects */
+static int pose_group_assign_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_pose_object_from_context(C);
+ bPose *pose;
+ short done = FALSE;
+
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ pose = ob->pose;
+
+ /* set the active group number to the one from operator props
+ * - if 0 after this, make a new group...
+ */
+ pose->active_group = RNA_int_get(op->ptr, "type");
+ if (pose->active_group == 0)
+ BKE_pose_add_group(ob);
+
+ /* add selected bones to group then */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ pchan->agrp_index = pose->active_group;
+ done = TRUE;
+ }
+ CTX_DATA_END;
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ /* report done status */
+ if (done)
+ return OPERATOR_FINISHED;
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void POSE_OT_group_assign(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Selected to Bone Group";
+ ot->idname = "POSE_OT_group_assign";
+ ot->description = "Add selected bones to the chosen bone group";
+
+ /* api callbacks */
+ ot->invoke = pose_groups_menu_invoke;
+ ot->exec = pose_group_assign_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_int(ot->srna, "type", 0, 0, INT_MAX, "Bone Group Index", "", 0, 10);
+}
+
+
+static int pose_group_unassign_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_pose_object_from_context(C);
+ short done = FALSE;
+
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ /* find selected bones to remove from all bone groups */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ if (pchan->agrp_index) {
+ pchan->agrp_index = 0;
+ done = TRUE;
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ /* report done status */
+ if (done)
+ return OPERATOR_FINISHED;
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void POSE_OT_group_unassign(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Selected from Bone Groups";
+ ot->idname = "POSE_OT_group_unassign";
+ ot->description = "Remove selected bones from all bone groups";
+
+ /* api callbacks */
+ ot->exec = pose_group_unassign_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int group_move_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_pose_object_from_context(C);
+ bPose *pose = (ob) ? ob->pose : NULL;
+ bPoseChannel *pchan;
+ bActionGroup *grp;
+ int dir = RNA_enum_get(op->ptr, "direction");
+ int grpIndexA, grpIndexB;
+
+ if (ELEM(NULL, ob, pose))
+ return OPERATOR_CANCELLED;
+ if (pose->active_group <= 0)
+ return OPERATOR_CANCELLED;
+
+ /* get group to move */
+ grp = BLI_findlink(&pose->agroups, pose->active_group - 1);
+ if (grp == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* move bone group */
+ grpIndexA = pose->active_group;
+ if (dir == 1) { /* up */
+ void *prev = grp->prev;
+
+ if (prev == NULL)
+ return OPERATOR_FINISHED;
+
+ BLI_remlink(&pose->agroups, grp);
+ BLI_insertlinkbefore(&pose->agroups, prev, grp);
+
+ grpIndexB = grpIndexA - 1;
+ pose->active_group--;
+ }
+ else { /* down */
+ void *next = grp->next;
+
+ if (next == NULL)
+ return OPERATOR_FINISHED;
+
+ BLI_remlink(&pose->agroups, grp);
+ BLI_insertlinkafter(&pose->agroups, next, grp);
+
+ grpIndexB = grpIndexA + 1;
+ pose->active_group++;
+ }
+
+ /* fix changed bone group indices in bones (swap grpIndexA with grpIndexB) */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->agrp_index == grpIndexB)
+ pchan->agrp_index = grpIndexA;
+ else if (pchan->agrp_index == grpIndexA)
+ pchan->agrp_index = grpIndexB;
+ }
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem group_slot_move[] = {
+ {1, "UP", 0, "Up", ""},
+ {-1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Move Bone Group";
+ ot->idname = "POSE_OT_group_move";
+ ot->description = "Change position of active Bone Group in list of Bone Groups";
+
+ /* api callbacks */
+ ot->exec = group_move_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "direction", group_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+}
+
+/* bone group sort element */
+typedef struct tSortActionGroup {
+ bActionGroup *agrp;
+ int index;
+} tSortActionGroup;
+
+/* compare bone groups by name */
+static int compare_agroup(const void *sgrp_a_ptr, const void *sgrp_b_ptr)
+{
+ tSortActionGroup *sgrp_a = (tSortActionGroup *)sgrp_a_ptr;
+ tSortActionGroup *sgrp_b = (tSortActionGroup *)sgrp_b_ptr;
+
+ return strcmp(sgrp_a->agrp->name, sgrp_b->agrp->name);
+}
+
+static int group_sort_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_pose_object_from_context(C);
+ bPose *pose = (ob) ? ob->pose : NULL;
+ bPoseChannel *pchan;
+ tSortActionGroup *agrp_array;
+ bActionGroup *agrp;
+ int agrp_count;
+ int i;
+
+ if (ELEM(NULL, ob, pose))
+ return OPERATOR_CANCELLED;
+ if (pose->active_group <= 0)
+ return OPERATOR_CANCELLED;
+
+ /* create temporary array with bone groups and indices */
+ agrp_count = BLI_countlist(&pose->agroups);
+ agrp_array = MEM_mallocN(sizeof(tSortActionGroup) * agrp_count, "sort bone groups");
+ for (agrp = pose->agroups.first, i = 0; agrp; agrp = agrp->next, i++) {
+ BLI_assert(i < agrp_count);
+ agrp_array[i].agrp = agrp;
+ agrp_array[i].index = i + 1;
+ }
+
+ /* sort bone groups by name */
+ qsort(agrp_array, agrp_count, sizeof(tSortActionGroup), compare_agroup);
+
+ /* create sorted bone group list from sorted array */
+ pose->agroups.first = pose->agroups.last = NULL;
+ for (i = 0; i < agrp_count; i++) {
+ BLI_addtail(&pose->agroups, agrp_array[i].agrp);
+ }
+
+ /* fix changed bone group indizes in bones */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (i = 0; i < agrp_count; i++) {
+ if (pchan->agrp_index == agrp_array[i].index) {
+ pchan->agrp_index = i + 1;
+ break;
+ }
+ }
+ }
+
+ /* free temp resources */
+ MEM_freeN(agrp_array);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_sort(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sort Bone Groups";
+ ot->idname = "POSE_OT_group_sort";
+ ot->description = "Sort Bone Groups by their names in ascending order";
+
+ /* api callbacks */
+ ot->exec = group_sort_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static void pose_group_select(bContext *C, Object *ob, int select)
+{
+ bPose *pose = ob->pose;
+
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
+ if (select) {
+ if (pchan->agrp_index == pose->active_group)
+ pchan->bone->flag |= BONE_SELECTED;
+ }
+ else {
+ if (pchan->agrp_index == pose->active_group)
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ }
+ }
+ CTX_DATA_END;
+}
+
+static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_pose_object_from_context(C);
+
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ pose_group_select(C, ob, 1);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Bones of Bone Group";
+ ot->idname = "POSE_OT_group_select";
+ ot->description = "Select bones in active Bone Group";
+
+ /* api callbacks */
+ ot->exec = pose_group_select_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_pose_object_from_context(C);
+
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ pose_group_select(C, ob, 0);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_deselect(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Deselect Bone Group";
+ ot->idname = "POSE_OT_group_deselect";
+ ot->description = "Deselect bones of active Bone Group";
+
+ /* api callbacks */
+ ot->exec = pose_group_deselect_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************************** */
diff --git a/source/blender/editors/armature/poselib.c b/source/blender/editors/armature/pose_lib.c
index 48c0a4a38c3..457874c7ae6 100644
--- a/source/blender/editors/armature/poselib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -23,25 +23,17 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/armature/poselib.c
+/** \file blender/editors/armature/pose_lib.c
* \ingroup edarmature
*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
#include <string.h>
#include <math.h>
-#include <float.h>
#include "MEM_guardedalloc.h"
-#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
#include "BLI_dlrbTree.h"
-#include "BLI_utildefines.h"
#include "BLF_translation.h"
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
new file mode 100644
index 00000000000..186c7a1fe89
--- /dev/null
+++ b/source/blender/editors/armature/pose_select.c
@@ -0,0 +1,853 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/armature/pose_select.c
+ * \ingroup edarmature
+ */
+
+#include <string.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 "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_object.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_keyframing.h"
+#include "ED_mesh.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "armature_intern.h"
+
+/* ***************** Pose Select Utilities ********************* */
+
+/* called from editview.c, for mode-less pose selection */
+/* assumes scene obact and basact is still on old situation */
+int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits,
+ short extend, short deselect, short toggle)
+{
+ Object *ob = base->object;
+ Bone *nearBone;
+
+ if (!ob || !ob->pose) return 0;
+
+ nearBone = get_bone_from_selectbuffer(scene, base, buffer, hits, 1);
+
+ /* if the bone cannot be affected, don't do anything */
+ if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
+ Object *ob_act = OBACT;
+ bArmature *arm = ob->data;
+
+ /* since we do unified select, we don't shift+select a bone if the
+ * armature object was not active yet.
+ * note, special exception for armature mode so we can do multi-select
+ * we could check for multi-select explicitly but think its fine to
+ * always give predictable behavior in weight paint mode - campbell */
+ if ((!extend && !deselect && !toggle) ||
+ ((ob_act && (ob_act != ob) && (ob_act->mode & OB_MODE_WEIGHT_PAINT) == 0)))
+ {
+ ED_pose_deselectall(ob, 0);
+ nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = nearBone;
+ }
+ else {
+ if (extend) {
+ nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = nearBone;
+ }
+ else if (deselect) {
+ nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if (toggle) {
+ if (nearBone->flag & BONE_SELECTED) {
+ /* if not active, we make it active */
+ if (nearBone != arm->act_bone) {
+ arm->act_bone = nearBone;
+ }
+ else {
+ nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+ else {
+ nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = nearBone;
+ }
+ }
+ }
+
+ if (ob_act) {
+ /* in weightpaint we select the associated vertex group too */
+ if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
+ if (nearBone == arm->act_bone) {
+ ED_vgroup_select_by_name(ob_act, nearBone->name);
+ DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
+ }
+ }
+ /* if there are some dependencies for visualizing armature state
+ * (e.g. Mask Modifier in 'Armature' mode), force update
+ */
+ else if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
+ }
+ }
+ }
+
+ return nearBone != NULL;
+}
+
+/* test==0: deselect all
+ * test==1: swap select (apply to all the opposite of current situation)
+ * test==2: only clear active tag
+ * test==3: swap select (no test / inverse selection status of all independently)
+ */
+void ED_pose_deselectall(Object *ob, int test)
+{
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan;
+ int selectmode = 0;
+
+ /* we call this from outliner too */
+ if (ob->pose == NULL) {
+ return;
+ }
+
+ /* Determine if we're selecting or deselecting */
+ if (test == 1) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (PBONE_VISIBLE(arm, pchan->bone)) {
+ if (pchan->bone->flag & BONE_SELECTED)
+ break;
+ }
+ }
+
+ if (pchan == NULL)
+ selectmode = 1;
+ }
+ else if (test == 2)
+ selectmode = 2;
+
+ /* Set the flags accordingly */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* ignore the pchan if it isn't visible or if its selection cannot be changed */
+ if ((pchan->bone->layer & arm->layer) && !(pchan->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
+ if (test == 3) {
+ pchan->bone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ if (selectmode == 0) pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ else if (selectmode == 1) pchan->bone->flag |= BONE_SELECTED;
+ }
+ }
+ }
+}
+
+/* ***************** Selections ********************** */
+
+static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
+{
+ Bone *curBone;
+
+ /* stop when unconnected child is encontered, or when unselectable bone is encountered */
+ if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE))
+ return;
+
+ /* XXX old cruft! use notifiers instead */
+ //select_actionchannel_by_name (ob->action, bone->name, !(shift));
+
+ if (extend)
+ bone->flag &= ~BONE_SELECTED;
+ else
+ bone->flag |= BONE_SELECTED;
+
+ for (curBone = bone->childbase.first; curBone; curBone = curBone->next)
+ selectconnected_posebonechildren(ob, curBone, extend);
+}
+
+/* within active object context */
+/* previously known as "selectconnected_posearmature" */
+static int pose_select_connected_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = (bArmature *)ob->data;
+ Bone *bone, *curBone, *next = NULL;
+ int extend = RNA_boolean_get(op->ptr, "extend");
+
+ view3d_operator_needs_opengl(C);
+
+ if (extend)
+ bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
+ else
+ bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]);
+
+ if (!bone)
+ return OPERATOR_CANCELLED;
+
+ /* Select parents */
+ for (curBone = bone; curBone; curBone = next) {
+ /* ignore bone if cannot be selected */
+ if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
+ if (extend)
+ curBone->flag &= ~BONE_SELECTED;
+ else
+ curBone->flag |= BONE_SELECTED;
+
+ if (curBone->flag & BONE_CONNECTED)
+ next = curBone->parent;
+ else
+ next = NULL;
+ }
+ else
+ next = NULL;
+ }
+
+ /* Select children */
+ for (curBone = bone->childbase.first; curBone; curBone = next)
+ selectconnected_posebonechildren(ob, curBone, extend);
+
+ /* updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int pose_select_linked_poll(bContext *C)
+{
+ return (ED_operator_view3d_active(C) && ED_operator_posemode(C));
+}
+
+void POSE_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Connected";
+ ot->idname = "POSE_OT_select_linked";
+ ot->description = "Select bones related to selected ones by parent/child relationships";
+
+ /* api callbacks */
+ ot->exec = NULL;
+ ot->invoke = pose_select_connected_invoke;
+ ot->poll = pose_select_linked_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
+}
+
+/* -------------------------------------- */
+
+static int pose_de_select_all_exec(bContext *C, wmOperator *op)
+{
+ int action = RNA_enum_get(op->ptr, "action");
+
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = ED_object_context(C);
+ bArmature *arm = ob->data;
+ int multipaint = scene->toolsettings->multipaint;
+
+ if (action == SEL_TOGGLE) {
+ action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT;
+ }
+
+ /* Set the flags */
+ CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ /* select pchan only if selectable, but deselect works always */
+ switch (action) {
+ case SEL_SELECT:
+ if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
+ pchan->bone->flag |= BONE_SELECTED;
+ break;
+ case SEL_DESELECT:
+ pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ case SEL_INVERT:
+ if (pchan->bone->flag & BONE_SELECTED) {
+ pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
+ pchan->bone->flag |= BONE_SELECTED;
+ }
+ break;
+ }
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
+
+ /* weightpaint or mask modifiers need depsgraph updates */
+ if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "(De)select All";
+ ot->idname = "POSE_OT_select_all";
+ ot->description = "Toggle selection status of all bones";
+
+ /* api callbacks */
+ ot->exec = pose_de_select_all_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_select_all(ot);
+}
+
+/* -------------------------------------- */
+
+static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = (bArmature *)ob->data;
+ bPoseChannel *pchan, *parent;
+
+ /* Determine if there is an active bone */
+ pchan = CTX_data_active_pose_bone(C);
+ if (pchan) {
+ parent = pchan->parent;
+ if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
+ parent->bone->flag |= BONE_SELECTED;
+ arm->act_bone = parent->bone;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_parent(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Parent Bone";
+ ot->idname = "POSE_OT_select_parent";
+ ot->description = "Select bones that are parents of the currently selected bones";
+
+ /* api callbacks */
+ ot->exec = pose_select_parent_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* -------------------------------------- */
+
+static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = (bArmature *)ob->data;
+ bConstraint *con;
+ int found = 0;
+
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ if (pchan->bone->flag & BONE_SELECTED) {
+ for (con = pchan->constraints.first; con; con = con->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if ((ct->tar == ob) && (ct->subtarget[0])) {
+ bPoseChannel *pchanc = BKE_pose_channel_find_name(ob->pose, ct->subtarget);
+ if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
+ pchanc->bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
+ found = 1;
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ if (!found)
+ return OPERATOR_CANCELLED;
+
+ /* updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_constraint_target(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Constraint Target";
+ ot->idname = "POSE_OT_select_constraint_target";
+ ot->description = "Select bones used as targets for the currently selected bones";
+
+ /* api callbacks */
+ ot->exec = pose_select_constraint_target_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* -------------------------------------- */
+
+static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = ob->data;
+ Bone *curbone, *pabone, *chbone;
+ int direction = RNA_enum_get(op->ptr, "direction");
+ int add_to_sel = RNA_boolean_get(op->ptr, "extend");
+ int found = 0;
+
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ curbone = pchan->bone;
+
+ if ((curbone->flag & BONE_UNSELECTABLE) == 0) {
+ if (curbone == arm->act_bone) {
+ if (direction == BONE_SELECT_PARENT) {
+ if (pchan->parent == NULL) continue;
+ else pabone = pchan->parent->bone;
+
+ if (PBONE_SELECTABLE(arm, pabone)) {
+ if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
+ pabone->flag |= BONE_SELECTED;
+ arm->act_bone = pabone;
+
+ found = 1;
+ break;
+ }
+ }
+ else { /* direction == BONE_SELECT_CHILD */
+ /* the child member is only assigned to connected bones, see [#30340] */
+#if 0
+ if (pchan->child == NULL) continue;
+ else chbone = pchan->child->bone;
+#else
+ /* instead. find _any_ visible child bone, using the first one is a little arbitrary - campbell */
+ chbone = pchan->child ? pchan->child->bone : NULL;
+ if (chbone == NULL) {
+ bPoseChannel *pchan_child;
+
+ for (pchan_child = ob->pose->chanbase.first; pchan_child; pchan_child = pchan_child->next) {
+ /* possible we have multiple children, some invisible */
+ if (PBONE_SELECTABLE(arm, pchan_child->bone)) {
+ if (pchan_child->parent == pchan) {
+ chbone = pchan_child->bone;
+ break;
+ }
+ }
+ }
+ }
+
+ if (chbone == NULL) continue;
+#endif
+
+ if (PBONE_SELECTABLE(arm, chbone)) {
+ if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
+ chbone->flag |= BONE_SELECTED;
+ arm->act_bone = chbone;
+
+ found = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ if (found == 0)
+ return OPERATOR_CANCELLED;
+
+ /* updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_hierarchy(wmOperatorType *ot)
+{
+ static EnumPropertyItem direction_items[] = {
+ {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
+ {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Select Hierarchy";
+ ot->idname = "POSE_OT_select_hierarchy";
+ ot->description = "Select immediate parent/children of selected bones";
+
+ /* api callbacks */
+ ot->exec = pose_select_hierarchy_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ ot->prop = RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+}
+
+/* -------------------------------------- */
+
+static short pose_select_same_group(bContext *C, Object *ob, short extend)
+{
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bPose *pose = (ob) ? ob->pose : NULL;
+ char *group_flags;
+ int numGroups = 0;
+ short changed = 0, tagged = 0;
+
+ /* sanity checks */
+ if (ELEM3(NULL, ob, pose, arm))
+ return 0;
+
+ /* count the number of groups */
+ numGroups = BLI_countlist(&pose->agroups);
+ if (numGroups == 0)
+ return 0;
+
+ /* alloc a small array to keep track of the groups to use
+ * - each cell stores on/off state for whether group should be used
+ * - size is (numGroups + 1), since (index = 0) is used for no-group
+ */
+ group_flags = MEM_callocN(numGroups + 1, "pose_select_same_group");
+
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ /* keep track of group as group to use later? */
+ if (pchan->bone->flag & BONE_SELECTED) {
+ group_flags[pchan->agrp_index] = 1;
+ tagged = 1;
+ }
+
+ /* deselect all bones before selecting new ones? */
+ if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ CTX_DATA_END;
+
+ /* small optimization: only loop through bones a second time if there are any groups tagged */
+ if (tagged) {
+ /* only if group matches (and is not selected or current bone) */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
+ /* check if the group used by this bone is counted */
+ if (group_flags[pchan->agrp_index]) {
+ pchan->bone->flag |= BONE_SELECTED;
+ changed = 1;
+ }
+ }
+ }
+ CTX_DATA_END;
+ }
+
+ /* free temp info */
+ MEM_freeN(group_flags);
+
+ return changed;
+}
+
+static short pose_select_same_layer(bContext *C, Object *ob, short extend)
+{
+ bPose *pose = (ob) ? ob->pose : NULL;
+ bArmature *arm = (ob) ? ob->data : NULL;
+ short changed = 0;
+ int layers = 0;
+
+ if (ELEM3(NULL, ob, pose, arm))
+ return 0;
+
+ /* figure out what bones are selected */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ /* keep track of layers to use later? */
+ if (pchan->bone->flag & BONE_SELECTED)
+ layers |= pchan->bone->layer;
+
+ /* deselect all bones before selecting new ones? */
+ if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ CTX_DATA_END;
+ if (layers == 0)
+ return 0;
+
+ /* select bones that are on same layers as layers flag */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ /* if bone is on a suitable layer, and the bone can have its selection changed, select it */
+ if ((layers & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
+ pchan->bone->flag |= BONE_SELECTED;
+ changed = 1;
+ }
+ }
+ CTX_DATA_END;
+
+ return changed;
+}
+
+static int pose_select_same_keyingset(bContext *C, Object *ob, short extend)
+{
+ KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
+ KS_Path *ksp;
+
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bPose *pose = (ob) ? ob->pose : NULL;
+ short changed = 0;
+
+ /* sanity checks: validate Keying Set and object */
+ if ((ks == NULL) || (ANIM_validate_keyingset(C, NULL, ks) != 0))
+ return 0;
+
+ if (ELEM3(NULL, ob, pose, arm))
+ return 0;
+
+ /* if not extending selection, deselect all selected first */
+ if (extend == 0) {
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ CTX_DATA_END;
+ }
+
+ /* iterate over elements in the Keying Set, setting selection depending on whether
+ * that bone is visible or not...
+ */
+ for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
+ /* only items related to this object will be relevant */
+ if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) {
+ if (strstr(ksp->rna_path, "bones")) {
+ char *boneName = BLI_str_quoted_substrN(ksp->rna_path, "bones[");
+
+ if (boneName) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
+
+ if (pchan) {
+ /* select if bone is visible and can be affected */
+ if (PBONE_SELECTABLE(arm, pchan->bone)) {
+ pchan->bone->flag |= BONE_SELECTED;
+ changed = 1;
+ }
+ }
+
+ /* free temp memory */
+ MEM_freeN(boneName);
+ }
+ }
+ }
+ }
+
+ return changed;
+}
+
+static int pose_select_grouped_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = (bArmature *)ob->data;
+ short extend = RNA_boolean_get(op->ptr, "extend");
+ short changed = 0;
+
+ /* sanity check */
+ if (ob->pose == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* selection types
+ * NOTE: for the order of these, see the enum in POSE_OT_select_grouped()
+ */
+ switch (RNA_enum_get(op->ptr, "type")) {
+ case 1: /* group */
+ changed = pose_select_same_group(C, ob, extend);
+ break;
+ case 2: /* Keying Set */
+ changed = pose_select_same_keyingset(C, ob, extend);
+ break;
+ default: /* layer */
+ changed = pose_select_same_layer(C, ob, extend);
+ break;
+ }
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ /* report done status */
+ if (changed)
+ return OPERATOR_FINISHED;
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void POSE_OT_select_grouped(wmOperatorType *ot)
+{
+ static EnumPropertyItem prop_select_grouped_types[] = {
+ {0, "LAYER", 0, "Layer", "Shared layers"},
+ {1, "GROUP", 0, "Group", "Shared group"},
+ {2, "KEYINGSET", 0, "Keying Set", "All bones affected by active Keying Set"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Select Grouped";
+ ot->description = "Select all visible bones grouped by similar properties";
+ ot->idname = "POSE_OT_select_grouped";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = pose_select_grouped_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
+}
+
+/* -------------------------------------- */
+
+/* context active object, or weightpainted object with armature in posemode */
+static int pose_bone_flip_active_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob_act = CTX_data_active_object(C);
+ Object *ob = BKE_object_pose_armature_get(ob_act);
+
+ if (ob && (ob->mode & OB_MODE_POSE)) {
+ bArmature *arm = ob->data;
+
+ if (arm->act_bone) {
+ bPoseChannel *pchanf;
+ char name[MAXBONENAME];
+ flip_side_name(name, arm->act_bone->name, TRUE);
+
+ pchanf = BKE_pose_channel_find_name(ob->pose, name);
+ if (pchanf && pchanf->bone != arm->act_bone) {
+ arm->act_bone->flag &= ~BONE_SELECTED;
+ pchanf->bone->flag |= BONE_SELECTED;
+
+ arm->act_bone = pchanf->bone;
+
+ /* in weightpaint we select the associated vertex group too */
+ if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
+ ED_vgroup_select_by_name(ob_act, name);
+ DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+ }
+ }
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void POSE_OT_select_flip_active(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flip Selected Active Bone";
+ ot->idname = "POSE_OT_select_flip_active";
+ ot->description = "Activate the bone with a flipped name";
+
+ /* api callbacks */
+ ot->exec = pose_bone_flip_active_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/pose_slide.c
index 3fd65de6c04..fee37a9c0fb 100644
--- a/source/blender/editors/armature/poseSlide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -23,25 +23,15 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/armature/poseSlide.c
+/** \file blender/editors/armature/pose_slide.c
* \ingroup edarmature
*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
#include "BLI_dlrbTree.h"
-#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
new file mode 100644
index 00000000000..2525641e58c
--- /dev/null
+++ b/source/blender/editors/armature/pose_transform.c
@@ -0,0 +1,879 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/armature/pose_transform.c
+ * \ingroup edarmature
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_animsys.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_keyframing.h"
+#include "ED_screen.h"
+#include "ED_util.h"
+
+#include "armature_intern.h"
+
+
+/* ********************************************** */
+/* Pose Apply */
+
+/* helper for apply_armature_pose2bones - fixes parenting of objects that are bone-parented to armature */
+static void applyarmature_fix_boneparents(Scene *scene, Object *armob)
+{
+ Object workob, *ob;
+
+ /* go through all objects in database */
+ for (ob = G.main->object.first; ob; ob = ob->id.next) {
+ /* if parent is bone in this armature, apply corrections */
+ if ((ob->parent == armob) && (ob->partype == PARBONE)) {
+ /* apply current transform from parent (not yet destroyed),
+ * then calculate new parent inverse matrix
+ */
+ BKE_object_apply_mat4(ob, ob->obmat, FALSE, FALSE);
+
+ BKE_object_workob_calc_parent(scene, ob, &workob);
+ invert_m4_m4(ob->parentinv, workob.obmat);
+ }
+ }
+}
+
+/* set the current pose as the restpose */
+static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object
+ bArmature *arm = BKE_armature_from_object(ob);
+ bPose *pose;
+ bPoseChannel *pchan;
+ EditBone *curbone;
+
+ /* don't check if editmode (should be done by caller) */
+ if (ob->type != OB_ARMATURE)
+ return OPERATOR_CANCELLED;
+ if (BKE_object_obdata_is_libdata(ob)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot apply pose to lib-linked armature"); /* error_libdata(); */
+ return OPERATOR_CANCELLED;
+ }
+
+ /* helpful warnings... */
+ /* TODO: add warnings to be careful about actions, applying deforms first, etc. */
+ if (ob->adt && ob->adt->action)
+ BKE_report(op->reports, RPT_WARNING,
+ "Actions on this armature will be destroyed by this new rest pose as the "
+ "transforms stored are relative to the old rest pose");
+
+ /* Get editbones of active armature to alter */
+ ED_armature_to_edit(ob);
+
+ /* get pose of active object and move it out of posemode */
+ pose = ob->pose;
+
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ curbone = editbone_name_exists(arm->edbo, pchan->name);
+
+ /* simply copy the head/tail values from pchan over to curbone */
+ copy_v3_v3(curbone->head, pchan->pose_head);
+ copy_v3_v3(curbone->tail, pchan->pose_tail);
+
+ /* fix roll:
+ * 1. find auto-calculated roll value for this bone now
+ * 2. remove this from the 'visual' y-rotation
+ */
+ {
+ float premat[3][3], imat[3][3], pmat[3][3], tmat[3][3];
+ float delta[3], eul[3];
+
+ /* obtain new auto y-rotation */
+ sub_v3_v3v3(delta, curbone->tail, curbone->head);
+ vec_roll_to_mat3(delta, 0.0f, premat);
+ invert_m3_m3(imat, premat);
+
+ /* get pchan 'visual' matrix */
+ copy_m3_m4(pmat, pchan->pose_mat);
+
+ /* remove auto from visual and get euler rotation */
+ mul_m3_m3m3(tmat, imat, pmat);
+ mat3_to_eul(eul, tmat);
+
+ /* just use this euler-y as new roll value */
+ curbone->roll = eul[1];
+ }
+
+ /* clear transform values for pchan */
+ zero_v3(pchan->loc);
+ zero_v3(pchan->eul);
+ unit_qt(pchan->quat);
+ unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
+ pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
+
+ /* set anim lock */
+ curbone->flag |= BONE_UNKEYED;
+ }
+
+ /* convert editbones back to bones, and then free the edit-data */
+ ED_armature_from_edit(ob);
+ ED_armature_edit_free(ob);
+
+ /* flush positions of posebones */
+ BKE_pose_where_is(scene, ob);
+
+ /* fix parenting of objects which are bone-parented */
+ applyarmature_fix_boneparents(scene, ob);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_armature_apply(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Apply Pose as Rest Pose";
+ ot->idname = "POSE_OT_armature_apply";
+ ot->description = "Apply the current pose as the new rest pose";
+
+ /* callbacks */
+ ot->exec = apply_armature_pose2bones_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+/* set the current pose as the restpose */
+static int pose_visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object
+
+ /* don't check if editmode (should be done by caller) */
+ if (ob->type != OB_ARMATURE)
+ return OPERATOR_CANCELLED;
+
+ /* loop over all selected pchans
+ *
+ * TODO, loop over children before parents if multiple bones
+ * at once are to be predictable*/
+ CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ float delta_mat[4][4];
+
+ /* chan_mat already contains the delta transform from rest pose to pose-mode pose
+ * as that is baked into there so that B-Bones will work. Once we've set this as the
+ * new raw-transform components, don't recalc the poses yet, otherwise IK result will
+ * change, thus changing the result we may be trying to record.
+ */
+ copy_m4_m4(delta_mat, pchan->chan_mat);
+ BKE_pchan_apply_mat4(pchan, delta_mat, TRUE);
+ }
+ CTX_DATA_END;
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_visual_transform_apply(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Apply Visual Transform to Pose";
+ ot->idname = "POSE_OT_visual_transform_apply";
+ ot->description = "Apply final constrained position of pose bones to their transform";
+
+ /* callbacks */
+ ot->exec = pose_visual_transform_apply_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************************** */
+/* Copy/Paste */
+
+/* Global copy/paste buffer for pose - cleared on start/end session + before every copy operation */
+static bPose *g_posebuf = NULL;
+
+void ED_clipboard_posebuf_free(void)
+{
+ if (g_posebuf) {
+ bPoseChannel *pchan;
+
+ for (pchan = g_posebuf->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->prop) {
+ IDP_FreeProperty(pchan->prop);
+ MEM_freeN(pchan->prop);
+ }
+ }
+
+ /* was copied without constraints */
+ BLI_freelistN(&g_posebuf->chanbase);
+ MEM_freeN(g_posebuf);
+ }
+
+ g_posebuf = NULL;
+}
+
+/* This function is used to indicate that a bone is selected
+ * and needs to be included in copy buffer (used to be for inserting keys)
+ */
+static void set_pose_keys(Object *ob)
+{
+ bArmature *arm = ob->data;
+ bPoseChannel *chan;
+
+ if (ob->pose) {
+ for (chan = ob->pose->chanbase.first; chan; chan = chan->next) {
+ Bone *bone = chan->bone;
+ if ((bone) && (bone->flag & BONE_SELECTED) && (arm->layer & bone->layer))
+ chan->flag |= POSE_KEY;
+ else
+ chan->flag &= ~POSE_KEY;
+ }
+ }
+}
+
+/* perform paste pose, for a single bone
+ * < ob: object where bone to paste to lives
+ * < chan: bone that pose to paste comes from
+ * < selOnly: only paste on selected bones
+ * < flip: flip on x-axis
+ *
+ * > returns: whether the bone that we pasted to if we succeeded
+ */
+static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, short selOnly, short flip)
+{
+ bPoseChannel *pchan;
+ char name[MAXBONENAME];
+ short paste_ok;
+
+ /* get the name - if flipping, we must flip this first */
+ if (flip)
+ flip_side_name(name, chan->name, 0); /* 0 = don't strip off number extensions */
+ else
+ BLI_strncpy(name, chan->name, sizeof(name));
+
+ /* only copy when:
+ * 1) channel exists - poses are not meant to add random channels to anymore
+ * 2) if selection-masking is on, channel is selected - only selected bones get pasted on, allowing making both sides symmetrical
+ */
+ pchan = BKE_pose_channel_find_name(ob->pose, name);
+
+ if (selOnly)
+ paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED));
+ else
+ paste_ok = ((pchan != NULL));
+
+ /* continue? */
+ if (paste_ok) {
+ /* only loc rot size
+ * - only copies transform info for the pose
+ */
+ copy_v3_v3(pchan->loc, chan->loc);
+ copy_v3_v3(pchan->size, chan->size);
+ pchan->flag = chan->flag;
+
+ /* check if rotation modes are compatible (i.e. do they need any conversions) */
+ if (pchan->rotmode == chan->rotmode) {
+ /* copy the type of rotation in use */
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(pchan->eul, chan->eul);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ copy_v3_v3(pchan->rotAxis, chan->rotAxis);
+ pchan->rotAngle = chan->rotAngle;
+ }
+ else {
+ copy_qt_qt(pchan->quat, chan->quat);
+ }
+ }
+ else if (pchan->rotmode > 0) {
+ /* quat/axis-angle to euler */
+ if (chan->rotmode == ROT_MODE_AXISANGLE)
+ axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
+ else
+ quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* quat/euler to axis angle */
+ if (chan->rotmode > 0)
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
+ else
+ quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
+ }
+ else {
+ /* euler/axis-angle to quat */
+ if (chan->rotmode > 0)
+ eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
+ else
+ axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
+ }
+
+ /* paste flipped pose? */
+ if (flip) {
+ pchan->loc[0] *= -1;
+
+ /* has to be done as eulers... */
+ if (pchan->rotmode > 0) {
+ pchan->eul[1] *= -1;
+ pchan->eul[2] *= -1;
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ float eul[3];
+
+ axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
+ }
+ else {
+ float eul[3];
+
+ normalize_qt(pchan->quat);
+ quat_to_eul(eul, pchan->quat);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eul_to_quat(pchan->quat, eul);
+ }
+ }
+
+ /* ID properties */
+ if (chan->prop) {
+ if (pchan->prop) {
+ /* if we have existing properties on a bone, just copy over the values of
+ * matching properties (i.e. ones which will have some impact) on to the
+ * target instead of just blinding replacing all [
+ */
+ IDP_SyncGroupValues(pchan->prop, chan->prop);
+ }
+ else {
+ /* no existing properties, so assume that we want copies too? */
+ pchan->prop = IDP_CopyProperty(chan->prop);
+ }
+ }
+ }
+
+ /* return whether paste went ahead */
+ return pchan;
+}
+
+/* ---- */
+
+static int pose_copy_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+
+ /* sanity checking */
+ if (ELEM(NULL, ob, ob->pose)) {
+ BKE_report(op->reports, RPT_ERROR, "No pose to copy");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* free existing pose buffer */
+ ED_clipboard_posebuf_free();
+
+ /* sets chan->flag to POSE_KEY if bone selected, then copy those bones to the buffer */
+ set_pose_keys(ob);
+ BKE_pose_copy_data(&g_posebuf, ob->pose, 0);
+
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_copy(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy Pose";
+ ot->idname = "POSE_OT_copy";
+ ot->description = "Copies the current pose of the selected bones to copy/paste buffer";
+
+ /* api callbacks */
+ ot->exec = pose_copy_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flag */
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/* ---- */
+
+static int pose_paste_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ Scene *scene = CTX_data_scene(C);
+ bPoseChannel *chan;
+ int flip = RNA_boolean_get(op->ptr, "flipped");
+ int selOnly = RNA_boolean_get(op->ptr, "selected_mask");
+
+ /* get KeyingSet to use */
+ KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOC_ROT_SCALE_ID);
+
+ /* sanity checks */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ if (g_posebuf == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* if selOnly option is enabled, if user hasn't selected any bones,
+ * just go back to default behavior to be more in line with other pose tools
+ */
+ if (selOnly) {
+ if (CTX_DATA_COUNT(C, selected_pose_bones) == 0)
+ selOnly = 0;
+ }
+
+ /* Safely merge all of the channels in the buffer pose into any existing pose */
+ for (chan = g_posebuf->chanbase.first; chan; chan = chan->next) {
+ if (chan->flag & POSE_KEY) {
+ /* try to perform paste on this bone */
+ bPoseChannel *pchan = pose_bone_do_paste(ob, chan, selOnly, flip);
+
+ if (pchan) {
+ /* keyframing tagging for successful paste */
+ ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
+ }
+ }
+ }
+
+ /* Update event for pose and deformation children */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_paste(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Paste Pose";
+ ot->idname = "POSE_OT_paste";
+ ot->description = "Paste the stored pose on to the current pose";
+
+ /* api callbacks */
+ ot->exec = pose_paste_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flag */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "flipped", FALSE, "Flipped on X-Axis", "Paste the stored pose flipped on to current pose");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ RNA_def_boolean(ot->srna, "selected_mask", FALSE, "On Selected Only", "Only paste the stored pose on to selected bones in the current pose");
+}
+
+/* ********************************************** */
+/* Clear Pose Transforms */
+
+/* clear scale of pose-channel */
+static void pchan_clear_scale(bPoseChannel *pchan)
+{
+ if ((pchan->protectflag & OB_LOCK_SCALEX) == 0)
+ pchan->size[0] = 1.0f;
+ if ((pchan->protectflag & OB_LOCK_SCALEY) == 0)
+ pchan->size[1] = 1.0f;
+ if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0)
+ pchan->size[2] = 1.0f;
+}
+
+/* clear location of pose-channel */
+static void pchan_clear_loc(bPoseChannel *pchan)
+{
+ if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
+ pchan->loc[0] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
+ pchan->loc[1] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
+ pchan->loc[2] = 0.0f;
+}
+
+/* clear rotation of pose-channel */
+static void pchan_clear_rot(bPoseChannel *pchan)
+{
+ if (pchan->protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) {
+ /* check if convert to eulers for locking... */
+ if (pchan->protectflag & OB_LOCK_ROT4D) {
+ /* perform clamping on a component by component basis */
+ if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
+ pchan->rotAngle = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
+ pchan->rotAxis[0] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
+ pchan->rotAxis[1] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
+ pchan->rotAxis[2] = 0.0f;
+
+ /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */
+ if (IS_EQF(pchan->rotAxis[0], pchan->rotAxis[1]) && IS_EQF(pchan->rotAxis[1], pchan->rotAxis[2]))
+ pchan->rotAxis[1] = 1.0f;
+ }
+ else if (pchan->rotmode == ROT_MODE_QUAT) {
+ if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
+ pchan->quat[0] = 1.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
+ pchan->quat[1] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
+ pchan->quat[2] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
+ pchan->quat[3] = 0.0f;
+ }
+ else {
+ /* the flag may have been set for the other modes, so just ignore the extra flag... */
+ if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
+ pchan->eul[0] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
+ pchan->eul[1] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
+ pchan->eul[2] = 0.0f;
+ }
+ }
+ else {
+ /* perform clamping using euler form (3-components) */
+ float eul[3], oldeul[3], quat1[4] = {0};
+ float qlen = 0.0f;
+
+ if (pchan->rotmode == ROT_MODE_QUAT) {
+ qlen = normalize_qt_qt(quat1, pchan->quat);
+ quat_to_eul(oldeul, quat1);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
+ }
+ else {
+ copy_v3_v3(oldeul, pchan->eul);
+ }
+
+ eul[0] = eul[1] = eul[2] = 0.0f;
+
+ if (pchan->protectflag & OB_LOCK_ROTX)
+ eul[0] = oldeul[0];
+ if (pchan->protectflag & OB_LOCK_ROTY)
+ eul[1] = oldeul[1];
+ if (pchan->protectflag & OB_LOCK_ROTZ)
+ eul[2] = oldeul[2];
+
+ if (pchan->rotmode == ROT_MODE_QUAT) {
+ eul_to_quat(pchan->quat, eul);
+
+ /* restore original quat size */
+ mul_qt_fl(pchan->quat, qlen);
+
+ /* quaternions flip w sign to accumulate rotations correctly */
+ if ((quat1[0] < 0.0f && pchan->quat[0] > 0.0f) || (quat1[0] > 0.0f && pchan->quat[0] < 0.0f)) {
+ mul_qt_fl(pchan->quat, -1.0f);
+ }
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
+ }
+ else {
+ copy_v3_v3(pchan->eul, eul);
+ }
+ }
+ } /* Duplicated in source/blender/editors/object/object_transform.c */
+ else {
+ if (pchan->rotmode == ROT_MODE_QUAT) {
+ unit_qt(pchan->quat);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* by default, make rotation of 0 radians around y-axis (roll) */
+ unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
+ }
+ else {
+ zero_v3(pchan->eul);
+ }
+ }
+}
+
+/* clear loc/rot/scale of pose-channel */
+static void pchan_clear_transforms(bPoseChannel *pchan)
+{
+ pchan_clear_loc(pchan);
+ pchan_clear_rot(pchan);
+ pchan_clear_scale(pchan);
+}
+
+/* --------------- */
+
+/* generic exec for clear-pose operators */
+static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op,
+ void (*clear_func)(bPoseChannel *), const char default_ksName[])
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ short autokey = 0;
+
+ /* sanity checks */
+ if (ELEM(NULL, clear_func, default_ksName)) {
+ BKE_report(op->reports, RPT_ERROR, "Programming error: missing clear transform function or keying set name");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* only clear relevant transforms for selected bones */
+ CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ /* run provided clearing function */
+ clear_func(pchan);
+
+ /* do auto-keyframing as appropriate */
+ if (autokeyframe_cfra_can_key(scene, &ob->id)) {
+ /* clear any unkeyed tags */
+ if (pchan->bone)
+ pchan->bone->flag &= ~BONE_UNKEYED;
+
+ /* tag for autokeying later */
+ autokey = 1;
+ }
+ else {
+ /* add unkeyed tags */
+ if (pchan->bone)
+ pchan->bone->flag |= BONE_UNKEYED;
+ }
+ }
+ CTX_DATA_END;
+
+ /* perform autokeying on the bones if needed */
+ if (autokey) {
+ /* get KeyingSet to use */
+ KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
+
+ /* insert keyframes */
+ ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+
+ /* now recalculate paths */
+ if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS))
+ ED_pose_recalculate_paths(scene, ob);
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+/* --------------- */
+
+static int pose_clear_scale_exec(bContext *C, wmOperator *op)
+{
+ return pose_clear_transform_generic_exec(C, op, pchan_clear_scale, ANIM_KS_SCALING_ID);
+}
+
+void POSE_OT_scale_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Pose Scale";
+ ot->idname = "POSE_OT_scale_clear";
+ ot->description = "Reset scaling of selected bones to their default values";
+
+ /* api callbacks */
+ ot->exec = pose_clear_scale_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int pose_clear_rot_exec(bContext *C, wmOperator *op)
+{
+ return pose_clear_transform_generic_exec(C, op, pchan_clear_rot, ANIM_KS_ROTATION_ID);
+}
+
+void POSE_OT_rot_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Pose Rotation";
+ ot->idname = "POSE_OT_rot_clear";
+ ot->description = "Reset rotations of selected bones to their default values";
+
+ /* api callbacks */
+ ot->exec = pose_clear_rot_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int pose_clear_loc_exec(bContext *C, wmOperator *op)
+{
+ return pose_clear_transform_generic_exec(C, op, pchan_clear_loc, ANIM_KS_LOCATION_ID);
+}
+
+void POSE_OT_loc_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Pose Location";
+ ot->idname = "POSE_OT_loc_clear";
+ ot->description = "Reset locations of selected bones to their default values";
+
+ /* api callbacks */
+ ot->exec = pose_clear_loc_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int pose_clear_transforms_exec(bContext *C, wmOperator *op)
+{
+ return pose_clear_transform_generic_exec(C, op, pchan_clear_transforms, ANIM_KS_LOC_ROT_SCALE_ID);
+}
+
+void POSE_OT_transforms_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Pose Transforms";
+ ot->idname = "POSE_OT_transforms_clear";
+ ot->description = "Reset location, rotation, and scaling of selected bones to their default values";
+
+ /* api callbacks */
+ ot->exec = pose_clear_transforms_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************************** */
+/* Clear User Transforms */
+
+static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ float cframe = (float)CFRA;
+ const short only_select = RNA_boolean_get(op->ptr, "only_selected");
+
+ if ((ob->adt) && (ob->adt->action)) {
+ /* XXX: this is just like this to avoid contaminating anything else;
+ * just pose values should change, so this should be fine
+ */
+ bPose *dummyPose = NULL;
+ Object workob = {{0}};
+ bPoseChannel *pchan;
+
+ /* execute animation step for current frame using a dummy copy of the pose */
+ BKE_pose_copy_data(&dummyPose, ob->pose, 0);
+
+ BLI_strncpy(workob.id.name, "OB<ClearTfmWorkOb>", sizeof(workob.id.name));
+ workob.type = OB_ARMATURE;
+ workob.data = ob->data;
+ workob.adt = ob->adt;
+ workob.pose = dummyPose;
+
+ BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM);
+
+ /* copy back values, but on selected bones only */
+ for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
+ pose_bone_do_paste(ob, pchan, only_select, 0);
+ }
+
+ /* free temp data - free manually as was copied without constraints */
+ for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->prop) {
+ IDP_FreeProperty(pchan->prop);
+ MEM_freeN(pchan->prop);
+ }
+ }
+
+ /* was copied without constraints */
+ BLI_freelistN(&dummyPose->chanbase);
+ MEM_freeN(dummyPose);
+ }
+ else {
+ /* no animation, so just reset whole pose to rest pose
+ * (cannot just restore for selected though)
+ */
+ BKE_pose_rest(ob->pose);
+ }
+
+ /* notifiers and updates */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_user_transforms_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear User Transforms";
+ ot->idname = "POSE_OT_user_transforms_clear";
+ ot->description = "Reset pose on selected bones to keyframed state";
+
+ /* callbacks */
+ ot->exec = pose_clear_user_transforms_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "only_selected", TRUE, "Only Selected", "Only visible/selected bones");
+}
diff --git a/source/blender/editors/armature/poseUtils.c b/source/blender/editors/armature/pose_utils.c
index f3c32399ad6..a5e51ccf32a 100644
--- a/source/blender/editors/armature/poseUtils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -23,25 +23,14 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/armature/poseUtils.c
+/** \file blender/editors/armature/pose_utils.c
* \ingroup edarmature
*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
-#include "BLI_dlrbTree.h"
-#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c
deleted file mode 100644
index c7d1e428355..00000000000
--- a/source/blender/editors/armature/poseobject.c
+++ /dev/null
@@ -1,2364 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): Ton Roosendaal, Blender Foundation '05, full recode.
- * Joshua Leung
- *
- * ***** END GPL LICENSE BLOCK *****
- * support for animation modes - Reevan McKay
- */
-
-/** \file blender/editors/armature/poseobject.c
- * \ingroup edarmature
- */
-
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-
-#include "BKE_animsys.h"
-#include "BKE_anim.h"
-#include "BKE_idprop.h"
-#include "BKE_action.h"
-#include "BKE_armature.h"
-#include "BKE_context.h"
-#include "BKE_constraint.h"
-#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
-#include "BKE_fcurve.h"
-#include "BKE_modifier.h"
-#include "BKE_object.h"
-#include "BKE_report.h"
-
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_armature.h"
-#include "ED_keyframing.h"
-#include "ED_mesh.h"
-#include "ED_screen.h"
-#include "ED_object.h"
-#include "ED_util.h" /* clipboard */
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "armature_intern.h"
-
-/* matches logic with ED_operator_posemode_context() */
-Object *ED_pose_object_from_context(bContext *C)
-{
- ScrArea *sa = CTX_wm_area(C);
- Object *ob;
-
- /* since this call may also be used from the buttons window, we need to check for where to get the object */
- if (sa && sa->spacetype == SPACE_BUTS) {
- ob = ED_object_context(C);
- }
- else {
- ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- }
-
- return ob;
-}
-
-/* This function is used to process the necessary updates for */
-void ED_armature_enter_posemode(bContext *C, Base *base)
-{
- ReportList *reports = CTX_wm_reports(C);
- Object *ob = base->object;
-
- if (ob->id.lib) {
- BKE_report(reports, RPT_WARNING, "Cannot pose libdata");
- return;
- }
-
- switch (ob->type) {
- case OB_ARMATURE:
- ob->restore_mode = ob->mode;
- ob->mode |= OB_MODE_POSE;
-
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
-
- break;
- default:
- return;
- }
-
- /* XXX: disabled as this would otherwise cause a nasty loop... */
- //ED_object_toggle_modes(C, ob->mode);
-}
-
-void ED_armature_exit_posemode(bContext *C, Base *base)
-{
- if (base) {
- Object *ob = base->object;
-
- ob->restore_mode = ob->mode;
- ob->mode &= ~OB_MODE_POSE;
-
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
- }
-}
-
-/* if a selected or active bone is protected, throw error (oonly if warn == 1) and return 1 */
-/* only_selected == 1: the active bone is allowed to be protected */
-#if 0 /* UNUSED 2.5 */
-static short pose_has_protected_selected(Object *ob, short warn)
-{
- /* check protection */
- if (ob->proxy) {
- bPoseChannel *pchan;
- bArmature *arm = ob->data;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone && (pchan->bone->layer & arm->layer)) {
- if (pchan->bone->layer & arm->layer_protected) {
- if (pchan->bone->flag & BONE_SELECTED)
- break;
- }
- }
- }
- if (pchan) {
- if (warn) error("Cannot change Proxy protected bones");
- return 1;
- }
- }
- return 0;
-}
-#endif
-
-/* only for real IK, not for auto-IK */
-static int pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan, int level)
-{
- bConstraint *con;
- Bone *bone;
-
- /* No need to check if constraint is active (has influence),
- * since all constraints with CONSTRAINT_IK_AUTO are active */
- for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
- bKinematicConstraint *data = con->data;
- if (data->rootbone == 0 || data->rootbone > level) {
- if ((data->flag & CONSTRAINT_IK_AUTO) == 0)
- return 1;
- }
- }
- }
- for (bone = pchan->bone->childbase.first; bone; bone = bone->next) {
- pchan = BKE_pose_channel_find_name(ob->pose, bone->name);
- if (pchan && pose_channel_in_IK_chain(ob, pchan, level + 1))
- return 1;
- }
- return 0;
-}
-
-int ED_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
-{
- return pose_channel_in_IK_chain(ob, pchan, 0);
-}
-
-/* ********************************************** */
-/* Motion Paths */
-
-/* For the object with pose/action: update paths for those that have got them
- * This should selectively update paths that exist...
- *
- * To be called from various tools that do incremental updates
- */
-void ED_pose_recalculate_paths(Scene *scene, Object *ob)
-{
- ListBase targets = {NULL, NULL};
-
- /* set flag to force recalc, then grab the relevant bones to target */
- ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
- animviz_get_object_motionpaths(ob, &targets);
-
- /* recalculate paths, then free */
- animviz_calc_motionpaths(scene, &targets);
- BLI_freelistN(&targets);
-}
-
-
-/* show popup to determine settings */
-static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- /* set default settings from existing/stored settings */
- {
- bAnimVizSettings *avs = &ob->pose->avs;
- PointerRNA avs_ptr;
-
- RNA_int_set(op->ptr, "start_frame", avs->path_sf);
- RNA_int_set(op->ptr, "end_frame", avs->path_ef);
-
- RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
- RNA_enum_set(op->ptr, "bake_location", RNA_enum_get(&avs_ptr, "bake_location"));
- }
-
- /* show popup dialog to allow editing of range... */
- // FIXME: hardcoded dimensions here are just arbitrary
- return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 10 * UI_UNIT_Y);
-}
-
-/* For the object with pose/action: create path curves for selected bones
- * This recalculates the WHOLE path within the pchan->pathsf and pchan->pathef range
- */
-static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- Scene *scene = CTX_data_scene(C);
-
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- /* grab baking settings from operator settings */
- {
- bAnimVizSettings *avs = &ob->pose->avs;
- PointerRNA avs_ptr;
-
- avs->path_sf = RNA_int_get(op->ptr, "start_frame");
- avs->path_ef = RNA_int_get(op->ptr, "end_frame");
-
- RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
- RNA_enum_set(&avs_ptr, "bake_location", RNA_enum_get(op->ptr, "bake_location"));
- }
-
- /* set up path data for bones being calculated */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- /* verify makes sure that the selected bone has a bone with the appropriate settings */
- animviz_verify_motionpaths(op->reports, scene, ob, pchan);
- }
- CTX_DATA_END;
-
- /* calculate the bones that now have motionpaths... */
- /* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(scene, ob);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_paths_calculate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Calculate Bone Paths";
- ot->idname = "POSE_OT_paths_calculate";
- ot->description = "Calculate paths for the selected bones";
-
- /* api callbacks */
- ot->invoke = pose_calculate_paths_invoke;
- ot->exec = pose_calculate_paths_exec;
- ot->poll = ED_operator_posemode_exclusive;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_int(ot->srna, "start_frame", 1, MINAFRAME, MAXFRAME, "Start",
- "First frame to calculate bone paths on", MINFRAME, MAXFRAME / 2.0);
- RNA_def_int(ot->srna, "end_frame", 250, MINAFRAME, MAXFRAME, "End",
- "Last frame to calculate bone paths on", MINFRAME, MAXFRAME / 2.0);
-
- RNA_def_enum(ot->srna, "bake_location", motionpath_bake_location_items, 0,
- "Bake Location",
- "Which point on the bones is used when calculating paths");
-}
-
-/* --------- */
-
-static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- Scene *scene = CTX_data_scene(C);
-
- if (ELEM(NULL, ob, scene))
- return OPERATOR_CANCELLED;
-
- /* calculate the bones that now have motionpaths... */
- /* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(scene, ob);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_paths_update(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Update Bone Paths";
- ot->idname = "POSE_OT_paths_update";
- ot->description = "Recalculate paths for bones that already have them";
-
- /* api callbakcs */
- ot->exec = pose_update_paths_exec;
- ot->poll = ED_operator_posemode_exclusive; /* TODO: this should probably check for active bone and/or existing paths */
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* --------- */
-
-/* for the object with pose/action: clear path curves for selected bones only */
-static void ED_pose_clear_paths(Object *ob)
-{
- bPoseChannel *pchan;
- short skipped = 0;
-
- if (ELEM(NULL, ob, ob->pose))
- return;
-
- /* free the motionpath blocks, but also take note of whether we skipped some... */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->mpath) {
- if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
- animviz_free_motionpath(pchan->mpath);
- pchan->mpath = NULL;
- }
- else
- skipped = 1;
- }
- }
-
- /* if we didn't skip any, we shouldn't have any paths left */
- if (skipped == 0)
- ob->pose->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS;
-}
-
-/* operator callback for this */
-static int pose_clear_paths_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-
- /* only continue if there's an object */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- /* use the backend function for this */
- ED_pose_clear_paths(ob);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_paths_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Bone Paths";
- ot->idname = "POSE_OT_paths_clear";
- ot->description = "Clear path caches for selected bones";
-
- /* api callbacks */
- ot->exec = pose_clear_paths_exec;
- ot->poll = ED_operator_posemode_exclusive;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ******************* Select Constraint Target Operator ************* */
-
-static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
- bConstraint *con;
- int found = 0;
-
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- if (pchan->bone->flag & BONE_SELECTED) {
- for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if ((ct->tar == ob) && (ct->subtarget[0])) {
- bPoseChannel *pchanc = BKE_pose_channel_find_name(ob->pose, ct->subtarget);
- if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
- pchanc->bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
- found = 1;
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
- }
- }
- }
- CTX_DATA_END;
-
- if (!found)
- return OPERATOR_CANCELLED;
-
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_select_constraint_target(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Constraint Target";
- ot->idname = "POSE_OT_select_constraint_target";
- ot->description = "Select bones used as targets for the currently selected bones";
-
- /* api callbacks */
- ot->exec = pose_select_constraint_target_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ******************* select hierarchy operator ************* */
-
-static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = ob->data;
- Bone *curbone, *pabone, *chbone;
- int direction = RNA_enum_get(op->ptr, "direction");
- int add_to_sel = RNA_boolean_get(op->ptr, "extend");
- int found = 0;
-
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- curbone = pchan->bone;
-
- if ((curbone->flag & BONE_UNSELECTABLE) == 0) {
- if (curbone == arm->act_bone) {
- if (direction == BONE_SELECT_PARENT) {
- if (pchan->parent == NULL) continue;
- else pabone = pchan->parent->bone;
-
- if (PBONE_SELECTABLE(arm, pabone)) {
- if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
- pabone->flag |= BONE_SELECTED;
- arm->act_bone = pabone;
-
- found = 1;
- break;
- }
- }
- else { /* direction == BONE_SELECT_CHILD */
- /* the child member is only assigned to connected bones, see [#30340] */
-#if 0
- if (pchan->child == NULL) continue;
- else chbone = pchan->child->bone;
-#else
- /* instead. find _any_ visible child bone, using the first one is a little arbitrary - campbell */
- chbone = pchan->child ? pchan->child->bone : NULL;
- if (chbone == NULL) {
- bPoseChannel *pchan_child;
-
- for (pchan_child = ob->pose->chanbase.first; pchan_child; pchan_child = pchan_child->next) {
- /* possible we have multiple children, some invisible */
- if (PBONE_SELECTABLE(arm, pchan_child->bone)) {
- if (pchan_child->parent == pchan) {
- chbone = pchan_child->bone;
- break;
- }
- }
- }
- }
-
- if (chbone == NULL) continue;
-#endif
-
- if (PBONE_SELECTABLE(arm, chbone)) {
- if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
- chbone->flag |= BONE_SELECTED;
- arm->act_bone = chbone;
-
- found = 1;
- break;
- }
- }
- }
- }
- }
- CTX_DATA_END;
-
- if (found == 0)
- return OPERATOR_CANCELLED;
-
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_select_hierarchy(wmOperatorType *ot)
-{
- static EnumPropertyItem direction_items[] = {
- {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
- {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Select Hierarchy";
- ot->idname = "POSE_OT_select_hierarchy";
- ot->description = "Select immediate parent/children of selected bones";
-
- /* api callbacks */
- ot->exec = pose_select_hierarchy_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- ot->prop = RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
-}
-
-/* ******************* select grouped operator ************* */
-
-static short pose_select_same_group(bContext *C, Object *ob, short extend)
-{
- bArmature *arm = (ob) ? ob->data : NULL;
- bPose *pose = (ob) ? ob->pose : NULL;
- char *group_flags;
- int numGroups = 0;
- short changed = 0, tagged = 0;
-
- /* sanity checks */
- if (ELEM3(NULL, ob, pose, arm))
- return 0;
-
- /* count the number of groups */
- numGroups = BLI_countlist(&pose->agroups);
- if (numGroups == 0)
- return 0;
-
- /* alloc a small array to keep track of the groups to use
- * - each cell stores on/off state for whether group should be used
- * - size is (numGroups + 1), since (index = 0) is used for no-group
- */
- group_flags = MEM_callocN(numGroups + 1, "pose_select_same_group");
-
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- /* keep track of group as group to use later? */
- if (pchan->bone->flag & BONE_SELECTED) {
- group_flags[pchan->agrp_index] = 1;
- tagged = 1;
- }
-
- /* deselect all bones before selecting new ones? */
- if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
- pchan->bone->flag &= ~BONE_SELECTED;
- }
- CTX_DATA_END;
-
- /* small optimization: only loop through bones a second time if there are any groups tagged */
- if (tagged) {
- /* only if group matches (and is not selected or current bone) */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- /* check if the group used by this bone is counted */
- if (group_flags[pchan->agrp_index]) {
- pchan->bone->flag |= BONE_SELECTED;
- changed = 1;
- }
- }
- }
- CTX_DATA_END;
- }
-
- /* free temp info */
- MEM_freeN(group_flags);
-
- return changed;
-}
-
-static short pose_select_same_layer(bContext *C, Object *ob, short extend)
-{
- bPose *pose = (ob) ? ob->pose : NULL;
- bArmature *arm = (ob) ? ob->data : NULL;
- short changed = 0;
- int layers = 0;
-
- if (ELEM3(NULL, ob, pose, arm))
- return 0;
-
- /* figure out what bones are selected */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- /* keep track of layers to use later? */
- if (pchan->bone->flag & BONE_SELECTED)
- layers |= pchan->bone->layer;
-
- /* deselect all bones before selecting new ones? */
- if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
- pchan->bone->flag &= ~BONE_SELECTED;
- }
- CTX_DATA_END;
- if (layers == 0)
- return 0;
-
- /* select bones that are on same layers as layers flag */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- /* if bone is on a suitable layer, and the bone can have its selection changed, select it */
- if ((layers & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- pchan->bone->flag |= BONE_SELECTED;
- changed = 1;
- }
- }
- CTX_DATA_END;
-
- return changed;
-}
-
-static int pose_select_same_keyingset(bContext *C, Object *ob, short extend)
-{
- KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
- KS_Path *ksp;
-
- bArmature *arm = (ob) ? ob->data : NULL;
- bPose *pose = (ob) ? ob->pose : NULL;
- short changed = 0;
-
- /* sanity checks: validate Keying Set and object */
- if ((ks == NULL) || (ANIM_validate_keyingset(C, NULL, ks) != 0))
- return 0;
-
- if (ELEM3(NULL, ob, pose, arm))
- return 0;
-
- /* if not extending selection, deselect all selected first */
- if (extend == 0) {
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
- pchan->bone->flag &= ~BONE_SELECTED;
- }
- CTX_DATA_END;
- }
-
- /* iterate over elements in the Keying Set, setting selection depending on whether
- * that bone is visible or not...
- */
- for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
- /* only items related to this object will be relevant */
- if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) {
- if (strstr(ksp->rna_path, "bones")) {
- char *boneName = BLI_str_quoted_substrN(ksp->rna_path, "bones[");
-
- if (boneName) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
-
- if (pchan) {
- /* select if bone is visible and can be affected */
- if (PBONE_SELECTABLE(arm, pchan->bone)) {
- pchan->bone->flag |= BONE_SELECTED;
- changed = 1;
- }
- }
-
- /* free temp memory */
- MEM_freeN(boneName);
- }
- }
- }
- }
-
- return changed;
-}
-
-static int pose_select_grouped_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
- short extend = RNA_boolean_get(op->ptr, "extend");
- short changed = 0;
-
- /* sanity check */
- if (ob->pose == NULL)
- return OPERATOR_CANCELLED;
-
- /* selection types
- * NOTE: for the order of these, see the enum in POSE_OT_select_grouped()
- */
- switch (RNA_enum_get(op->ptr, "type")) {
- case 1: /* group */
- changed = pose_select_same_group(C, ob, extend);
- break;
- case 2: /* Keying Set */
- changed = pose_select_same_keyingset(C, ob, extend);
- break;
- default: /* layer */
- changed = pose_select_same_layer(C, ob, extend);
- break;
- }
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- /* report done status */
- if (changed)
- return OPERATOR_FINISHED;
- else
- return OPERATOR_CANCELLED;
-}
-
-void POSE_OT_select_grouped(wmOperatorType *ot)
-{
- static EnumPropertyItem prop_select_grouped_types[] = {
- {0, "LAYER", 0, "Layer", "Shared layers"},
- {1, "GROUP", 0, "Group", "Shared group"},
- {2, "KEYINGSET", 0, "Keying Set", "All bones affected by active Keying Set"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Select Grouped";
- ot->description = "Select all visible bones grouped by similar properties";
- ot->idname = "POSE_OT_select_grouped";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = pose_select_grouped_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
- ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
-}
-
-
-/* ********************************************** */
-
-/* context active object, or weightpainted object with armature in posemode */
-static int pose_bone_flip_active_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob_act = CTX_data_active_object(C);
- Object *ob = BKE_object_pose_armature_get(ob_act);
-
- if (ob && (ob->mode & OB_MODE_POSE)) {
- bArmature *arm = ob->data;
-
- if (arm->act_bone) {
- bPoseChannel *pchanf;
- char name[MAXBONENAME];
- flip_side_name(name, arm->act_bone->name, TRUE);
-
- pchanf = BKE_pose_channel_find_name(ob->pose, name);
- if (pchanf && pchanf->bone != arm->act_bone) {
- arm->act_bone->flag &= ~BONE_SELECTED;
- pchanf->bone->flag |= BONE_SELECTED;
-
- arm->act_bone = pchanf->bone;
-
- /* in weightpaint we select the associated vertex group too */
- if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
- ED_vgroup_select_by_name(ob_act, name);
- DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
- }
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
- }
- }
- }
-
- return OPERATOR_CANCELLED;
-}
-
-void POSE_OT_select_flip_active(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Flip Selected Active Bone";
- ot->idname = "POSE_OT_select_flip_active";
- ot->description = "Activate the bone with a flipped name";
-
- /* api callbacks */
- ot->exec = pose_bone_flip_active_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-/* ********************************************** */
-#if 0 /* UNUSED 2.5 */
-static void pose_copy_menu(Scene *scene)
-{
- Object *obedit = scene->obedit; // XXX context
- Object *ob = OBACT;
- bArmature *arm;
- bPoseChannel *pchan, *pchanact;
- short nr = 0;
- int i = 0;
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose)) return;
- if ((ob == obedit) || (ob->mode & OB_MODE_POSE) == 0) return;
-
- pchan = BKE_pose_channel_active(ob);
-
- if (pchan == NULL) return;
- pchanact = pchan;
- arm = ob->data;
-
- /* if proxy-protected bones selected, some things (such as locks + displays) shouldn't be changeable,
- * but for constraints (just add local constraints)
- */
- if (pose_has_protected_selected(ob, 0)) {
- i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
- if (i < 25)
- nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5");
- else
- nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4");
- }
- else {
- i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
- if (i < 25)
- nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5|%l|Transform Locks %x6|IK Limits %x7|Bone Shape %x8");
- else
- nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|%l|Transform Locks %x6|IK Limits %x7|Bone Shape %x8");
- }
-
- if (nr <= 0)
- return;
-
- if (nr != 5) {
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((arm->layer & pchan->bone->layer) &&
- (pchan->bone->flag & BONE_SELECTED) &&
- (pchan != pchanact) )
- {
- switch (nr) {
- case 1: /* Local Location */
- copy_v3_v3(pchan->loc, pchanact->loc);
- break;
- case 2: /* Local Rotation */
- copy_qt_qt(pchan->quat, pchanact->quat);
- copy_v3_v3(pchan->eul, pchanact->eul);
- break;
- case 3: /* Local Size */
- copy_v3_v3(pchan->size, pchanact->size);
- break;
- case 4: /* All Constraints */
- {
- ListBase tmp_constraints = {NULL, NULL};
-
- /* copy constraints to tmpbase and apply 'local' tags before
- * appending to list of constraints for this channel
- */
- BKE_copy_constraints(&tmp_constraints, &pchanact->constraints, TRUE);
- if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
- bConstraint *con;
-
- /* add proxy-local tags */
- for (con = tmp_constraints.first; con; con = con->next)
- con->flag |= CONSTRAINT_PROXY_LOCAL;
- }
- BLI_movelisttolist(&pchan->constraints, &tmp_constraints);
-
- /* update flags (need to add here, not just copy) */
- pchan->constflag |= pchanact->constflag;
-
- if (ob->pose)
- ob->pose->flag |= POSE_RECALC;
- }
- break;
- case 6: /* Transform Locks */
- pchan->protectflag = pchanact->protectflag;
- break;
- case 7: /* IK (DOF) settings */
- {
- pchan->ikflag = pchanact->ikflag;
- copy_v3_v3(pchan->limitmin, pchanact->limitmin);
- copy_v3_v3(pchan->limitmax, pchanact->limitmax);
- copy_v3_v3(pchan->stiffness, pchanact->stiffness);
- pchan->ikstretch = pchanact->ikstretch;
- pchan->ikrotweight = pchanact->ikrotweight;
- pchan->iklinweight = pchanact->iklinweight;
- }
- break;
- case 8: /* Custom Bone Shape */
- pchan->custom = pchanact->custom;
- break;
- case 9: /* Visual Location */
- BKE_armature_loc_pose_to_bone(pchan, pchanact->pose_mat[3], pchan->loc);
- break;
- case 10: /* Visual Rotation */
- {
- float delta_mat[4][4];
-
- BKE_armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat);
-
- if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- float tmp_quat[4];
-
- /* need to convert to quat first (in temp var)... */
- mat4_to_quat(tmp_quat, delta_mat);
- quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, tmp_quat);
- }
- else if (pchan->rotmode == ROT_MODE_QUAT)
- mat4_to_quat(pchan->quat, delta_mat);
- else
- mat4_to_eulO(pchan->eul, pchan->rotmode, delta_mat);
- }
- break;
- case 11: /* Visual Size */
- {
- float delta_mat[4][4], size[4];
-
- BKE_armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat);
- mat4_to_size(size, delta_mat);
- copy_v3_v3(pchan->size, size);
- }
- }
- }
- }
- }
- else { /* constraints, optional (note: max we can have is 24 constraints) */
- bConstraint *con, *con_back;
- int const_toggle[24] = {0}; /* XXX, initialize as 0 to quiet errors */
- ListBase const_copy = {NULL, NULL};
-
- BLI_duplicatelist(&const_copy, &(pchanact->constraints));
-
- /* build the puplist of constraints */
- for (con = pchanact->constraints.first, i = 0; con; con = con->next, i++) {
- const_toggle[i] = 1;
-// add_numbut(i, TOG|INT, con->name, 0, 0, &(const_toggle[i]), "");
- }
-
-// if (!do_clever_numbuts("Select Constraints", i, REDRAW)) {
-// BLI_freelistN(&const_copy);
-// return;
-// }
-
- /* now build a new listbase from the options selected */
- for (i = 0, con = const_copy.first; con; i++) {
- /* if not selected, free/remove it from the list */
- if (!const_toggle[i]) {
- con_back = con->next;
- BLI_freelinkN(&const_copy, con);
- con = con_back;
- }
- else
- con = con->next;
- }
-
- /* Copy the temo listbase to the selected posebones */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((arm->layer & pchan->bone->layer) &&
- (pchan->bone->flag & BONE_SELECTED) &&
- (pchan != pchanact) )
- {
- ListBase tmp_constraints = {NULL, NULL};
-
- /* copy constraints to tmpbase and apply 'local' tags before
- * appending to list of constraints for this channel
- */
- BKE_copy_constraints(&tmp_constraints, &const_copy, TRUE);
- if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
- /* add proxy-local tags */
- for (con = tmp_constraints.first; con; con = con->next)
- con->flag |= CONSTRAINT_PROXY_LOCAL;
- }
- BLI_movelisttolist(&pchan->constraints, &tmp_constraints);
-
- /* update flags (need to add here, not just copy) */
- pchan->constflag |= pchanact->constflag;
- }
- }
- BLI_freelistN(&const_copy);
- BKE_pose_update_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */
-
- if (ob->pose)
- ob->pose->flag |= POSE_RECALC;
- }
-
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations
-
- BIF_undo_push("Copy Pose Attributes");
-
-}
-#endif
-
-/* ******************** copy/paste pose ********************** */
-
-/* Global copy/paste buffer for pose - cleared on start/end session + before every copy operation */
-static bPose *g_posebuf = NULL;
-
-void ED_clipboard_posebuf_free(void)
-{
- if (g_posebuf) {
- bPoseChannel *pchan;
-
- for (pchan = g_posebuf->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->prop) {
- IDP_FreeProperty(pchan->prop);
- MEM_freeN(pchan->prop);
- }
- }
-
- /* was copied without constraints */
- BLI_freelistN(&g_posebuf->chanbase);
- MEM_freeN(g_posebuf);
- }
-
- g_posebuf = NULL;
-}
-
-/* This function is used to indicate that a bone is selected
- * and needs to be included in copy buffer (used to be for inserting keys)
- */
-static void set_pose_keys(Object *ob)
-{
- bArmature *arm = ob->data;
- bPoseChannel *chan;
-
- if (ob->pose) {
- for (chan = ob->pose->chanbase.first; chan; chan = chan->next) {
- Bone *bone = chan->bone;
- if ((bone) && (bone->flag & BONE_SELECTED) && (arm->layer & bone->layer))
- chan->flag |= POSE_KEY;
- else
- chan->flag &= ~POSE_KEY;
- }
- }
-}
-
-/* perform paste pose, for a single bone
- * < ob: object where bone to paste to lives
- * < chan: bone that pose to paste comes from
- * < selOnly: only paste on selected bones
- * < flip: flip on x-axis
- *
- * > returns: whether the bone that we pasted to if we succeeded
- */
-static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, short selOnly, short flip)
-{
- bPoseChannel *pchan;
- char name[MAXBONENAME];
- short paste_ok;
-
- /* get the name - if flipping, we must flip this first */
- if (flip)
- flip_side_name(name, chan->name, 0); /* 0 = don't strip off number extensions */
- else
- BLI_strncpy(name, chan->name, sizeof(name));
-
- /* only copy when:
- * 1) channel exists - poses are not meant to add random channels to anymore
- * 2) if selection-masking is on, channel is selected - only selected bones get pasted on, allowing making both sides symmetrical
- */
- pchan = BKE_pose_channel_find_name(ob->pose, name);
-
- if (selOnly)
- paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED));
- else
- paste_ok = ((pchan != NULL));
-
- /* continue? */
- if (paste_ok) {
- /* only loc rot size
- * - only copies transform info for the pose
- */
- copy_v3_v3(pchan->loc, chan->loc);
- copy_v3_v3(pchan->size, chan->size);
- pchan->flag = chan->flag;
-
- /* check if rotation modes are compatible (i.e. do they need any conversions) */
- if (pchan->rotmode == chan->rotmode) {
- /* copy the type of rotation in use */
- if (pchan->rotmode > 0) {
- copy_v3_v3(pchan->eul, chan->eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- copy_v3_v3(pchan->rotAxis, chan->rotAxis);
- pchan->rotAngle = chan->rotAngle;
- }
- else {
- copy_qt_qt(pchan->quat, chan->quat);
- }
- }
- else if (pchan->rotmode > 0) {
- /* quat/axis-angle to euler */
- if (chan->rotmode == ROT_MODE_AXISANGLE)
- axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
- else
- quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* quat/euler to axis angle */
- if (chan->rotmode > 0)
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
- else
- quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
- }
- else {
- /* euler/axis-angle to quat */
- if (chan->rotmode > 0)
- eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
- else
- axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
- }
-
- /* paste flipped pose? */
- if (flip) {
- pchan->loc[0] *= -1;
-
- /* has to be done as eulers... */
- if (pchan->rotmode > 0) {
- pchan->eul[1] *= -1;
- pchan->eul[2] *= -1;
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- float eul[3];
-
- axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
- eul[1] *= -1;
- eul[2] *= -1;
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
- }
- else {
- float eul[3];
-
- normalize_qt(pchan->quat);
- quat_to_eul(eul, pchan->quat);
- eul[1] *= -1;
- eul[2] *= -1;
- eul_to_quat(pchan->quat, eul);
- }
- }
-
- /* ID properties */
- if (chan->prop) {
- if (pchan->prop) {
- /* if we have existing properties on a bone, just copy over the values of
- * matching properties (i.e. ones which will have some impact) on to the
- * target instead of just blinding replacing all [
- */
- IDP_SyncGroupValues(pchan->prop, chan->prop);
- }
- else {
- /* no existing properties, so assume that we want copies too? */
- pchan->prop = IDP_CopyProperty(chan->prop);
- }
- }
- }
-
- /* return whether paste went ahead */
- return pchan;
-}
-
-/* ---- */
-
-static int pose_copy_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-
- /* sanity checking */
- if (ELEM(NULL, ob, ob->pose)) {
- BKE_report(op->reports, RPT_ERROR, "No pose to copy");
- return OPERATOR_CANCELLED;
- }
-
- /* free existing pose buffer */
- ED_clipboard_posebuf_free();
-
- /* sets chan->flag to POSE_KEY if bone selected, then copy those bones to the buffer */
- set_pose_keys(ob);
- BKE_pose_copy_data(&g_posebuf, ob->pose, 0);
-
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_copy(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Copy Pose";
- ot->idname = "POSE_OT_copy";
- ot->description = "Copies the current pose of the selected bones to copy/paste buffer";
-
- /* api callbacks */
- ot->exec = pose_copy_exec;
- ot->poll = ED_operator_posemode;
-
- /* flag */
- ot->flag = OPTYPE_REGISTER;
-}
-
-/* ---- */
-
-static int pose_paste_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- Scene *scene = CTX_data_scene(C);
- bPoseChannel *chan;
- int flip = RNA_boolean_get(op->ptr, "flipped");
- int selOnly = RNA_boolean_get(op->ptr, "selected_mask");
-
- /* get KeyingSet to use */
- KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOC_ROT_SCALE_ID);
-
- /* sanity checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- if (g_posebuf == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty");
- return OPERATOR_CANCELLED;
- }
-
- /* if selOnly option is enabled, if user hasn't selected any bones,
- * just go back to default behavior to be more in line with other pose tools
- */
- if (selOnly) {
- if (CTX_DATA_COUNT(C, selected_pose_bones) == 0)
- selOnly = 0;
- }
-
- /* Safely merge all of the channels in the buffer pose into any existing pose */
- for (chan = g_posebuf->chanbase.first; chan; chan = chan->next) {
- if (chan->flag & POSE_KEY) {
- /* try to perform paste on this bone */
- bPoseChannel *pchan = pose_bone_do_paste(ob, chan, selOnly, flip);
-
- if (pchan) {
- /* keyframing tagging for successful paste */
- ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
- }
- }
- }
-
- /* Update event for pose and deformation children */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_paste(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Paste Pose";
- ot->idname = "POSE_OT_paste";
- ot->description = "Paste the stored pose on to the current pose";
-
- /* api callbacks */
- ot->exec = pose_paste_exec;
- ot->poll = ED_operator_posemode;
-
- /* flag */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- prop = RNA_def_boolean(ot->srna, "flipped", FALSE, "Flipped on X-Axis", "Paste the stored pose flipped on to current pose");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- RNA_def_boolean(ot->srna, "selected_mask", FALSE, "On Selected Only", "Only paste the stored pose on to selected bones in the current pose");
-}
-
-/* ********************************************** */
-/* Bone Groups */
-
-static int pose_group_add_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_pose_object_from_context(C);
-
- /* only continue if there's an object */
- if (ob == NULL)
- return OPERATOR_CANCELLED;
-
- /* for now, just call the API function for this */
- BKE_pose_add_group(ob);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_group_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Bone Group";
- ot->idname = "POSE_OT_group_add";
- ot->description = "Add a new bone group";
-
- /* api callbacks */
- ot->exec = pose_group_add_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-static int pose_group_remove_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_pose_object_from_context(C);
-
- /* only continue if there's an object */
- if (ob == NULL)
- return OPERATOR_CANCELLED;
-
- /* for now, just call the API function for this */
- BKE_pose_remove_group(ob);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_group_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Bone Group";
- ot->idname = "POSE_OT_group_remove";
- ot->description = "Remove the active bone group";
-
- /* api callbacks */
- ot->exec = pose_group_remove_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ------------ */
-
-/* invoke callback which presents a list of bone-groups for the user to choose from */
-static int pose_groups_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
-{
- Object *ob = ED_pose_object_from_context(C);
- bPose *pose;
-
- uiPopupMenu *pup;
- uiLayout *layout;
- bActionGroup *grp;
- int i;
-
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
- pose = ob->pose;
-
- /* if there's no active group (or active is invalid), create a new menu to find it */
- if (pose->active_group <= 0) {
- /* create a new menu, and start populating it with group names */
- pup = uiPupMenuBegin(C, op->type->name, ICON_NONE);
- layout = uiPupMenuLayout(pup);
-
- /* special entry - allow to create new group, then use that
- * (not to be used for removing though)
- */
- if (strstr(op->idname, "assign")) {
- uiItemIntO(layout, "New Group", ICON_NONE, op->idname, "type", 0);
- uiItemS(layout);
- }
-
- /* add entries for each group */
- for (grp = pose->agroups.first, i = 1; grp; grp = grp->next, i++)
- uiItemIntO(layout, grp->name, ICON_NONE, op->idname, "type", i);
-
- /* finish building the menu, and process it (should result in calling self again) */
- uiPupMenuEnd(C, pup);
-
- return OPERATOR_CANCELLED;
- }
- else {
- /* just use the active group index, and call the exec callback for the calling operator */
- RNA_int_set(op->ptr, "type", pose->active_group);
- return op->type->exec(C, op);
- }
-}
-
-/* Assign selected pchans to the bone group that the user selects */
-static int pose_group_assign_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_pose_object_from_context(C);
- bPose *pose;
- short done = FALSE;
-
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- pose = ob->pose;
-
- /* set the active group number to the one from operator props
- * - if 0 after this, make a new group...
- */
- pose->active_group = RNA_int_get(op->ptr, "type");
- if (pose->active_group == 0)
- BKE_pose_add_group(ob);
-
- /* add selected bones to group then */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- pchan->agrp_index = pose->active_group;
- done = TRUE;
- }
- CTX_DATA_END;
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- /* report done status */
- if (done)
- return OPERATOR_FINISHED;
- else
- return OPERATOR_CANCELLED;
-}
-
-void POSE_OT_group_assign(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Selected to Bone Group";
- ot->idname = "POSE_OT_group_assign";
- ot->description = "Add selected bones to the chosen bone group";
-
- /* api callbacks */
- ot->invoke = pose_groups_menu_invoke;
- ot->exec = pose_group_assign_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_int(ot->srna, "type", 0, 0, INT_MAX, "Bone Group Index", "", 0, 10);
-}
-
-
-static int pose_group_unassign_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_pose_object_from_context(C);
- short done = FALSE;
-
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- /* find selected bones to remove from all bone groups */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- if (pchan->agrp_index) {
- pchan->agrp_index = 0;
- done = TRUE;
- }
- }
- CTX_DATA_END;
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- /* report done status */
- if (done)
- return OPERATOR_FINISHED;
- else
- return OPERATOR_CANCELLED;
-}
-
-void POSE_OT_group_unassign(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Selected from Bone Groups";
- ot->idname = "POSE_OT_group_unassign";
- ot->description = "Remove selected bones from all bone groups";
-
- /* api callbacks */
- ot->exec = pose_group_unassign_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int group_move_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_pose_object_from_context(C);
- bPose *pose = (ob) ? ob->pose : NULL;
- bPoseChannel *pchan;
- bActionGroup *grp;
- int dir = RNA_enum_get(op->ptr, "direction");
- int grpIndexA, grpIndexB;
-
- if (ELEM(NULL, ob, pose))
- return OPERATOR_CANCELLED;
- if (pose->active_group <= 0)
- return OPERATOR_CANCELLED;
-
- /* get group to move */
- grp = BLI_findlink(&pose->agroups, pose->active_group - 1);
- if (grp == NULL)
- return OPERATOR_CANCELLED;
-
- /* move bone group */
- grpIndexA = pose->active_group;
- if (dir == 1) { /* up */
- void *prev = grp->prev;
-
- if (prev == NULL)
- return OPERATOR_FINISHED;
-
- BLI_remlink(&pose->agroups, grp);
- BLI_insertlinkbefore(&pose->agroups, prev, grp);
-
- grpIndexB = grpIndexA - 1;
- pose->active_group--;
- }
- else { /* down */
- void *next = grp->next;
-
- if (next == NULL)
- return OPERATOR_FINISHED;
-
- BLI_remlink(&pose->agroups, grp);
- BLI_insertlinkafter(&pose->agroups, next, grp);
-
- grpIndexB = grpIndexA + 1;
- pose->active_group++;
- }
-
- /* fix changed bone group indices in bones (swap grpIndexA with grpIndexB) */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->agrp_index == grpIndexB)
- pchan->agrp_index = grpIndexA;
- else if (pchan->agrp_index == grpIndexA)
- pchan->agrp_index = grpIndexB;
- }
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_group_move(wmOperatorType *ot)
-{
- static EnumPropertyItem group_slot_move[] = {
- {1, "UP", 0, "Up", ""},
- {-1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Move Bone Group";
- ot->idname = "POSE_OT_group_move";
- ot->description = "Change position of active Bone Group in list of Bone Groups";
-
- /* api callbacks */
- ot->exec = group_move_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(ot->srna, "direction", group_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
-}
-
-/* bone group sort element */
-typedef struct tSortActionGroup {
- bActionGroup *agrp;
- int index;
-} tSortActionGroup;
-
-/* compare bone groups by name */
-static int compare_agroup(const void *sgrp_a_ptr, const void *sgrp_b_ptr)
-{
- tSortActionGroup *sgrp_a = (tSortActionGroup *)sgrp_a_ptr;
- tSortActionGroup *sgrp_b = (tSortActionGroup *)sgrp_b_ptr;
-
- return strcmp(sgrp_a->agrp->name, sgrp_b->agrp->name);
-}
-
-static int group_sort_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_pose_object_from_context(C);
- bPose *pose = (ob) ? ob->pose : NULL;
- bPoseChannel *pchan;
- tSortActionGroup *agrp_array;
- bActionGroup *agrp;
- int agrp_count;
- int i;
-
- if (ELEM(NULL, ob, pose))
- return OPERATOR_CANCELLED;
- if (pose->active_group <= 0)
- return OPERATOR_CANCELLED;
-
- /* create temporary array with bone groups and indices */
- agrp_count = BLI_countlist(&pose->agroups);
- agrp_array = MEM_mallocN(sizeof(tSortActionGroup) * agrp_count, "sort bone groups");
- for (agrp = pose->agroups.first, i = 0; agrp; agrp = agrp->next, i++) {
- BLI_assert(i < agrp_count);
- agrp_array[i].agrp = agrp;
- agrp_array[i].index = i + 1;
- }
-
- /* sort bone groups by name */
- qsort(agrp_array, agrp_count, sizeof(tSortActionGroup), compare_agroup);
-
- /* create sorted bone group list from sorted array */
- pose->agroups.first = pose->agroups.last = NULL;
- for (i = 0; i < agrp_count; i++) {
- BLI_addtail(&pose->agroups, agrp_array[i].agrp);
- }
-
- /* fix changed bone group indizes in bones */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (i = 0; i < agrp_count; i++) {
- if (pchan->agrp_index == agrp_array[i].index) {
- pchan->agrp_index = i + 1;
- break;
- }
- }
- }
-
- /* free temp resources */
- MEM_freeN(agrp_array);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_group_sort(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Sort Bone Groups";
- ot->idname = "POSE_OT_group_sort";
- ot->description = "Sort Bone Groups by their names in ascending order";
-
- /* api callbacks */
- ot->exec = group_sort_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static void pose_group_select(bContext *C, Object *ob, int select)
-{
- bPose *pose = ob->pose;
-
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- if (select) {
- if (pchan->agrp_index == pose->active_group)
- pchan->bone->flag |= BONE_SELECTED;
- }
- else {
- if (pchan->agrp_index == pose->active_group)
- pchan->bone->flag &= ~BONE_SELECTED;
- }
- }
- }
- CTX_DATA_END;
-}
-
-static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_pose_object_from_context(C);
-
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- pose_group_select(C, ob, 1);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_group_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Bones of Bone Group";
- ot->idname = "POSE_OT_group_select";
- ot->description = "Select bones in active Bone Group";
-
- /* api callbacks */
- ot->exec = pose_group_select_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_pose_object_from_context(C);
-
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- pose_group_select(C, ob, 0);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_group_deselect(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Deselect Bone Group";
- ot->idname = "POSE_OT_group_deselect";
- ot->description = "Deselect bones of active Bone Group";
-
- /* api callbacks */
- ot->exec = pose_group_deselect_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ********************************************** */
-
-static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm;
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
- arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- char newname[MAXBONENAME];
- flip_side_name(newname, pchan->name, TRUE);
- ED_armature_bone_rename(arm, pchan->name, newname);
- }
- CTX_DATA_END;
-
- /* since we renamed stuff... */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_flip_names(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Flip Names";
- ot->idname = "POSE_OT_flip_names";
- ot->description = "Flips (and corrects) the axis suffixes of the the names of selected bones";
-
- /* api callbacks */
- ot->exec = pose_flip_names_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ------------------ */
-
-static int pose_autoside_names_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm;
- char newname[MAXBONENAME];
- short axis = RNA_enum_get(op->ptr, "axis");
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
- arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- BLI_strncpy(newname, pchan->name, sizeof(newname));
- if (bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis]))
- ED_armature_bone_rename(arm, pchan->name, newname);
- }
- CTX_DATA_END;
-
- /* since we renamed stuff... */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_autoside_names(wmOperatorType *ot)
-{
- static EnumPropertyItem axis_items[] = {
- {0, "XAXIS", 0, "X-Axis", "Left/Right"},
- {1, "YAXIS", 0, "Y-Axis", "Front/Back"},
- {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "AutoName by Axis";
- ot->idname = "POSE_OT_autoside_names";
- ot->description = "Automatically renames the selected bones according to which side of the target axis they fall on";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = pose_autoside_names_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* settings */
- ot->prop = RNA_def_enum(ot->srna, "axis", axis_items, 0, "Axis", "Axis tag names with");
-}
-
-/* ********************************************** */
-
-static int pose_bone_rotmode_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_active_object(C);
- int mode = RNA_enum_get(op->ptr, "type");
-
- /* set rotation mode of selected bones */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- pchan->rotmode = mode;
- }
- CTX_DATA_END;
-
- /* notifiers and updates */
- DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_rotation_mode_set(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Rotation Mode";
- ot->idname = "POSE_OT_rotation_mode_set";
- ot->description = "Set the rotation representation used by selected bones";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = pose_bone_rotmode_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", posebone_rotmode_items, 0, "Rotation Mode", "");
-}
-
-/* ********************************************** */
-
-/* Show all armature layers */
-static int pose_armature_layers_showall_poll(bContext *C)
-{
- /* this single operator can be used in posemode OR editmode for armatures */
- return ED_operator_posemode(C) || ED_operator_editarmature(C);
-}
-
-static int pose_armature_layers_showall_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (ob) ? ob->data : NULL;
- PointerRNA ptr;
- int maxLayers = (RNA_boolean_get(op->ptr, "all")) ? 32 : 16;
- int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
- int i;
-
- /* sanity checking */
- if (arm == NULL)
- return OPERATOR_CANCELLED;
-
- /* use RNA to set the layers
- * although it would be faster to just set directly using bitflags, we still
- * need to setup a RNA pointer so that we get the "update" callbacks for free...
- */
- RNA_id_pointer_create(&arm->id, &ptr);
-
- for (i = 0; i < maxLayers; i++)
- layers[i] = 1;
-
- RNA_boolean_set_array(&ptr, "layers", layers);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- /* done */
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_layers_show_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Show All Layers";
- ot->idname = "ARMATURE_OT_layers_show_all";
- ot->description = "Make all armature layers visible";
-
- /* callbacks */
- ot->exec = pose_armature_layers_showall_exec;
- ot->poll = pose_armature_layers_showall_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All Layers", "Enable all layers or just the first 16 (top row)");
-}
-
-/* ------------------- */
-
-/* Present a popup to get the layers that should be used */
-static int pose_armature_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (ob) ? ob->data : NULL;
- PointerRNA ptr;
- int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
-
- /* sanity checking */
- if (arm == NULL)
- return OPERATOR_CANCELLED;
-
- /* get RNA pointer to armature data to use that to retrieve the layers as ints to init the operator */
- RNA_id_pointer_create((ID *)arm, &ptr);
- RNA_boolean_get_array(&ptr, "layers", layers);
- RNA_boolean_set_array(op->ptr, "layers", layers);
-
- /* part to sync with other similar operators... */
- return WM_operator_props_popup(C, op, evt);
-}
-
-/* Set the visible layers for the active armature (edit and pose modes) */
-static int pose_armature_layers_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- PointerRNA ptr;
- int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
-
- if (ELEM(NULL, ob, ob->data)) {
- return OPERATOR_CANCELLED;
- }
-
- /* get the values set in the operator properties */
- RNA_boolean_get_array(op->ptr, "layers", layers);
-
- /* get pointer for armature, and write data there... */
- RNA_id_pointer_create((ID *)ob->data, &ptr);
- RNA_boolean_set_array(&ptr, "layers", layers);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-
-void POSE_OT_armature_layers(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Change Armature Layers";
- ot->idname = "POSE_OT_armature_layers";
- ot->description = "Change the visible armature layers";
-
- /* callbacks */
- ot->invoke = pose_armature_layers_invoke;
- ot->exec = pose_armature_layers_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
-}
-
-void ARMATURE_OT_armature_layers(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Change Armature Layers";
- ot->idname = "ARMATURE_OT_armature_layers";
- ot->description = "Change the visible armature layers";
-
- /* callbacks */
- ot->invoke = pose_armature_layers_invoke;
- ot->exec = pose_armature_layers_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
-}
-
-/* ------------------- */
-
-/* Present a popup to get the layers that should be used */
-static int pose_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
-{
- int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
-
- /* get layers that are active already */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- short bit;
-
- /* loop over the bits for this pchan's layers, adding layers where they're needed */
- for (bit = 0; bit < 32; bit++) {
- if (pchan->bone->layer & (1 << bit))
- layers[bit] = 1;
- }
- }
- CTX_DATA_END;
-
- /* copy layers to operator */
- RNA_boolean_set_array(op->ptr, "layers", layers);
-
- /* part to sync with other similar operators... */
- return WM_operator_props_popup(C, op, evt);
-}
-
-/* Set the visible layers for the active armature (edit and pose modes) */
-static int pose_bone_layers_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- PointerRNA ptr;
- int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
-
- if (ob == NULL || ob->data == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- /* get the values set in the operator properties */
- RNA_boolean_get_array(op->ptr, "layers", layers);
-
- /* set layers of pchans based on the values set in the operator props */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- /* get pointer for pchan, and write flags this way */
- RNA_pointer_create((ID *)ob->data, &RNA_Bone, pchan->bone, &ptr);
- RNA_boolean_set_array(&ptr, "layers", layers);
- }
- CTX_DATA_END;
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_bone_layers(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Change Bone Layers";
- ot->idname = "POSE_OT_bone_layers";
- ot->description = "Change the layers that the selected bones belong to";
-
- /* callbacks */
- ot->invoke = pose_bone_layers_invoke;
- ot->exec = pose_bone_layers_exec;
- ot->poll = ED_operator_posemode_exclusive;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
-}
-
-/* ------------------- */
-
-/* Present a popup to get the layers that should be used */
-static int armature_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
-{
- int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
-
- /* get layers that are active already */
- CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones)
- {
- short bit;
-
- /* loop over the bits for this pchan's layers, adding layers where they're needed */
- for (bit = 0; bit < 32; bit++) {
- if (ebone->layer & (1 << bit))
- layers[bit] = 1;
- }
- }
- CTX_DATA_END;
-
- /* copy layers to operator */
- RNA_boolean_set_array(op->ptr, "layers", layers);
-
- /* part to sync with other similar operators... */
- return WM_operator_props_popup(C, op, evt);
-}
-
-/* Set the visible layers for the active armature (edit and pose modes) */
-static int armature_bone_layers_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (ob) ? ob->data : NULL;
- PointerRNA ptr;
- int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
-
- /* get the values set in the operator properties */
- RNA_boolean_get_array(op->ptr, "layers", layers);
-
- /* set layers of pchans based on the values set in the operator props */
- CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones)
- {
- /* get pointer for pchan, and write flags this way */
- RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr);
- RNA_boolean_set_array(&ptr, "layers", layers);
- }
- CTX_DATA_END;
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_bone_layers(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Change Bone Layers";
- ot->idname = "ARMATURE_OT_bone_layers";
- ot->description = "Change the layers that the selected bones belong to";
-
- /* callbacks */
- ot->invoke = armature_bone_layers_invoke;
- ot->exec = armature_bone_layers_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
-}
-
-/* ********************************************** */
-/* Flip Quats */
-
-static int pose_flip_quats_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
-
- /* loop through all selected pchans, flipping and keying (as needed) */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- /* only if bone is using quaternion rotation */
- if (pchan->rotmode == ROT_MODE_QUAT) {
- /* quaternions have 720 degree range */
- negate_v4(pchan->quat);
-
- ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
- }
- }
- CTX_DATA_END;
-
- /* notifiers and updates */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_quaternions_flip(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Flip Quats";
- ot->idname = "POSE_OT_quaternions_flip";
- ot->description = "Flip quaternion values to achieve desired rotations, while maintaining the same orientations";
-
- /* callbacks */
- ot->exec = pose_flip_quats_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ********************************************** */
-/* Clear User Transforms */
-
-static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- float cframe = (float)CFRA;
- const short only_select = RNA_boolean_get(op->ptr, "only_selected");
-
- if ((ob->adt) && (ob->adt->action)) {
- /* XXX: this is just like this to avoid contaminating anything else;
- * just pose values should change, so this should be fine
- */
- bPose *dummyPose = NULL;
- Object workob = {{0}};
- bPoseChannel *pchan;
-
- /* execute animation step for current frame using a dummy copy of the pose */
- BKE_pose_copy_data(&dummyPose, ob->pose, 0);
-
- BLI_strncpy(workob.id.name, "OB<ClearTfmWorkOb>", sizeof(workob.id.name));
- workob.type = OB_ARMATURE;
- workob.data = ob->data;
- workob.adt = ob->adt;
- workob.pose = dummyPose;
-
- BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM);
-
- /* copy back values, but on selected bones only */
- for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
- pose_bone_do_paste(ob, pchan, only_select, 0);
- }
-
- /* free temp data - free manually as was copied without constraints */
- for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->prop) {
- IDP_FreeProperty(pchan->prop);
- MEM_freeN(pchan->prop);
- }
- }
-
- /* was copied without constraints */
- BLI_freelistN(&dummyPose->chanbase);
- MEM_freeN(dummyPose);
- }
- else {
- /* no animation, so just reset whole pose to rest pose
- * (cannot just restore for selected though)
- */
- BKE_pose_rest(ob->pose);
- }
-
- /* notifiers and updates */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_user_transforms_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear User Transforms";
- ot->idname = "POSE_OT_user_transforms_clear";
- ot->description = "Reset pose on selected bones to keyframed state";
-
- /* callbacks */
- ot->exec = pose_clear_user_transforms_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "only_selected", TRUE, "Only Selected", "Only visible/selected bones");
-}
-
diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c
index 1b5c550df11..454b0f0bceb 100644
--- a/source/blender/editors/armature/reeb.c
+++ b/source/blender/editors/armature/reeb.c
@@ -24,29 +24,14 @@
* \ingroup edarmature
*/
-#include <math.h>
-#include <string.h> /* for memcpy */
-#include <stdio.h>
-#include <stdlib.h> /* for qsort */
-#include <float.h>
-
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-
#include "MEM_guardedalloc.h"
#include "BKE_context.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
#include "BLI_edgehash.h"
#include "BLI_ghash.h"
-#include "BLI_heap.h"
-
-#include "BKE_mesh.h"
-
-#include "ONL_opennl.h"
#include "reeb.h"
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index 25df17d232a..c38ded49830 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -20,6 +20,7 @@
set(INC
../include
+ ../../blenfont
../../blenkernel
../../blenlib
../../blenloader
@@ -42,4 +43,8 @@ set(SRC
curve_intern.h
)
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
blender_add_lib(bf_editor_curve "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/curve/SConscript b/source/blender/editors/curve/SConscript
index abefd3c6dd6..21c6a3732fa 100644
--- a/source/blender/editors/curve/SConscript
+++ b/source/blender/editors/curve/SConscript
@@ -29,9 +29,14 @@ Import ('env')
sources = env.Glob('*.c')
-incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
+defs = []
+
+incs = '../include ../../blenfont ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../bmesh ../../gpu ../../blenloader'
incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern'
-env.BlenderLib ( 'bf_editors_curve', sources, Split(incs), [], libtype=['core'], priority=[45] )
+if env['WITH_BF_INTERNATIONAL']:
+ defs.append('WITH_INTERNATIONAL')
+
+env.BlenderLib ( 'bf_editors_curve', sources, Split(incs), defs, libtype=['core'], priority=[45] )
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index b5aa55dbda9..d01e5c5d9bf 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -53,6 +53,8 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
@@ -4925,7 +4927,7 @@ static int toggle_cyclic_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(eve
for (nu = editnurb->first; nu; nu = nu->next) {
if (nu->pntsu > 1 || nu->pntsv > 1) {
if (nu->type == CU_NURBS) {
- pup = uiPupMenuBegin(C, "Direction", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Direction"), ICON_NONE);
layout = uiPupMenuLayout(pup);
uiItemsEnumO(layout, op->type->idname, "direction");
uiPupMenuEnd(C, pup);
@@ -6051,14 +6053,14 @@ static int delete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
uiLayout *layout;
if (obedit->type == OB_SURF) {
- pup = uiPupMenuBegin(C, "Delete", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Delete"), ICON_NONE);
layout = uiPupMenuLayout(pup);
uiItemEnumO_ptr(layout, op->type, NULL, 0, "type", 0);
uiItemEnumO_ptr(layout, op->type, NULL, 0, "type", 2);
uiPupMenuEnd(C, pup);
}
else {
- pup = uiPupMenuBegin(C, "Delete", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Delete"), ICON_NONE);
layout = uiPupMenuLayout(pup);
uiItemsEnumO(layout, op->type->idname, "type");
uiPupMenuEnd(C, pup);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 8cd2bd861bc..46815450bf2 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -931,7 +931,8 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* check that point segment of the boundbox of the eraser stroke */
if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
- ((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1))) {
+ ((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1)))
+ {
/* check if point segment of stroke had anything to do with
* eraser region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 4db79df033e..30ac360cab6 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -137,7 +137,7 @@ struct EditBone *ED_armature_edit_bone_add(struct bArmature *arm, const char *na
void ED_armature_edit_bone_remove(struct bArmature *arm, EditBone *exBone);
void transform_armature_mirror_update(struct Object *obedit);
-void docenter_armature(struct Scene *scene, struct Object *ob, float cursor[3], int centermode, int around);
+void ED_armature_origin_set(struct Scene *scene, struct Object *ob, float cursor[3], int centermode, int around);
void ED_armature_apply_transform(struct Object *ob, float mat[4][4]);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 46f4515e0ca..d89d66dd62c 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -105,9 +105,10 @@ void ED_view3d_depth_tag_update(struct RegionView3D *rv3d);
typedef enum {
V3D_PROJ_RET_OK = 0,
V3D_PROJ_RET_CLIP_NEAR = 1, /* can't avoid this when in perspective mode, (can't avoid) */
- V3D_PROJ_RET_CLIP_BB = 2, /* bounding box clip - RV3D_CLIPPING */
- V3D_PROJ_RET_CLIP_WIN = 3, /* outside window bounds */
- V3D_PROJ_RET_OVERFLOW = 4 /* outside range (mainly for short), (can't avoid) */
+ V3D_PROJ_RET_CLIP_ZERO = 2, /* so close to zero we can't apply a perspective matrix usefully */
+ V3D_PROJ_RET_CLIP_BB = 3, /* bounding box clip - RV3D_CLIPPING */
+ V3D_PROJ_RET_CLIP_WIN = 4, /* outside window bounds */
+ V3D_PROJ_RET_OVERFLOW = 5 /* outside range (mainly for short), (can't avoid) */
} eV3DProjStatus;
/* some clipping tests are optional */
@@ -116,10 +117,13 @@ typedef enum {
V3D_PROJ_TEST_CLIP_BB = (1 << 0),
V3D_PROJ_TEST_CLIP_WIN = (1 << 1),
V3D_PROJ_TEST_CLIP_NEAR = (1 << 2),
+ V3D_PROJ_TEST_CLIP_ZERO = (1 << 3)
} eV3DProjTest;
-#define V3D_PROJ_TEST_CLIP_DEFAULT (V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR)
-#define V3D_PROJ_TEST_ALL (V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR)
+#define V3D_PROJ_TEST_CLIP_DEFAULT \
+ (V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR)
+#define V3D_PROJ_TEST_ALL \
+ (V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_ZERO)
/* view3d_iterators.c */
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 78689c078c6..3c8a9a87fbe 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -183,6 +183,7 @@ typedef struct uiLayout uiLayout;
/* scale fixed button widths by this to account for DPI */
#define UI_DPI_FAC ((U.pixelsize * (float)U.dpi) / 72.0f)
+#define UI_DPI_WINDOW_FAC (((float)U.dpi) / 72.0f)
/* 16 to copy ICON_DEFAULT_HEIGHT */
#define UI_DPI_ICON_SIZE ((float)16 * UI_DPI_FAC)
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 37249896e34..2c17a629ed4 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1097,34 +1097,29 @@ void uiDrawBlock(const bContext *C, uiBlock *block)
/* ************* EVENTS ************* */
-static void ui_is_but_sel(uiBut *but, double *value)
+int ui_is_but_push_ex(uiBut *but, double *value)
{
- short is_push = 0; /* (0 == UNSELECT), (1 == SELECT), (2 == DO-NOHING) */
- short is_true = TRUE;
-
- if (ELEM3(but->type, TOGN, ICONTOGN, OPTIONN)) {
- is_true = FALSE;
- }
+ int is_push = false; /* (0 == UNSELECT), (1 == SELECT), (-1 == DO-NOHING) */
if (but->bit) {
+ const bool state = ELEM3(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true;
int lvalue;
UI_GET_BUT_VALUE_INIT(but, *value);
lvalue = (int)*value;
if (UI_BITBUT_TEST(lvalue, (but->bitnr))) {
- is_push = is_true;
+ is_push = state;
}
else {
- is_push = !is_true;
+ is_push = !state;
}
}
else {
switch (but->type) {
case BUT:
- is_push = 2;
- break;
case HOTKEYEVT:
case KEYEVT:
- is_push = 2;
+ case COLOR:
+ is_push = -1;
break;
case TOGBUT:
case TOG:
@@ -1134,42 +1129,48 @@ static void ui_is_but_sel(uiBut *but, double *value)
case ICONTOG:
case OPTION:
UI_GET_BUT_VALUE_INIT(but, *value);
- if (*value != (double)but->hardmin) is_push = 1;
+ if (*value != (double)but->hardmin) is_push = true;
break;
case ICONTOGN:
case TOGN:
case OPTIONN:
UI_GET_BUT_VALUE_INIT(but, *value);
- if (*value == 0.0) is_push = 1;
+ if (*value == 0.0) is_push = true;
break;
case ROW:
case LISTROW:
UI_GET_BUT_VALUE_INIT(but, *value);
/* support for rna enum buts */
if (but->rnaprop && (RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG)) {
- if ((int)*value & (int)but->hardmax) is_push = 1;
+ if ((int)*value & (int)but->hardmax) is_push = true;
}
else {
- if (*value == (double)but->hardmax) is_push = 1;
+ if (*value == (double)but->hardmax) is_push = true;
}
break;
- case COLOR:
- is_push = 2;
- break;
default:
- is_push = 2;
+ is_push = -1;
break;
}
}
-
- if (is_push == 2) {
- /* pass */
- }
- else if (is_push == 1) {
- but->flag |= UI_SELECT;
- }
- else {
- but->flag &= ~UI_SELECT;
+
+ return is_push;
+}
+int ui_is_but_push(uiBut *but)
+{
+ double value = UI_BUT_VALUE_UNSET;
+ return ui_is_but_push_ex(but, &value);
+}
+
+static void ui_check_but_select(uiBut *but, double *value)
+{
+ switch (ui_is_but_push_ex(but, value)) {
+ case true:
+ but->flag |= UI_SELECT;
+ break;
+ case false:
+ but->flag &= ~UI_SELECT;
+ break;
}
}
@@ -1620,8 +1621,7 @@ void ui_set_but_val(uiBut *but, double value)
value = *((float *)but->poin) = (float)value;
}
- /* update select flag */
- ui_is_but_sel(but, &value);
+ ui_check_but_select(but, &value);
}
int ui_get_but_string_max_length(uiBut *but)
@@ -2256,7 +2256,7 @@ void ui_check_but(uiBut *but)
double value = UI_BUT_VALUE_UNSET;
// float okwidth; // UNUSED
- ui_is_but_sel(but, &value);
+ ui_check_but_select(but, &value);
/* only update soft range while not editing */
if (but->rnaprop && !(but->editval || but->editstr || but->editvec)) {
@@ -3929,15 +3929,20 @@ void uiButGetStrInfo(bContext *C, uiBut *but, ...)
}
}
else if (type == BUT_GET_RNA_LABEL_CONTEXT) {
+ const char *_tmp = NULL;
if (but->rnaprop)
- tmp = BLI_strdup(RNA_property_translation_context(but->rnaprop));
+ _tmp = RNA_property_translation_context(but->rnaprop);
else if (but->optype)
- tmp = BLI_strdup(RNA_struct_translation_context(but->optype->srna));
+ _tmp = RNA_struct_translation_context(but->optype->srna);
else if (ELEM(but->type, MENU, PULLDOWN)) {
MenuType *mt = uiButGetMenuType(but);
if (mt)
- tmp = BLI_strdup(RNA_struct_translation_context(mt->ext.srna));
+ _tmp = RNA_struct_translation_context(mt->ext.srna);
+ }
+ if (!_tmp) { /* _tmp == BLF_I18NCONTEXT_DEFAULT */
+ _tmp = BLF_I18NCONTEXT_DEFAULT_BPY;
}
+ tmp = BLI_strdup(_tmp);
}
else if (ELEM3(type, BUT_GET_RNAENUM_IDENTIFIER, BUT_GET_RNAENUM_LABEL, BUT_GET_RNAENUM_TIP)) {
PointerRNA *ptr = NULL;
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 5cff61f4239..e0d6c293be5 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -81,6 +81,8 @@
/* place the mouse at the scaled down location when un-grabbing */
#define USE_CONT_MOUSE_CORRECT
+/* support dragging toggle buttons */
+#define USE_DRAG_TOGGLE
/* proto */
static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to);
@@ -151,6 +153,7 @@ typedef struct uiHandleButtonData {
int maxlen, selextend, selstartx;
/* number editing / dragging */
+ /* coords are Window/uiBlock relative (depends on the button) */
int draglastx, draglasty;
int dragstartx, dragstarty;
int dragchange, draglock, dragsel;
@@ -406,9 +409,9 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
}
}
-static void ui_apply_autokey_undo(bContext *C, uiBut *but)
+/* typically call ui_apply_undo(), ui_apply_autokey() */
+static void ui_apply_undo(uiBut *but)
{
- Scene *scene = CTX_data_scene(C);
uiAfterFunc *after;
if (but->flag & UI_BUT_UNDO) {
@@ -430,6 +433,11 @@ static void ui_apply_autokey_undo(bContext *C, uiBut *but)
BLI_strncpy(after->undostr, str, sizeof(after->undostr));
BLI_addtail(&UIAfterFuncs, after);
}
+}
+
+static void ui_apply_autokey(bContext *C, uiBut *but)
+{
+ Scene *scene = CTX_data_scene(C);
/* try autokey */
ui_but_anim_autokey(C, but, scene, scene->r.cfra);
@@ -732,6 +740,153 @@ static void ui_apply_but_CHARTAB(bContext *C, uiBut *but, uiHandleButtonData *da
/* ****************** drag drop code *********************** */
+#ifdef USE_DRAG_TOGGLE
+
+typedef struct uiDragToggleHandle {
+ /* init */
+ bool is_set;
+ float but_cent_start[2];
+ eButType but_type_start;
+
+ bool xy_lock[2];
+ int xy_last[2];
+} uiDragToggleHandle;
+
+static bool ui_drag_toggle_set_xy_xy(bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
+ const int xy_src[2], const int xy_dst[2])
+{
+ bool change = false;
+ uiBlock *block;
+
+ for (block = ar->uiblocks.first; block; block = block->next) {
+ uiBut *but;
+
+ float xy_a_block[2] = {UNPACK2(xy_src)};
+ float xy_b_block[2] = {UNPACK2(xy_dst)};
+
+ ui_window_to_block_fl(ar, block, &xy_a_block[0], &xy_a_block[1]);
+ ui_window_to_block_fl(ar, block, &xy_b_block[0], &xy_b_block[1]);
+
+ for (but = block->buttons.first; but; but = but->next) {
+ if (ui_is_but_interactive(but)) {
+ if (BLI_rctf_isect_segment(&but->rect, xy_a_block, xy_b_block)) {
+
+ /* execute the button */
+ if (ui_is_but_bool(but) && but->type == but_type_start) {
+ /* is it pressed? */
+ bool is_set_but = ui_is_but_push(but);
+ BLI_assert(ui_is_but_bool(but) == true);
+ if (is_set_but != is_set) {
+ uiButExecute(C, but);
+ change = true;
+ }
+ }
+ /* done */
+
+ }
+ }
+ }
+ }
+
+ return change;
+}
+
+static void ui_drag_toggle_set(bContext *C, uiDragToggleHandle *drag_info, const int xy_input[2])
+{
+ ARegion *ar = CTX_wm_region(C);
+ bool do_draw = false;
+ int xy[2];
+
+ /**
+ * Initialize Locking:
+ *
+ * Check if we need to initialize the lock axis by finding if the first
+ * button we mouse over is X or Y aligned, then lock the mouse to that axis after.
+ */
+ if (drag_info->xy_lock[0] == false && drag_info->xy_lock[1] == false) {
+ ARegion *ar = CTX_wm_region(C);
+
+ /* first store the buttons original coords */
+ uiBut *but = ui_but_find_mouse_over(ar, xy_input[0], xy_input[1]);
+ if (but) {
+ const float but_cent_new[2] = {BLI_rctf_cent_x(&but->rect),
+ BLI_rctf_cent_y(&but->rect)};
+
+ /* check if this is a different button, chances are high the button wont move about :) */
+ if (len_manhattan_v2v2(drag_info->but_cent_start, but_cent_new) > 1.0f) {
+ if (fabsf(drag_info->but_cent_start[0] - but_cent_new[0]) <
+ fabsf(drag_info->but_cent_start[1] - but_cent_new[1]))
+ {
+ drag_info->xy_lock[0] = true;
+ }
+ else {
+ drag_info->xy_lock[1] = true;
+ }
+ }
+ }
+ }
+ /* done with axis locking */
+
+
+ xy[0] = (drag_info->xy_lock[0] == false) ? xy_input[0] : drag_info->xy_last[0];
+ xy[1] = (drag_info->xy_lock[1] == false) ? xy_input[1] : drag_info->xy_last[1];
+
+
+ /* touch all buttons between last mouse coord and this one */
+ do_draw = ui_drag_toggle_set_xy_xy(C, ar, drag_info->is_set, drag_info->but_type_start, drag_info->xy_last, xy);
+
+ if (do_draw) {
+ ED_region_tag_redraw(ar);
+ }
+
+ copy_v2_v2_int(drag_info->xy_last, xy);
+}
+
+static void ui_handler_region_drag_toggle_remove(bContext *UNUSED(C), void *userdata)
+{
+ uiDragToggleHandle *drag_info = userdata;
+ MEM_freeN(drag_info);
+}
+
+static int ui_handler_region_drag_toggle(bContext *C, const wmEvent *event, void *userdata)
+{
+ uiDragToggleHandle *drag_info = userdata;
+ bool done = false;
+
+ switch (event->type) {
+ case LEFTMOUSE:
+ {
+ if (event->val != KM_PRESS) {
+ done = true;
+ }
+ break;
+ }
+ case MOUSEMOVE:
+ {
+ ui_drag_toggle_set(C, drag_info, &event->x);
+ break;
+ }
+ }
+
+ if (done) {
+ wmWindow *win = CTX_wm_window(C);
+ WM_event_remove_ui_handler(&win->modalhandlers,
+ ui_handler_region_drag_toggle,
+ ui_handler_region_drag_toggle_remove,
+ drag_info, false);
+ ui_handler_region_drag_toggle_remove(C, drag_info);
+
+ WM_event_add_mousemove(C);
+ return WM_UI_HANDLER_BREAK;
+ }
+ else {
+ return WM_UI_HANDLER_CONTINUE;
+ }
+}
+
+#endif /* USE_DRAG_TOGGLE */
+
+
static int ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, const wmEvent *event)
{
rcti rect;
@@ -765,18 +920,24 @@ static int ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data,
button_activate_state(C, but, BUTTON_STATE_EXIT);
data->cancel = TRUE;
-
+#ifdef USE_DRAG_TOGGLE
if (ui_is_but_bool(but)) {
- const bool is_set = (ui_get_but_val(but) != 0.0);
- PointerRNA ptr;
- WM_operator_properties_create(&ptr, "UI_OT_drag_toggle");
- RNA_boolean_set(&ptr, "state", !is_set);
- RNA_int_set(&ptr, "last_x", data->dragstartx);
- RNA_int_set(&ptr, "last_y", data->dragstarty);
- WM_operator_name_call(C, "UI_OT_drag_toggle", WM_OP_INVOKE_DEFAULT, &ptr);
- WM_operator_properties_free(&ptr);
+ uiDragToggleHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__);
+
+ drag_info->is_set = ui_is_but_push(but);
+ drag_info->but_cent_start[0] = BLI_rctf_cent_x(&but->rect);
+ drag_info->but_cent_start[1] = BLI_rctf_cent_y(&but->rect);
+ drag_info->but_type_start = but->type;
+ copy_v2_v2_int(drag_info->xy_last, &event->x);
+
+ WM_event_add_ui_handler(C, &data->window->modalhandlers,
+ ui_handler_region_drag_toggle,
+ ui_handler_region_drag_toggle_remove,
+ drag_info);
}
- else {
+ else
+#endif
+ {
wmDrag *drag;
drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but));
@@ -2485,25 +2646,32 @@ static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHa
static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
+#ifdef USE_DRAG_TOGGLE
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE && event->val == KM_PRESS && ui_is_but_bool(but)) {
+ data->togdual = event->ctrl;
+ data->togonly = !event->shift;
+ ui_apply_button(C, but->block, but, data, true);
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
- return WM_UI_HANDLER_CONTINUE;
+ return WM_UI_HANDLER_BREAK;
}
-
+ }
+ else if (data->state == BUTTON_STATE_WAIT_DRAG) {
+ /* note: the 'BUTTON_STATE_WAIT_DRAG' part of 'ui_do_but_EXIT' could be refactored into its own function */
+ data->applied = false;
+ return ui_do_but_EXIT(C, but, data, event);
+ }
+#endif
+ if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
data->togdual = event->ctrl;
data->togonly = !event->shift;
button_activate_state(C, but, BUTTON_STATE_EXIT);
- return WM_UI_HANDLER_CONTINUE;
+ return WM_UI_HANDLER_BREAK;
}
}
- else if (data->state == BUTTON_STATE_WAIT_DRAG) {
- /* note: the 'BUTTON_STATE_WAIT_DRAG' part of 'ui_do_but_EXIT' could be refactored into its own function */
- return ui_do_but_EXIT(C, but, data, event);
- }
return WM_UI_HANDLER_CONTINUE;
}
@@ -2524,13 +2692,15 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
return WM_UI_HANDLER_CONTINUE;
}
}
+#ifdef USE_DRAG_TOGGLE
if (event->type == LEFTMOUSE && ui_is_but_bool(but)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
return WM_UI_HANDLER_CONTINUE;
}
-
+#endif
+
if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
int ret = WM_UI_HANDLER_BREAK;
/* XXX (a bit ugly) Special case handling for filebrowser drag button */
@@ -3246,13 +3416,14 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
return WM_UI_HANDLER_BREAK;
}
}
+#ifdef USE_DRAG_TOGGLE
if (event->type == LEFTMOUSE && ui_is_but_bool(but)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
return WM_UI_HANDLER_BREAK;
}
-
+#endif
/* regular open menu */
if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
@@ -4253,7 +4424,7 @@ static int ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int mx
if (in_scope_resize_zone(but, data->dragstartx, data->dragstarty)) {
/* resize histogram widget itself */
- hist->height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my))/UI_DPI_FAC;
+ hist->height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my)) / UI_DPI_FAC;
}
else {
/* scale histogram values (dy / 10 for better control) */
@@ -4337,7 +4508,7 @@ static int ui_numedit_but_WAVEFORM(uiBut *but, uiHandleButtonData *data, int mx,
if (in_scope_resize_zone(but, data->dragstartx, data->dragstarty)) {
/* resize waveform widget itself */
- scopes->wavefrm_height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my))/UI_DPI_FAC;
+ scopes->wavefrm_height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my)) / UI_DPI_FAC;
}
else {
/* scale waveform values */
@@ -4419,7 +4590,7 @@ static int ui_numedit_but_VECTORSCOPE(uiBut *but, uiHandleButtonData *data, int
if (in_scope_resize_zone(but, data->dragstartx, data->dragstarty)) {
/* resize vectorscope widget itself */
- scopes->vecscope_height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my))/UI_DPI_FAC;
+ scopes->vecscope_height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my)) / UI_DPI_FAC;
}
data->draglastx = mx;
@@ -4622,7 +4793,7 @@ static int ui_numedit_but_TRACKPREVIEW(bContext *C, uiBut *but, uiHandleButtonDa
if (in_scope_resize_zone(but, data->dragstartx, data->dragstarty)) {
/* resize preview widget itself */
- scopes->track_preview_height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my))/UI_DPI_FAC;
+ scopes->track_preview_height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my)) / UI_DPI_FAC;
}
else {
if (!scopes->track_locked) {
@@ -5452,6 +5623,24 @@ static int ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y)
return 1;
}
+/**
+ * Can we mouse over the button or is it hidden/disabled/layout.
+ */
+bool ui_is_but_interactive(uiBut *but)
+{
+ /* note, LABEL is included for highlights, this allows drags */
+ if (but->type == LABEL && but->dragpoin == NULL)
+ return false;
+ if (ELEM3(but->type, ROUNDBOX, SEPR, LISTBOX))
+ return false;
+ if (but->flag & UI_HIDDEN)
+ return false;
+ if (but->flag & UI_SCROLLED)
+ return false;
+
+ return true;
+}
+
uiBut *ui_but_find_mouse_over(ARegion *ar, int x, int y)
{
uiBlock *block;
@@ -5469,17 +5658,11 @@ uiBut *ui_but_find_mouse_over(ARegion *ar, int x, int y)
ui_window_to_block(ar, block, &mx, &my);
for (but = block->buttons.first; but; but = but->next) {
- /* note, LABEL is included for highlights, this allows drags */
- if (but->type == LABEL && but->dragpoin == NULL)
- continue;
- if (ELEM3(but->type, ROUNDBOX, SEPR, LISTBOX))
- continue;
- if (but->flag & UI_HIDDEN)
- continue;
- if (but->flag & UI_SCROLLED)
- continue;
- if (ui_but_contains_pt(but, mx, my))
- butover = but;
+ if (ui_is_but_interactive(but)) {
+ if (ui_but_contains_pt(but, mx, my)) {
+ butover = but;
+ }
+ }
}
/* CLIP_EVENTS prevents the event from reaching other blocks */
@@ -5795,7 +5978,8 @@ static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *da
if (!onfree && !data->cancel) {
/* autokey & undo push */
- ui_apply_autokey_undo(C, but);
+ ui_apply_undo(but);
+ ui_apply_autokey(C, but);
/* popup menu memory */
if (block->flag & UI_BLOCK_POPUP_MEMORY)
@@ -5820,12 +6004,13 @@ static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *da
/* redraw (data is but->active!) */
ED_region_tag_redraw(data->region);
-
+
/* clean up button */
if (but->active) {
MEM_freeN(but->active);
but->active = NULL;
}
+
but->flag &= ~(UI_ACTIVE | UI_SELECT);
but->flag |= UI_BUT_LAST_ACTIVE;
if (!onfree)
@@ -6084,6 +6269,7 @@ void ui_button_execute_do(struct bContext *C, struct ARegion *ar, uiBut *but)
data->region = ar;
ui_apply_button(C, but->block, but, data, true);
/* use onfree event so undo is handled by caller and apply is already done above */
+ ui_apply_autokey(C, but);
button_activate_exit((bContext *)C, but, data, false, true);
but->active = active_back;
}
@@ -6107,14 +6293,12 @@ static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiBu
static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
{
- uiHandleButtonData *data;
+ uiHandleButtonData *data = but->active;
+ const uiButtonActivateType state_orig = data->state;
uiBlock *block;
ARegion *ar;
- uiBut *postbut;
- uiButtonActivateType posttype;
int retval;
- data = but->active;
block = but->block;
ar = data->region;
@@ -6266,14 +6450,28 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
}
if (data->state == BUTTON_STATE_EXIT) {
- postbut = data->postbut;
- posttype = data->posttype;
+ uiBut *post_but = data->postbut;
+ uiButtonActivateType post_type = data->posttype;
- button_activate_exit(C, but, data, (postbut == NULL), false);
+ button_activate_exit(C, but, data, (post_but == NULL), false);
/* for jumping to the next button with tab while text editing */
- if (postbut)
- button_activate_init(C, ar, postbut, posttype);
+ if (post_but) {
+ button_activate_init(C, ar, post_but, post_type);
+ }
+ else {
+ /* XXX issue is because WM_event_add_mousemove(C) is a bad hack and not reliable,
+ *if that gets coded better this bypass can go away too.
+ *
+ * This is needed to make sure if a button was active,
+ * it stays active while the mouse is over it.
+ * This avoids adding mousemoves, see: [#33466] */
+ if (ELEM(state_orig, BUTTON_ACTIVATE, BUTTON_ACTIVATE_OVER)) {
+ if (ui_but_find_mouse_over(ar, event->x, event->y) == but) {
+ button_activate_init(C, ar, but, state_orig);
+ }
+ }
+ }
}
return retval;
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index f0e59f1f935..9093e8f8d30 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -171,8 +171,8 @@ struct uiBut {
char *str;
char strdata[UI_MAX_NAME_STR];
char drawstr[UI_MAX_DRAW_STR];
-
- rctf rect;
+
+ rctf rect; /* block relative coords */
char *poin;
float hardmin, hardmax, softmin, softmax;
@@ -225,7 +225,7 @@ struct uiBut {
void *rename_orig;
uiLink *link;
- short linkto[2];
+ short linkto[2]; /* region relative coords */
const char *tip, *lockstr;
@@ -410,6 +410,11 @@ extern int ui_is_but_bool(uiBut *but);
extern int ui_is_but_unit(uiBut *but);
extern int ui_is_but_rna_valid(uiBut *but);
extern int ui_is_but_utf8(uiBut *but);
+extern bool ui_is_but_interactive(uiBut *but);
+
+extern int ui_is_but_push_ex(uiBut *but, double *value);
+extern int ui_is_but_push(uiBut *but);
+
extern void ui_bounds_block(uiBlock *block);
extern void ui_block_translate(uiBlock *block, int x, int y);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index c69f53a53d2..1e95b4df762 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -2263,6 +2263,7 @@ uiLayout *uiLayoutRow(uiLayout *layout, int align)
litem->enabled = 1;
litem->context = layout->context;
litem->space = (align) ? 0 : layout->root->style->buttonspacex;
+ litem->redalert = layout->redalert;
litem->w = layout->w;
BLI_addtail(&layout->items, litem);
@@ -2283,6 +2284,7 @@ uiLayout *uiLayoutColumn(uiLayout *layout, int align)
litem->enabled = 1;
litem->context = layout->context;
litem->space = (litem->align) ? 0 : layout->root->style->buttonspacey;
+ litem->redalert = layout->redalert;
litem->w = layout->w;
BLI_addtail(&layout->items, litem);
@@ -2303,6 +2305,7 @@ uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align)
flow->litem.enabled = 1;
flow->litem.context = layout->context;
flow->litem.space = (flow->litem.align) ? 0 : layout->root->style->columnspace;
+ flow->litem.redalert = layout->redalert;
flow->litem.w = layout->w;
flow->number = number;
BLI_addtail(&layout->items, flow);
@@ -2323,6 +2326,7 @@ static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
box->litem.enabled = 1;
box->litem.context = layout->context;
box->litem.space = layout->root->style->columnspace;
+ box->litem.redalert = layout->redalert;
box->litem.w = layout->w;
BLI_addtail(&layout->items, box);
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index d48d699d881..3298859ee0c 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1071,222 +1071,6 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot)
ot->exec = reloadtranslation_exec;
}
-
-/* -------------------------------------------------------------------- */
-/* Toggle Drag Operator */
-
-typedef struct DragOpInfo {
- bool xy_lock[2];
- float but_cent_start[2];
- eButType but_type_start;
-} DragOpInfo;
-
-typedef struct DragOpPlotData {
- bContext *C;
- ARegion *ar;
- bool is_set;
- eButType but_type_start;
- bool do_draw;
- const uiBut *but_prev;
-} DragOpPlotData;
-
-static const uiBut *ui_but_set_xy(bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
- const int xy[2], const uiBut *but_prev)
-{
- uiBut *but = ui_but_find_mouse_over(ar, xy[0], xy[1]);
-
- if (but_prev == but) {
- return but_prev;
- }
-
- if (but && ui_is_but_bool(but) && but->type == but_type_start) {
- /* is it pressed? */
- bool is_set_but = (ui_get_but_val(but) != 0.0);
- BLI_assert(ui_is_but_bool(but) == true);
- if (is_set_but != is_set) {
- uiButExecute(C, but);
- return but;
- }
- }
-
- return but_prev;
-}
-
-static int ui_but_set_cb(int x, int y, void *data_v)
-{
- DragOpPlotData *data = data_v;
- int xy[2] = {x, y};
- data->but_prev = ui_but_set_xy(data->C, data->ar, data->is_set, data->but_type_start, xy, data->but_prev);
- return 1; /* keep going */
-}
-
-/* operates on buttons between 2 mouse-points */
-static bool ui_but_set_xy_xy(bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
- const int xy_src[2], const int xy_dst[2])
-{
- DragOpPlotData data;
- data.C = C;
- data.ar = ar;
- data.is_set = is_set;
- data.but_type_start = but_type_start;
- data.do_draw = false;
- data.but_prev = NULL;
-
-
- /* prevent dragging too fast loosing buttons */
- plot_line_v2v2i(xy_src, xy_dst, ui_but_set_cb, &data);
-
- return data.do_draw;
-}
-
-static void ui_drag_but_set(bContext *C, wmOperator *op, const int xy_input[2])
-{
- ARegion *ar = CTX_wm_region(C);
- DragOpInfo *drag_info = op->customdata;
- bool do_draw = false;
-
- const bool is_set = RNA_boolean_get(op->ptr, "state");
- const int xy_last[2] = {RNA_int_get(op->ptr, "last_x"),
- RNA_int_get(op->ptr, "last_y")};
-
- int xy[2];
-
- /**
- * Initialize Locking:
- *
- * Check if we need to initialize the lock axis by finding if the first
- * button we mouse over is X or Y aligned, then lock the mouse to that axis after.
- */
- if (drag_info->xy_lock[0] == false && drag_info->xy_lock[1] == false) {
- ARegion *ar = CTX_wm_region(C);
-
- /* first store the buttons original coords */
- uiBut *but = ui_but_find_mouse_over(ar, xy_input[0], xy_input[1]);
- if (but) {
- const float but_cent_new[2] = {BLI_rctf_cent_x(&but->rect),
- BLI_rctf_cent_y(&but->rect)};
-
- /* check if this is a different button, chances are high the button wont move about :) */
- if (len_manhattan_v2v2(drag_info->but_cent_start, but_cent_new) > 1.0f) {
- if (fabsf(drag_info->but_cent_start[0] - but_cent_new[0]) <
- fabsf(drag_info->but_cent_start[1] - but_cent_new[1]))
- {
- drag_info->xy_lock[0] = true;
- }
- else {
- drag_info->xy_lock[1] = true;
- }
- }
- }
- }
- /* done with axis locking */
-
-
- xy[0] = (drag_info->xy_lock[0] == false) ? xy_input[0] : xy_last[0];
- xy[1] = (drag_info->xy_lock[1] == false) ? xy_input[1] : xy_last[1];
-
-
- /* touch all buttons between last mouse coord and this one */
- do_draw = ui_but_set_xy_xy(C, ar, is_set, drag_info->but_type_start, xy_last, xy);
-
- if (do_draw) {
- ED_region_tag_redraw(ar);
- }
-
- RNA_int_set(op->ptr, "last_x", xy[0]);
- RNA_int_set(op->ptr, "last_y", xy[1]);
-}
-
-static int ui_drag_toggle_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- int xy_last[2] = {RNA_int_get(op->ptr, "last_x"),
- RNA_int_get(op->ptr, "last_y")};
-
- float but_cent_start[2];
- eButType but_type_start;
- DragOpInfo *drag_info;
-
- {
- /* find the button where we started dragging */
- ARegion *ar = CTX_wm_region(C);
- uiBut *but = ui_but_find_mouse_over(ar, xy_last[0], xy_last[1]);
- if (but) {
- but_cent_start[0] = BLI_rctf_cent_x(&but->rect);
- but_cent_start[1] = BLI_rctf_cent_y(&but->rect);
- but_type_start = but->type;
- }
- else {
- return OPERATOR_CANCELLED;
- }
- }
-
- drag_info = op->customdata = MEM_callocN(sizeof(DragOpInfo), __func__);
- copy_v2_v2(drag_info->but_cent_start, but_cent_start);
- drag_info->but_type_start = but_type_start;
-
- /* set the initial button */
- ui_drag_but_set(C, op, xy_last);
- ui_drag_but_set(C, op, &event->x);
-
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int ui_drag_toggle_modal(bContext *C, wmOperator *op, wmEvent *event)
-{
- bool done = false;
-
- switch (event->type) {
- case LEFTMOUSE:
- {
- if (event->val != KM_PRESS) {
- done = true;
- }
- break;
- }
- case MOUSEMOVE:
- {
- ui_drag_but_set(C, op, &event->x);
- break;
- }
- }
-
- if (done) {
- MEM_freeN(op->customdata);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_RUNNING_MODAL;
- }
-}
-
-static int ui_drag_toggle_cancel(bContext *UNUSED(C), wmOperator *op)
-{
- MEM_freeN(op->customdata);
- return OPERATOR_CANCELLED;
-}
-
-static void UI_OT_drag_toggle(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Button Drag Toggle";
- ot->description = "";
- ot->idname = "UI_OT_drag_toggle";
-
- /* api callbacks */
- ot->invoke = ui_drag_toggle_invoke;
- ot->modal = ui_drag_toggle_modal;
- ot->cancel = ui_drag_toggle_cancel;
-
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- RNA_def_boolean(ot->srna, "state", true, "State", "");
- RNA_def_int(ot->srna, "last_x", 0, 0, INT_MAX, "X", "", 0, INT_MAX);
- RNA_def_int(ot->srna, "last_y", 0, 0, INT_MAX, "Y", "", 0, INT_MAX);
-}
-
/* ********************************************************* */
/* Registration */
@@ -1304,6 +1088,4 @@ void UI_buttons_operatortypes(void)
WM_operatortype_append(UI_OT_edittranslation_init);
#endif
WM_operatortype_append(UI_OT_reloadtranslation);
- WM_operatortype_append(UI_OT_drag_toggle);
}
-
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 900ba7de559..83540cef9fc 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2594,7 +2594,8 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
/* if list length changes and active is out of view, scroll to it */
if ((ui_list->list_last_len != len) &&
- (activei < ui_list->list_scroll || activei >= ui_list->list_scroll + items)) {
+ (activei < ui_list->list_scroll || activei >= ui_list->list_scroll + items))
+ {
ui_list->list_scroll = activei;
}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 68df8e29957..dd7b1d0ee06 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1855,7 +1855,7 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r
widget_verts_to_quad_strip(&wtb, totvert, quad_strip);
glVertexPointer(2, GL_FLOAT, 0, quad_strip);
- glDrawArrays(GL_QUAD_STRIP, 0, totvert * 2 + 2);
+ glDrawArrays(GL_QUAD_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);
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 7f1140501b5..daa78957231 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -1034,10 +1034,11 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, wmEvent *event)
}
else {
/* 'continuous' or 'dolly' */
- float fac, zoomfac = 0.001f * v2d->maxzoom;
+ float fac, zoomfac = 0.01f;
/* some view2d's (graph) don't have min/max zoom, or extreme ones */
- CLAMP (zoomfac, 0.001f, 0.01f);
+ if (v2d->maxzoom > 0.0f)
+ zoomfac = CLAMPIS(0.001f * v2d->maxzoom, 0.001f, 0.01f);
/* x-axis transform */
fac = zoomfac * (event->x - vzd->lastx);
@@ -1116,7 +1117,7 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot)
ot->poll = view_zoom_poll;
/* operator is repeatable */
- // ot->flag = OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
/* rna - must keep these in sync with the other operators */
RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX);
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 7db23041c88..d4ae5b8b29b 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -47,4 +47,8 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
blender_add_lib(bf_editor_io "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/io/SConscript b/source/blender/editors/io/SConscript
index cef73f33ddd..b7449ccad79 100644
--- a/source/blender/editors/io/SConscript
+++ b/source/blender/editors/io/SConscript
@@ -36,4 +36,7 @@ incs += '../../makesdna ../../makesrna ../../windowmanager ../../collada'
if env['WITH_BF_COLLADA']:
defs += ['WITH_COLLADA']
+if env['WITH_BF_INTERNATIONAL']:
+ defs += ['WITH_INTERNATIONAL']
+
env.BlenderLib ( 'bf_editor_io', sources, Split(incs), defines=defs, libtype=['core','player'], priority=[330,210] )
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index 7703a8638c9..4908c101a7c 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -92,6 +92,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int use_texture_copies;
int active_uv_only;
+ int triangulate;
int use_object_instantiation;
int sort_by_name;
int second_life;
@@ -118,6 +119,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
use_texture_copies = RNA_boolean_get(op->ptr, "use_texture_copies");
active_uv_only = RNA_boolean_get(op->ptr, "active_uv_only");
+ triangulate = RNA_boolean_get(op->ptr, "triangulate");
use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation");
sort_by_name = RNA_boolean_get(op->ptr, "sort_by_name");
second_life = RNA_boolean_get(op->ptr, "second_life");
@@ -140,9 +142,11 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
include_material_textures,
use_texture_copies,
+ triangulate,
use_object_instantiation,
sort_by_name,
- second_life)) {
+ second_life))
+ {
return OPERATOR_FINISHED;
}
else {
@@ -217,6 +221,8 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemL(row, IFACE_("Collada Options:"), ICON_MODIFIER);
row = uiLayoutRow(box, FALSE);
+ uiItemR(row, imfptr, "triangulate", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, FALSE);
uiItemR(row, imfptr, "use_object_instantiation", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, FALSE);
uiItemR(row, imfptr, "sort_by_name", 0, NULL, ICON_NONE);
@@ -293,6 +299,9 @@ void WM_OT_collada_export(wmOperatorType *ot)
"Copy textures to same folder where the .dae file is exported");
+ RNA_def_boolean(ot->srna, "triangulate", 1, "Triangulate",
+ "Export Polygons (Quads & NGons) as Triangles");
+
RNA_def_boolean(ot->srna, "use_object_instantiation", 1, "Use Object Instances",
"Instantiate multiple Objects from same Data");
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 7ac27e038a4..7ddf2b54a88 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -181,11 +181,17 @@ void paintface_reveal(Object *ob)
static void hash_add_face(EdgeHash *ehash, MPoly *mp, MLoop *mloop)
{
- MLoop *ml;
- int i;
+ MLoop *ml, *ml_next;
+ int i = mp->totloop;
+
+ ml_next = mloop; /* first loop */
+ ml = &ml_next[i - 1]; /* last loop */
+
+ while (i-- != 0) {
+ BLI_edgehash_insert(ehash, ml->v, ml_next->v, NULL);
- for (i = 0, ml = mloop; i < mp->totloop; i++, ml++) {
- BLI_edgehash_insert(ehash, ml->v, ME_POLY_LOOP_NEXT(mloop, mp, i)->v, NULL);
+ ml = ml_next;
+ ml_next++;
}
}
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 57f116693f8..51161970c0b 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -933,9 +933,13 @@ static int edbm_select_mode_exec(bContext *C, wmOperator *op)
static int edbm_select_mode_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
- // RNA_enum_set(op->ptr, "type"); /* type must be set already */
- RNA_boolean_set(op->ptr, "use_extend", event->shift);
- RNA_boolean_set(op->ptr, "use_expand", event->ctrl);
+ /* detecting these options based on shift/ctrl here is weak, but it's done
+ * to make this work when clicking buttons or menus */
+ if (!RNA_struct_property_is_set(op->ptr, "use_extend"))
+ RNA_boolean_set(op->ptr, "use_extend", event->shift);
+ if (!RNA_struct_property_is_set(op->ptr, "use_expand"))
+ RNA_boolean_set(op->ptr, "use_expand", event->ctrl);
+
return edbm_select_mode_exec(C, op);
}
@@ -1358,6 +1362,22 @@ static int edgetag_context_check(Scene *scene, BMesh *bm, BMEdge *e)
return 0;
}
+static void edgetag_ensure_cd_flag(Scene *scene, Mesh *me)
+{
+ BMesh *bm = me->edit_btmesh->bm;
+
+ switch (scene->toolsettings->edge_mode) {
+ case EDGE_MODE_TAG_CREASE:
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
+ break;
+ case EDGE_MODE_TAG_BEVEL:
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
+ break;
+ default:
+ break;
+ }
+}
+
static int edgetag_shortest_path(Scene *scene, BMesh *bm, BMEdge *e_src, BMEdge *e_dst)
{
/* BM_ELEM_TAG flag is used to store visited edges */
@@ -1371,16 +1391,7 @@ static int edgetag_shortest_path(Scene *scene, BMesh *bm, BMEdge *e_src, BMEdge
/* note, would pass BM_EDGE except we are looping over all edges anyway */
BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */);
- switch (scene->toolsettings->edge_mode) {
- case EDGE_MODE_TAG_CREASE:
- BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(OBACT), ME_CDFLAG_EDGE_CREASE);
- break;
- case EDGE_MODE_TAG_BEVEL:
- BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(OBACT), ME_CDFLAG_EDGE_BWEIGHT);
- break;
- default:
- break;
- }
+ edgetag_ensure_cd_flag(scene, OBACT->data);
BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == FALSE) {
@@ -1470,7 +1481,7 @@ static int mouse_mesh_shortest_path_edge(ViewContext *vc)
e_dst = EDBM_edge_find_nearest(vc, &dist);
if (e_dst) {
Mesh *me = vc->obedit->data;
- int path = 0;
+ bool is_path = false;
if (em->bm->selected.last) {
BMEditSelection *ese = em->bm->selected.last;
@@ -1481,13 +1492,14 @@ static int mouse_mesh_shortest_path_edge(ViewContext *vc)
if (e_act != e_dst) {
if (edgetag_shortest_path(vc->scene, em->bm, e_act, e_dst)) {
BM_select_history_remove(em->bm, e_act);
- path = 1;
+ is_path = true;
}
}
}
}
- if (path == 0) {
+ if (is_path == false) {
int act = (edgetag_context_check(vc->scene, em->bm, e_dst) == 0);
+ edgetag_ensure_cd_flag(vc->scene, vc->obedit->data);
edgetag_context_set(em->bm, vc->scene, e_dst, act); /* switch the edge option */
}
@@ -2963,7 +2975,7 @@ void MESH_OT_select_random(wmOperatorType *ot)
/* props */
RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
"Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
static int edbm_select_next_loop_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index dcb25423b80..92e1dbf433f 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3321,7 +3321,8 @@ static int edbm_fill_exec(bContext *C, wmOperator *op)
if (!EDBM_op_init(em, &bmop, op,
"triangle_fill edges=%he use_beauty=%b",
- BM_ELEM_SELECT, use_beauty)) {
+ BM_ELEM_SELECT, use_beauty))
+ {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index f983a43f573..378f6374336 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -149,7 +149,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* remove tessface to ensure we don't old references to invalid faces */
+ /* remove tessface to ensure we don't hold references to invalid faces */
BKE_mesh_tessface_clear(me);
/* new material indices and material array */
@@ -309,6 +309,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
me = base->object->data;
if (me->totvert) {
+
+ /* merge customdata flag */
+ ((Mesh *)ob->data)->cd_flag |= me->cd_flag;
+
/* standard data */
CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index bc577f6ee29..997cbb71683 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -67,6 +67,7 @@
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_group.h"
+#include "BKE_image.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
@@ -735,6 +736,83 @@ void OBJECT_OT_empty_add(wmOperatorType *ot)
ED_object_add_generic_props(ot, FALSE);
}
+static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Base *base = NULL;
+ Image *ima = NULL;
+ Object *ob = NULL;
+
+ /* check image input variables */
+ if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ char path[FILE_MAX];
+
+ RNA_string_get(op->ptr, "filepath", path);
+ ima = BKE_image_load_exists(path);
+ }
+ else if (RNA_struct_property_is_set(op->ptr, "name")) {
+ char name[MAX_ID_NAME - 2];
+
+ RNA_string_get(op->ptr, "name", name);
+ ima = (Image *)BKE_libblock_find_name(ID_IM, name);
+ }
+
+ if (ima == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Not an image");
+ return OPERATOR_CANCELLED;
+ }
+
+ base = ED_view3d_give_base_under_cursor(C, event->mval);
+
+ /* if empty under cursor, then set object */
+ if (base && base->object->type == OB_EMPTY) {
+ ob = base->object;
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, CTX_data_scene(C));
+ }
+ else {
+ /* add new empty */
+ unsigned int layer;
+ float rot[3];
+
+ if (!ED_object_add_generic_get_opts(C, op, NULL, rot, NULL, &layer, NULL))
+ return OPERATOR_CANCELLED;
+
+ ob = ED_object_add_type(C, OB_EMPTY, NULL, rot, FALSE, layer);
+
+ /* add under the mouse */
+ ED_object_location_from_view(C, ob->loc);
+ ED_view3d_cursor3d_position(C, ob->loc, event->mval);
+ }
+
+ ob->empty_drawtype = OB_EMPTY_IMAGE;
+ ob->data = ima;
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_drop_named_image(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Add Empty Image/Drop Image To Empty";
+ ot->description = "Add an empty image type to scene with data";
+ ot->idname = "OBJECT_OT_drop_named_image";
+
+ /* api callbacks */
+ ot->invoke = empty_drop_named_image_invoke;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_string(ot->srna, "filepath", "", FILE_MAX, "Filepath", "Path to image file");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_string(ot->srna, "name", "", MAX_ID_NAME - 2, "Name", "Image name to assign");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ ED_object_add_generic_props(ot, FALSE);
+}
+
/********************* Add Lamp Operator ********************/
static const char *get_lamp_defname(int type)
@@ -2034,12 +2112,17 @@ static int add_named_exec(bContext *C, wmOperator *op)
}
basen->lay = basen->object->lay = scene->lay;
+ basen->object->restrictflag &= ~OB_RESTRICT_VIEW;
if (event) {
+ ARegion *ar = CTX_wm_region(C);
+ const int mval[2] = {event->x - ar->winrct.xmin,
+ event->y - ar->winrct.ymin};
ED_object_location_from_view(C, basen->object->loc);
- ED_view3d_cursor3d_position(C, basen->object->loc, event->mval);
+ ED_view3d_cursor3d_position(C, basen->object->loc, mval);
}
+ ED_base_object_select(basen, BA_SELECT);
ED_base_object_activate(C, basen);
copy_object_set_idnew(C, dupflag);
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 84b989e2f59..1bed7d7dd11 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -40,6 +40,8 @@
#include "BLI_dynstr.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "DNA_anim_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
@@ -1873,7 +1875,7 @@ static int pose_ik_add_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
}
/* prepare popup menu to choose targetting options */
- pup = uiPupMenuBegin(C, "Add IK", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Add IK"), ICON_NONE);
layout = uiPupMenuLayout(pup);
/* the type of targets we'll set determines the menu entries to show... */
@@ -1882,14 +1884,14 @@ static int pose_ik_add_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
* - the only thing that matters is that we want a target...
*/
if (tar_pchan)
- uiItemBooleanO(layout, "To Active Bone", ICON_NONE, "POSE_OT_ik_add", "with_targets", 1);
+ uiItemBooleanO(layout, IFACE_("To Active Bone"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 1);
else
- uiItemBooleanO(layout, "To Active Object", ICON_NONE, "POSE_OT_ik_add", "with_targets", 1);
+ uiItemBooleanO(layout, IFACE_("To Active Object"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 1);
}
else {
/* we have a choice of adding to a new empty, or not setting any target (targetless IK) */
- uiItemBooleanO(layout, "To New Empty Object", ICON_NONE, "POSE_OT_ik_add", "with_targets", 1);
- uiItemBooleanO(layout, "Without Targets", ICON_NONE, "POSE_OT_ik_add", "with_targets", 0);
+ uiItemBooleanO(layout, IFACE_("To New Empty Object"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 1);
+ uiItemBooleanO(layout, IFACE_("Without Targets"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 0);
}
/* finish building the menu, and process it (should result in calling self again) */
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 4523ac098d6..a302aa65fd0 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -113,6 +113,7 @@ void OBJECT_OT_metaball_add(struct wmOperatorType *ot);
void OBJECT_OT_text_add(struct wmOperatorType *ot);
void OBJECT_OT_armature_add(struct wmOperatorType *ot);
void OBJECT_OT_empty_add(struct wmOperatorType *ot);
+void OBJECT_OT_drop_named_image(struct wmOperatorType *ot);
void OBJECT_OT_lamp_add(struct wmOperatorType *ot);
void OBJECT_OT_effector_add(struct wmOperatorType *ot);
void OBJECT_OT_camera_add(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index bf408d6dbe4..e5aaaffade8 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -114,6 +114,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_text_add);
WM_operatortype_append(OBJECT_OT_armature_add);
WM_operatortype_append(OBJECT_OT_empty_add);
+ WM_operatortype_append(OBJECT_OT_drop_named_image);
WM_operatortype_append(OBJECT_OT_lamp_add);
WM_operatortype_append(OBJECT_OT_camera_add);
WM_operatortype_append(OBJECT_OT_speaker_add);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index c5e8310e9fb..f9dde043607 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -304,7 +304,7 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, wmEvent *evt)
}
else if (ob->id.lib) {
- uiPopupMenu *pup = uiPupMenuBegin(C, "OK?", ICON_QUESTION);
+ uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("OK?"), ICON_QUESTION);
uiLayout *layout = uiPupMenuLayout(pup);
/* create operator menu item with relevant properties filled in */
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 775a2897513..baa0199baf7 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -50,6 +50,8 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_group.h"
#include "BKE_main.h"
@@ -606,7 +608,7 @@ static short select_grouped_group(bContext *C, Object *ob) /* Select objects in
}
/* build the menu. */
- pup = uiPupMenuBegin(C, "Select Group", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Select Group"), ICON_NONE);
layout = uiPupMenuLayout(pup);
for (i = 0; i < group_count; i++) {
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 01dcac2d1b4..3fa6c301fcb 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -871,7 +871,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
/* Function to recenter armatures in editarmature.c
* Bone + object locations are handled there.
*/
- docenter_armature(scene, ob, cursor, centermode, around);
+ ED_armature_origin_set(scene, ob, cursor, centermode, around);
tot_change++;
arm->id.flag |= LIB_DOIT;
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 87ff42ef4db..ef882b2486b 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -558,8 +558,10 @@ static int ed_vgroup_transfer_weight(Object *ob_dst, Object *ob_src, bDeformGrou
}
/* Loop through the vertices.*/
- for (i = 0, dv_src = dv_array_src, dv_dst = dv_array_dst; i < me_dst->totvert;
- i++, dv_dst++, dv_src++, mv_src++, mv_dst++) {
+ for (i = 0, dv_src = dv_array_src, dv_dst = dv_array_dst;
+ i < me_dst->totvert;
+ i++, dv_dst++, dv_src++, mv_src++, mv_dst++)
+ {
if (*dv_dst == NULL) {
continue;
@@ -2598,7 +2600,7 @@ static int vertex_group_poll(bContext *C)
return (ob && !ob->id.lib && OB_TYPE_SUPPORT_VGROUP(ob->type) && data && !data->lib);
}
-static int UNUSED_FUNCTION(vertex_group_poll_edit) (bContext * C)
+static int UNUSED_FUNCTION(vertex_group_poll_edit) (bContext *C)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c
index bbce94b6215..b9742c9968f 100644
--- a/source/blender/editors/physics/physics_pointcache.c
+++ b/source/blender/editors/physics/physics_pointcache.c
@@ -90,6 +90,20 @@ static void bake_console_progress_end(void *UNUSED(arg))
printf("\rbake: done!\n");
}
+static void ptcache_free_bake(PointCache *cache)
+{
+ if (cache->edit) {
+ if (!cache->edit->edited || 1) {// XXX okee("Lose changes done in particle mode?")) {
+ PE_free_ptcache_edit(cache->edit);
+ cache->edit = NULL;
+ cache->flag &= ~PTCACHE_BAKED;
+ }
+ }
+ else {
+ cache->flag &= ~PTCACHE_BAKED;
+ }
+}
+
static int ptcache_bake_all_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -139,7 +153,7 @@ static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op))
BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
for (pid=pidlist.first; pid; pid=pid->next) {
- pid->cache->flag &= ~PTCACHE_BAKED;
+ ptcache_free_bake(pid->cache);
}
BLI_freelistN(&pidlist);
@@ -241,15 +255,7 @@ static int ptcache_free_bake_exec(bContext *C, wmOperator *UNUSED(op))
PointCache *cache= ptr.data;
Object *ob= ptr.id.data;
- if (cache->edit) {
- if (!cache->edit->edited || 1) {// XXX okee("Lose changes done in particle mode?")) {
- PE_free_ptcache_edit(cache->edit);
- cache->edit = NULL;
- cache->flag &= ~PTCACHE_BAKED;
- }
- }
- else
- cache->flag &= ~PTCACHE_BAKED;
+ ptcache_free_bake(cache);
WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 46f726e45c6..1b7cd4a6d20 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1586,14 +1586,14 @@ int ED_area_header_standardbuttons(const bContext *C, uiBlock *block, int yco)
ICON_DISCLOSURE_TRI_RIGHT,
xco, yco, U.widget_unit, U.widget_unit * 0.9f,
&(sa->flag), 0, 0, 0, 0,
- "Show pulldown menus");
+ TIP_("Show pulldown menus"));
}
else {
but = uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, 0,
ICON_DISCLOSURE_TRI_DOWN,
xco, yco, U.widget_unit, U.widget_unit * 0.9f,
&(sa->flag), 0, 0, 0, 0,
- "Hide pulldown menus");
+ TIP_("Hide pulldown menus"));
}
uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
@@ -1967,11 +1967,11 @@ void ED_region_visible_rect(ARegion *ar, rcti *rect)
if (BLI_rcti_isect(rect, &arn->winrct, NULL)) {
/* overlap left, also check 1 pixel offset (2 regions on one side) */
- if ( ABS(rect->xmin - arn->winrct.xmin) < 2)
+ if (ABS(rect->xmin - arn->winrct.xmin) < 2)
rect->xmin = arn->winrct.xmax;
/* overlap right */
- if ( ABS(rect->xmax - arn->winrct.xmax) < 2)
+ if (ABS(rect->xmax - arn->winrct.xmax) < 2)
rect->xmax = arn->winrct.xmin;
}
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 12a7a33c893..fcd0968d52f 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -206,7 +206,7 @@ int ED_operator_animview_active(bContext *C)
return TRUE;
}
- CTX_wm_operator_poll_msg_set(C, "expected an timeline/animation area to be active");
+ CTX_wm_operator_poll_msg_set(C, "expected a timeline/animation area to be active");
return 0;
}
@@ -3427,8 +3427,8 @@ static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *ev
rcti rect;
int sizex, sizey;
- sizex = 800;
- sizey = 480;
+ sizex = 800 * UI_DPI_WINDOW_FAC;
+ sizey = 480 * UI_DPI_WINDOW_FAC;
/* some magic to calculate postition */
/* pixelsize: mouse coords are in U.pixelsize units :/ */
@@ -3447,8 +3447,8 @@ static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *ev
static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Show/Hide User Preferences";
- ot->description = "Show/hide user preferences";
+ ot->name = "Show User Preferences";
+ ot->description = "Show user preferences";
ot->idname = "SCREEN_OT_userpref_show";
/* api callbacks */
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 1f7fee313b3..9cde62e8302 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -449,13 +449,21 @@ static void screenshot_endjob(void *sjv)
static int screencast_exec(bContext *C, wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
- wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), screen, "Screencast", 0, WM_JOB_TYPE_SCREENCAST);
- ScreenshotJob *sj = MEM_callocN(sizeof(ScreenshotJob), "screenshot job");
+ wmJob *wm_job;
+ ScreenshotJob *sj;
+ /* if called again, stop the running job */
+ if (WM_jobs_test(wm, screen, WM_JOB_TYPE_SCREENCAST))
+ WM_jobs_stop(wm, screen, screenshot_startjob);
+
+ wm_job = WM_jobs_get(wm, win, screen, "Screencast", 0, WM_JOB_TYPE_SCREENCAST);
+ sj = MEM_callocN(sizeof(ScreenshotJob), "screenshot job");
+
/* setup sj */
if (RNA_boolean_get(op->ptr, "full")) {
- wmWindow *win = CTX_wm_window(C);
sj->x = 0;
sj->y = 0;
sj->dumpsx = WM_window_pixels_x(win);
@@ -470,7 +478,7 @@ static int screencast_exec(bContext *C, wmOperator *op)
}
sj->bmain = CTX_data_main(C);
sj->scene = CTX_data_scene(C);
- sj->wm = CTX_wm_manager(C);
+ sj->wm = wm;
BKE_reports_init(&sj->reports, RPT_PRINT);
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index faa9ce00da8..e7c3ddd071b 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -151,12 +151,10 @@ void BRUSH_OT_curve_preset(struct wmOperatorType *ot);
void PAINT_OT_face_select_linked(struct wmOperatorType *ot);
void PAINT_OT_face_select_linked_pick(struct wmOperatorType *ot);
void PAINT_OT_face_select_all(struct wmOperatorType *ot);
-void PAINT_OT_face_select_inverse(struct wmOperatorType *ot);
void PAINT_OT_face_select_hide(struct wmOperatorType *ot);
void PAINT_OT_face_select_reveal(struct wmOperatorType *ot);
void PAINT_OT_vert_select_all(struct wmOperatorType *ot);
-void PAINT_OT_vert_select_inverse(struct wmOperatorType *ot);
int vert_paint_poll(struct bContext *C);
int mask_paint_poll(struct bContext *C);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 3cf67667f39..dffb8c39bf2 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -127,13 +127,14 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
void PAINT_OT_mask_flood_fill(struct wmOperatorType *ot)
{
static EnumPropertyItem mode_items[] = {
- {PAINT_MASK_FLOOD_VALUE, "VALUE", 0, "Value", "Set mask to the level specified by the \"value\" property"},
+ {PAINT_MASK_FLOOD_VALUE, "VALUE", 0, "Value", "Set mask to the level specified by the 'value' property"},
{PAINT_MASK_INVERT, "INVERT", 0, "Invert", "Invert the mask"},
{0}};
/* identifiers */
ot->name = "Mask Flood Fill";
ot->idname = "PAINT_OT_mask_flood_fill";
+ ot->description = "Fill the whole mask with a given value, or invert its values";
/* api callbacks */
ot->exec = mask_flood_fill_exec;
@@ -143,5 +144,6 @@ void PAINT_OT_mask_flood_fill(struct wmOperatorType *ot)
/* rna */
RNA_def_enum(ot->srna, "mode", mode_items, PAINT_MASK_FLOOD_VALUE, "Mode", NULL);
- RNA_def_float(ot->srna, "value", 0, 0, 1, "Value", "Mask level to use when mode is \"Value\"; zero means no masking and one is fully masked", 0, 1);
+ RNA_def_float(ot->srna, "value", 0, 0, 1, "Value",
+ "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", 0, 1);
}
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index ba33ad22f92..7385c2f0cf1 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -485,7 +485,6 @@ void ED_operatortypes_paint(void)
/* vertex selection */
WM_operatortype_append(PAINT_OT_vert_select_all);
- WM_operatortype_append(PAINT_OT_vert_select_inverse);
/* vertex */
WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
@@ -496,7 +495,6 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_face_select_linked);
WM_operatortype_append(PAINT_OT_face_select_linked_pick);
WM_operatortype_append(PAINT_OT_face_select_all);
- WM_operatortype_append(PAINT_OT_face_select_inverse);
WM_operatortype_append(PAINT_OT_face_select_hide);
WM_operatortype_append(PAINT_OT_face_select_reveal);
@@ -748,7 +746,8 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
keymap = WM_keymap_find(keyconf, "Weight Paint Vertex Selection", 0, 0);
keymap->poll = vert_paint_poll;
WM_keymap_add_item(keymap, "PAINT_OT_vert_select_all", AKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PAINT_OT_vert_select_inverse", IKEY, KM_PRESS, KM_CTRL, 0);
+ kmi = WM_keymap_add_item(keymap, "PAINT_OT_vert_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
WM_keymap_add_item(keymap, "VIEW3D_OT_select_border", BKEY, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "deselect", FALSE);
@@ -777,7 +776,8 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
keymap->poll = facemask_paint_poll;
WM_keymap_add_item(keymap, "PAINT_OT_face_select_all", AKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PAINT_OT_face_select_inverse", IKEY, KM_PRESS, KM_CTRL, 0);
+ kmi = WM_keymap_add_item(keymap, "PAINT_OT_face_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
kmi = WM_keymap_add_item(keymap, "PAINT_OT_face_select_hide", HKEY, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "unselected", FALSE);
kmi = WM_keymap_add_item(keymap, "PAINT_OT_face_select_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 4f156276aac..dc3f310b405 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -448,7 +448,7 @@ static int face_select_all_exec(bContext *C, wmOperator *op)
void PAINT_OT_face_select_all(wmOperatorType *ot)
{
- ot->name = "Face Selection";
+ ot->name = "(De)select All";
ot->description = "Change selection for all faces";
ot->idname = "PAINT_OT_face_select_all";
@@ -472,7 +472,7 @@ static int vert_select_all_exec(bContext *C, wmOperator *op)
void PAINT_OT_vert_select_all(wmOperatorType *ot)
{
- ot->name = "Vertex Selection";
+ ot->name = "(De)select All";
ot->description = "Change selection for all vertices";
ot->idname = "PAINT_OT_vert_select_all";
@@ -484,46 +484,6 @@ void PAINT_OT_vert_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
-static int vert_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
- paintvert_deselect_all_visible(ob, SEL_INVERT, TRUE);
- ED_region_tag_redraw(CTX_wm_region(C));
- return OPERATOR_FINISHED;
-}
-
-void PAINT_OT_vert_select_inverse(wmOperatorType *ot)
-{
- ot->name = "Vertex Select Invert";
- ot->description = "Invert selection of vertices";
- ot->idname = "PAINT_OT_vert_select_inverse";
-
- ot->exec = vert_select_inverse_exec;
- ot->poll = vert_paint_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-static int face_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
- paintface_deselect_all_visible(ob, SEL_INVERT, TRUE);
- ED_region_tag_redraw(CTX_wm_region(C));
- return OPERATOR_FINISHED;
-}
-
-
-void PAINT_OT_face_select_inverse(wmOperatorType *ot)
-{
- ot->name = "Face Select Invert";
- ot->description = "Invert selection of faces";
- ot->idname = "PAINT_OT_face_select_inverse";
-
- ot->exec = face_select_inverse_exec;
- ot->poll = facemask_paint_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
static int face_select_hide_exec(bContext *C, wmOperator *op)
{
const int unselected = RNA_boolean_get(op->ptr, "unselected");
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 8ff2a68013c..0277e1e11dc 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -913,7 +913,8 @@ static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc,
BLI_INLINE float wval_blend(const float weight, const float paintval, const float alpha)
{
- return (paintval * alpha) + (weight * (1.0f - alpha));
+ const float talpha = min_ff(alpha, 1.0f); /* blending with values over 1 doesn't make sense */
+ return (paintval * talpha) + (weight * (1.0f - talpha));
}
BLI_INLINE float wval_add(const float weight, const float paintval, const float alpha)
{
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 342671698d2..90e7645032b 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -2281,7 +2281,7 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
sculpt_brush_test_init(ss, &test);
- if (ss->cache->original) {
+ if (ss->cache->original && unode->co) {
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
@@ -3742,7 +3742,8 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
/* not supported yet for multires or dynamic topology */
if (!ss->multires && !ss->bm && !ss->layer_co &&
- (brush->flag & BRUSH_PERSISTENT)) {
+ (brush->flag & BRUSH_PERSISTENT))
+ {
if (!ss->layer_co)
ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert,
"sculpt mesh vertices copy");
@@ -4784,6 +4785,7 @@ static void SCULPT_OT_symmetrize(wmOperatorType *ot)
/* identifiers */
ot->name = "Symmetrize";
ot->idname = "SCULPT_OT_symmetrize";
+ ot->description = "Symmetrize the topology modifications";
/* api callbacks */
ot->exec = sculpt_symmetrize_exec;
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index c828e8c8651..406756f4197 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -567,6 +567,8 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
unode->totvert = totvert;
}
+ else
+ maxgrid = 0;
/* we will use this while sculpting, is mapalloc slow to access then? */
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 935b15f3cd8..16d194d0929 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -37,6 +37,8 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "DNA_brush_types.h"
#include "DNA_ID.h"
#include "DNA_lamp_types.h"
@@ -397,7 +399,7 @@ void uiTemplateTextureUser(uiLayout *layout, bContext *C)
user = ct->user;
if (!user) {
- uiItemL(layout, "No textures in context.", ICON_NONE);
+ uiItemL(layout, IFACE_("No textures in context"), ICON_NONE);
return;
}
diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c
index b2d31ececa5..9409ce42d3a 100644
--- a/source/blender/editors/space_clip/clip_buttons.c
+++ b/source/blender/editors/space_clip/clip_buttons.c
@@ -407,7 +407,7 @@ void uiTemplateMarker(uiLayout *layout, PointerRNA *ptr, const char *propname, P
if (track->flag & TRACK_LOCKED) {
uiLayoutSetActive(layout, FALSE);
block = uiLayoutAbsoluteBlock(layout);
- uiDefBut(block, LABEL, 0, IFACE_("Track is locked"), 0, 0, UI_UNIT_X*15.0f, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, IFACE_("Track is locked"), 0, 0, UI_UNIT_X * 15.0f, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
return;
}
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 77ed197c1d7..ac7ebd9ddac 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -2892,7 +2892,7 @@ void CLIP_OT_set_solver_keyframe(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_enum(ot->srna, "keyframe", keyframe_items, 0, "Keyframe", "keyframe to set");
+ RNA_def_enum(ot->srna, "keyframe", keyframe_items, 0, "Keyframe", "Keyframe to set");
}
/********************** track copy color operator *********************/
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 9349abb4d8b..79a578a86d1 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1178,11 +1178,10 @@ static void file_expand_directory(bContext *C)
get_default_root(sfile->params->dir);
}
/* change "C:" --> "C:\", [#28102] */
- else if ( (isalpha(sfile->params->dir[0]) &&
- (sfile->params->dir[1] == ':')) &&
- (sfile->params->dir[2] == '\0')
-
- ) {
+ else if ((isalpha(sfile->params->dir[0]) &&
+ (sfile->params->dir[1] == ':')) &&
+ (sfile->params->dir[2] == '\0'))
+ {
sfile->params->dir[2] = '\\';
sfile->params->dir[3] = '\0';
}
diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h
index 1b69eb09fce..eea7e0e3837 100644
--- a/source/blender/editors/space_file/fsmenu.h
+++ b/source/blender/editors/space_file/fsmenu.h
@@ -64,7 +64,7 @@ char *fsmenu_get_entry(struct FSMenu *fsmenu, FSMenuCategory category, int index
/** Inserts a new fsmenu entry with the given \a path.
* Duplicate entries are not added.
- * \param sorted Should entry be inserted in sorted order?
+ * \param flag Options for inserting the entry.
*/
void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const char *path, const FSMenuInsert flag);
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index ab16a9d55e6..f1501857b13 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -461,6 +461,7 @@ static void graph_panel_driverVar__singleProp(uiLayout *layout, ID *id, DriverVa
/* Target ID */
row = uiLayoutRow(layout, FALSE);
+ uiLayoutSetRedAlert(row, ((dtar->flag & DTAR_FLAG_INVALID) && !dtar->id));
uiTemplateAnyID(row, &dtar_ptr, "id", "id_type", IFACE_("Prop:"));
/* Target Property */
@@ -470,8 +471,9 @@ static void graph_panel_driverVar__singleProp(uiLayout *layout, ID *id, DriverVa
/* get pointer for resolving the property selected */
RNA_id_pointer_create(dtar->id, &root_ptr);
- col = uiLayoutColumn(layout, TRUE);
/* rna path */
+ col = uiLayoutColumn(layout, TRUE);
+ uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID));
uiTemplatePathBuilder(col, &dtar_ptr, "data_path", &root_ptr, IFACE_("Path"));
}
}
@@ -492,21 +494,23 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *
/* Bone 1 */
col = uiLayoutColumn(layout, TRUE);
+ uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Bone 1:"));
-
+
if (dtar->id && ob1->pose) {
PointerRNA tar_ptr;
-
+
RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
col = uiLayoutColumn(layout, TRUE);
+ uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Bone 2:"));
if (dtar2->id && ob2->pose) {
PointerRNA tar_ptr;
-
+
RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
@@ -515,7 +519,7 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *
/* settings for 'location difference' driver variable type */
static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *dvar)
{
- DriverTarget *dtar = &dvar->targets[0];
+ DriverTarget *dtar = &dvar->targets[0];
DriverTarget *dtar2 = &dvar->targets[1];
Object *ob1 = (Object *)dtar->id;
Object *ob2 = (Object *)dtar2->id;
@@ -523,32 +527,36 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
uiLayout *col;
/* initialize RNA pointer to the target */
- RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
+ RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
/* Bone 1 */
col = uiLayoutColumn(layout, TRUE);
+ uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone 1:"));
if (dtar->id && ob1->pose) {
PointerRNA tar_ptr;
-
+
RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
-
+
+ uiLayoutSetRedAlert(col, false); /* we can clear it again now - it's only needed when creating the ID/Bone fields */
uiItemR(col, &dtar_ptr, "transform_space", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, TRUE);
+ uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Ob/Bone 2:"));
if (dtar2->id && ob2->pose) {
PointerRNA tar_ptr;
-
+
RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
+ uiLayoutSetRedAlert(col, false); /* we can clear it again now - it's only needed when creating the ID/Bone fields */
uiItemR(col, &dtar2_ptr, "transform_space", 0, NULL, ICON_NONE);
}
@@ -565,11 +573,12 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar
/* properties */
col = uiLayoutColumn(layout, TRUE);
+ uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone:"));
if (dtar->id && ob->pose) {
PointerRNA tar_ptr;
-
+
RNA_pointer_create(dtar->id, &RNA_Pose, ob->pose, &tar_ptr);
uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
}
@@ -623,7 +632,7 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
if (driver->type == DRIVER_TYPE_PYTHON) {
/* expression */
uiItemR(col, &driver_ptr, "expression", 0, IFACE_("Expr"), ICON_NONE);
-
+
/* errors? */
if (driver->flag & DRIVER_FLAG_INVALID)
uiItemL(col, IFACE_("ERROR: Invalid Python expression"), ICON_ERROR);
@@ -668,19 +677,19 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
box = uiLayoutBox(col);
/* first row context info for driver */
RNA_pointer_create(ale->id, &RNA_DriverVariable, dvar, &dvar_ptr);
-
+
row = uiLayoutRow(box, FALSE);
block = uiLayoutGetBlock(row);
/* variable name */
uiItemR(row, &dvar_ptr, "name", 0, "", ICON_NONE);
-
+
/* remove button */
uiBlockSetEmboss(block, UI_EMBOSSN);
but = uiDefIconBut(block, BUT, B_IPO_DEPCHANGE, ICON_X, 290, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, IFACE_("Delete target variable"));
uiButSetFunc(but, driver_delete_var_cb, driver, dvar);
uiBlockSetEmboss(block, UI_EMBOSS);
-
+
/* variable type */
row = uiLayoutRow(box, FALSE);
uiItemR(row, &dvar_ptr, "type", 0, "", ICON_NONE);
@@ -721,7 +730,7 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
else {
BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", dvar->curval);
}
-
+
uiItemL(row, valBuf, ICON_NONE);
}
}
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 01364fcacf0..6237958e723 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -82,36 +82,36 @@ static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf,
if (ima == NULL) return;
if (ibuf == NULL) {
- ofs += sprintf(str, "%s", IFACE_("Can't Load Image"));
+ ofs += sprintf(str, IFACE_("Can't Load Image"));
}
else {
if (ima->source == IMA_SRC_MOVIE) {
- ofs += sprintf(str, "%s", IFACE_("Movie"));
+ ofs += sprintf(str, IFACE_("Movie"));
if (ima->anim)
- ofs += sprintf(str + ofs, IFACE_("%d frs"), IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN));
+ ofs += sprintf(str + ofs, IFACE_(" %d frs"), IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN));
}
else
- ofs += sprintf(str, "%s", IFACE_("Image"));
+ ofs += sprintf(str, IFACE_("Image"));
- ofs += sprintf(str + ofs, ": %s %d x %d,", IFACE_("size"), ibuf->x, ibuf->y);
+ ofs += sprintf(str + ofs, IFACE_(": size %d x %d,"), ibuf->x, ibuf->y);
if (ibuf->rect_float) {
if (ibuf->channels != 4) {
- ofs += sprintf(str + ofs, "%d %s", ibuf->channels, IFACE_("float channel(s)"));
+ ofs += sprintf(str + ofs, IFACE_("%d float channel(s)"), ibuf->channels);
}
else if (ibuf->planes == R_IMF_PLANES_RGBA)
- ofs += sprintf(str + ofs, "%s", IFACE_(" RGBA float"));
+ ofs += sprintf(str + ofs, IFACE_(" RGBA float"));
else
- ofs += sprintf(str + ofs, "%s", IFACE_(" RGB float"));
+ ofs += sprintf(str + ofs, IFACE_(" RGB float"));
}
else {
if (ibuf->planes == R_IMF_PLANES_RGBA)
- ofs += sprintf(str + ofs, "%s", IFACE_(" RGBA byte"));
+ ofs += sprintf(str + ofs, IFACE_(" RGBA byte"));
else
- ofs += sprintf(str + ofs, "%s", IFACE_(" RGB byte"));
+ ofs += sprintf(str + ofs, IFACE_(" RGB byte"));
}
if (ibuf->zbuf || ibuf->zbuf_float)
- ofs += sprintf(str + ofs, "%s", IFACE_(" + Z"));
+ ofs += sprintf(str + ofs, IFACE_(" + Z"));
if (ima->source == IMA_SRC_SEQUENCE) {
char *file = BLI_last_slash(ibuf->name);
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index f86e59c41a8..5184b1e1a73 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -87,8 +87,6 @@ void IMAGE_OT_sample(struct wmOperatorType *ot);
void IMAGE_OT_sample_line(struct wmOperatorType *ot);
void IMAGE_OT_curves_point_set(struct wmOperatorType *ot);
-void IMAGE_OT_record_composite(struct wmOperatorType *ot);
-
/* image_panels.c */
struct ImageUser *ntree_get_active_iuser(struct bNodeTree *ntree);
void image_buttons_register(struct ARegionType *art);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index dc834d88323..b913b3528ac 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1959,9 +1959,10 @@ static int image_pack_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)
ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
if (!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
- pup = uiPupMenuBegin(C, "OK", ICON_QUESTION);
+ pup = uiPupMenuBegin(C, IFACE_("OK"), ICON_QUESTION);
layout = uiPupMenuLayout(pup);
- uiItemBooleanO(layout, "Can't pack edited image from disk. Pack as internal PNG?", ICON_NONE, op->idname, "as_png", 1);
+ uiItemBooleanO(layout, IFACE_("Can't pack edited image from disk, pack as internal PNG?"), ICON_NONE,
+ op->idname, "as_png", 1);
uiPupMenuEnd(C, pup);
BKE_image_release_ibuf(ima, ibuf, NULL);
@@ -2438,6 +2439,7 @@ void IMAGE_OT_curves_point_set(wmOperatorType *ot)
RNA_def_enum(ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves");
}
+#if 0 /* Not ported to 2.5x yet */
/******************** record composite operator *********************/
typedef struct RecordCompositeData {
@@ -2589,6 +2591,8 @@ void IMAGE_OT_record_composite(wmOperatorType *ot)
ot->poll = space_image_buffer_exists_poll;
}
+#endif
+
/********************* cycle render slot operator *********************/
static int image_cycle_render_slot_poll(bContext *C)
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index ca8270ba0f5..d82a46e9578 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -253,8 +253,6 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_sample_line);
WM_operatortype_append(IMAGE_OT_curves_point_set);
- WM_operatortype_append(IMAGE_OT_record_composite);
-
WM_operatortype_append(IMAGE_OT_properties);
WM_operatortype_append(IMAGE_OT_scopes);
}
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 22668a3de3a..04f6a5152e6 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -40,9 +40,11 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BKE_bpath.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
+#include "BKE_bpath.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -218,9 +220,9 @@ static int unpack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)
}
if (count == 1)
- strcpy(title, "Unpack 1 file");
+ strcpy(title, IFACE_("Unpack 1 File"));
else
- BLI_snprintf(title, sizeof(title), "Unpack %d files", count);
+ BLI_snprintf(title, sizeof(title), IFACE_("Unpack %d Files"), count);
pup = uiPupMenuBegin(C, title, ICON_NONE);
layout = uiPupMenuLayout(pup);
@@ -291,7 +293,7 @@ static int unpack_item_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event
uiPopupMenu *pup;
uiLayout *layout;
- pup = uiPupMenuBegin(C, "Unpack", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Unpack"), ICON_NONE);
layout = uiPupMenuLayout(pup);
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 5a8a77f7350..976769752f9 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -367,9 +367,9 @@ static void stats_string(Scene *scene)
mmap_in_use = MEM_get_mapped_memory_in_use();
/* get memory statistics */
- s = memstr + sprintf(memstr, " | Mem:%.2fM", (double)((mem_in_use - mmap_in_use) >> 10) / 1024.0);
+ s = memstr + sprintf(memstr, IFACE_(" | Mem:%.2fM"), (double)((mem_in_use - mmap_in_use) >> 10) / 1024.0);
if (mmap_in_use)
- sprintf(s, " (%.2fM)", (double)((mmap_in_use) >> 10) / 1024.0);
+ sprintf(s, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0);
s = stats->infostr;
@@ -377,32 +377,32 @@ static void stats_string(Scene *scene)
if (scene->obedit) {
if (BKE_keyblock_from_object(scene->obedit))
- s += sprintf(s, "(Key) ");
+ s += sprintf(s, IFACE_("(Key) "));
if (scene->obedit->type == OB_MESH) {
- s += sprintf(s, "Verts:%d/%d | Edges:%d/%d | Faces:%d/%d | Tris:%d",
+ s += sprintf(s, IFACE_("Verts:%d/%d | Edges:%d/%d | Faces:%d/%d | Tris:%d"),
stats->totvertsel, stats->totvert, stats->totedgesel, stats->totedge, stats->totfacesel,
stats->totface, stats->tottri);
}
else if (scene->obedit->type == OB_ARMATURE) {
- s += sprintf(s, "Verts:%d/%d | Bones:%d/%d", stats->totvertsel, stats->totvert, stats->totbonesel,
+ s += sprintf(s, IFACE_("Verts:%d/%d | Bones:%d/%d"), stats->totvertsel, stats->totvert, stats->totbonesel,
stats->totbone);
}
else {
- s += sprintf(s, "Verts:%d/%d", stats->totvertsel, stats->totvert);
+ s += sprintf(s, IFACE_("Verts:%d/%d"), stats->totvertsel, stats->totvert);
}
strcat(s, memstr);
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
- s += sprintf(s, "Bones:%d/%d %s",
+ s += sprintf(s, IFACE_("Bones:%d/%d %s"),
stats->totbonesel, stats->totbone, memstr);
}
else if (stats_is_object_dynamic_topology_sculpt(ob)) {
- s += sprintf(s, "Verts:%d | Tris:%d", stats->totvert, stats->tottri);
+ s += sprintf(s, IFACE_("Verts:%d | Tris:%d"), stats->totvert, stats->tottri);
}
else {
- s += sprintf(s, "Verts:%d | Faces:%d | Tris:%d | Objects:%d/%d | Lamps:%d/%d%s",
+ s += sprintf(s, IFACE_("Verts:%d | Faces:%d | Tris:%d | Objects:%d/%d | Lamps:%d/%d%s"),
stats->totvert, stats->totface, stats->tottri, stats->totobjsel, stats->totobj, stats->totlampsel,
stats->totlamp, memstr);
}
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index e2eb1f030b3..31c773e613e 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -311,7 +311,7 @@ static void nla_panel_properties(const bContext *C, Panel *pa)
/* strip extents */
column = uiLayoutColumn(layout, TRUE);
- uiItemL(column, "Strip Extents:", ICON_NONE);
+ uiItemL(column, IFACE_("Strip Extents:"), ICON_NONE);
uiItemR(column, &strip_ptr, "frame_start", 0, NULL, ICON_NONE);
uiItemR(column, &strip_ptr, "frame_end", 0, NULL, ICON_NONE);
@@ -346,7 +346,7 @@ static void nla_panel_properties(const bContext *C, Panel *pa)
/* settings */
column = uiLayoutColumn(layout, TRUE);
uiLayoutSetActive(column, !(RNA_boolean_get(&strip_ptr, "use_animated_influence") || RNA_boolean_get(&strip_ptr, "use_animated_time")));
- uiItemL(column, "Playback Settings:", ICON_NONE);
+ uiItemL(column, IFACE_("Playback Settings:"), ICON_NONE);
uiItemR(column, &strip_ptr, "mute", 0, NULL, ICON_NONE);
uiItemR(column, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE);
}
@@ -376,15 +376,15 @@ static void nla_panel_actclip(const bContext *C, Panel *pa)
/* action extents */
// XXX custom names were used here (to avoid the prefixes)... probably not necessary in future?
column = uiLayoutColumn(layout, TRUE);
- uiItemL(column, "Action Extents:", ICON_NONE);
- uiItemR(column, &strip_ptr, "action_frame_start", 0, "Start Frame", ICON_NONE);
- uiItemR(column, &strip_ptr, "action_frame_end", 0, "End Frame", ICON_NONE);
+ uiItemL(column, IFACE_("Action Extents:"), ICON_NONE);
+ uiItemR(column, &strip_ptr, "action_frame_start", 0, IFACE_("Start Frame"), ICON_NONE);
+ uiItemR(column, &strip_ptr, "action_frame_end", 0, IFACE_("End Frame"), ICON_NONE);
uiItemO(column, NULL, ICON_NONE, "NLA_OT_action_sync_length");
/* action usage */
column = uiLayoutColumn(layout, TRUE);
uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_animated_time") == FALSE);
- uiItemL(column, "Playback Settings:", ICON_NONE);
+ uiItemL(column, IFACE_("Playback Settings:"), ICON_NONE);
uiItemR(column, &strip_ptr, "scale", 0, NULL, ICON_NONE);
uiItemR(column, &strip_ptr, "repeat", 0, NULL, ICON_NONE);
}
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 3740c3fae5e..484eb47fa8e 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -44,6 +44,8 @@
#include "BLI_rand.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "BKE_action.h"
#include "BKE_fcurve.h"
#include "BKE_nla.h"
@@ -1951,7 +1953,7 @@ static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent
uiLayout *layout;
int i;
- pup = uiPupMenuBegin(C, "Add F-Modifier", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Add F-Modifier"), ICON_NONE);
layout = uiPupMenuLayout(pup);
/* start from 1 to skip the 'Invalid' modifier type */
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index b211bca4c0a..8a2e03f2660 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -1131,8 +1131,8 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
/* skip if out of view */
if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax ||
- node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax) {
-
+ node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax)
+ {
uiEndBlock(C, node->block);
node->block = NULL;
return;
@@ -1608,12 +1608,15 @@ static void node_composit_buts_image_details(uiLayout *layout, bContext *C, Poin
node_composit_buts_image(layout, C, ptr);
+ uiItemR(layout, ptr, "use_straight_alpha_output", 0, NULL, 0);
+
if (!node->id)
return;
imaptr = RNA_pointer_get(ptr, "image");
uiTemplateColorspaceSettings(layout, &imaptr, "colorspace_settings");
+ uiItemR(layout, &imaptr, "alpha_mode", 0, NULL, 0);
}
static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 22631568d03..4943bb45113 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -307,6 +307,7 @@ void NODE_OT_add_reroute(wmOperatorType *ot)
ot->name = "Add Reroute";
ot->idname = "NODE_OT_add_reroute";
+ ot->description = "Add a reroute node";
ot->invoke = WM_gesture_lines_invoke;
ot->modal = WM_gesture_lines_modal;
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 943f12c4c54..7b7b98f132c 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -42,6 +42,8 @@
#include "BLI_rect.h"
#include "BLI_math.h"
+#include "BLF_translation.h"
+
#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
@@ -789,7 +791,7 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
static int node_group_separate_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
{
- uiPopupMenu *pup = uiPupMenuBegin(C, "Separate", ICON_NONE);
+ uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Separate"), ICON_NONE);
uiLayout *layout = uiPupMenuLayout(pup);
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
@@ -1148,7 +1150,7 @@ static int node_group_make_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *act = nodeGetActive(snode->edittree);
- uiPopupMenu *pup = uiPupMenuBegin(C, "Make Group", ICON_NONE);
+ uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Make Group"), ICON_NONE);
uiLayout *layout = uiPupMenuLayout(pup);
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 303782f3fbd..cd04c8c6bd1 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -389,7 +389,7 @@ static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElemen
/* link to scene */
base = MEM_callocN(sizeof(Base), "add_base");
BLI_addhead(&scene->base, base);
- base->lay = (1 << 20) - 1; /*v3d->lay;*/ /* would be nice to use the 3d layer but the include's not here */
+ base->lay = gob->ob->lay;
gob->ob->flag |= SELECT;
base->flag = gob->ob->flag;
base->object = gob->ob;
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 29a6a1f6d50..78a76532487 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -126,23 +126,50 @@ static void sequencer_generic_invoke_path__internal(bContext *C, wmOperator *op,
}
}
-static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, wmEvent *event, int flag)
+static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type)
{
- View2D *v2d = UI_view2d_fromcontext(C);
-
- float mval_v2d[2];
+ Sequence *tgt = NULL;
+ Sequence *seq;
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, TRUE);
+ int cfra = (int) CFRA;
+ int proximity = INT_MAX;
+
+ if (!ed || !ed->seqbasep) {
+ return 1;
+ }
+
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if ((type == -1 || seq->type == type) &&
+ (seq->enddisp < cfra) &&
+ (cfra - seq->enddisp < proximity))
+ {
+ tgt = seq;
+ proximity = cfra - seq->enddisp;
+ }
+ }
- UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mval_v2d[0], &mval_v2d[1]);
+ if (tgt) {
+ return tgt->machine;
+ }
+ return 1;
+}
+static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, int flag, int type)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ int cfra = (int) CFRA;
+
/* effect strips don't need a channel initialized from the mouse */
if (!(flag & SEQPROP_NOCHAN)) {
- RNA_int_set(op->ptr, "channel", (int)mval_v2d[1] + 0.5f);
+ RNA_int_set(op->ptr, "channel", sequencer_generic_invoke_xy_guess_channel(C, type));
}
- RNA_int_set(op->ptr, "frame_start", (int)mval_v2d[0]);
+ RNA_int_set(op->ptr, "frame_start", cfra);
if ((flag & SEQPROP_ENDFRAME) && RNA_struct_property_is_set(op->ptr, "frame_end") == 0)
- RNA_int_set(op->ptr, "frame_end", (int)mval_v2d[0] + 25); // XXX arbitary but ok for now.
+ RNA_int_set(op->ptr, "frame_end", cfra + 25); // XXX arbitary but ok for now.
if (!(flag & SEQPROP_NOPATHS)) {
sequencer_generic_invoke_path__internal(C, op, "filepath");
@@ -277,7 +304,7 @@ static int sequencer_add_scene_strip_invoke(bContext *C, wmOperator *op, wmEvent
if (!RNA_struct_property_is_set(op->ptr, "scene"))
return WM_enum_search_invoke(C, op, event);
- sequencer_generic_invoke_xy__internal(C, op, event, 0);
+ sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_SCENE);
return sequencer_add_scene_strip_exec(C, op);
// needs a menu
// return WM_menu_invoke(C, op, event);
@@ -375,7 +402,7 @@ static int sequencer_add_movieclip_strip_invoke(bContext *C, wmOperator *op, wmE
if (!RNA_struct_property_is_set(op->ptr, "clip"))
return WM_enum_search_invoke(C, op, event);
- sequencer_generic_invoke_xy__internal(C, op, event, 0);
+ sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MOVIECLIP);
return sequencer_add_movieclip_strip_exec(C, op);
// needs a menu
// return WM_menu_invoke(C, op, event);
@@ -472,7 +499,7 @@ static int sequencer_add_mask_strip_invoke(bContext *C, wmOperator *op, wmEvent
if (!RNA_struct_property_is_set(op->ptr, "mask"))
return WM_enum_search_invoke(C, op, event);
- sequencer_generic_invoke_xy__internal(C, op, event, 0);
+ sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MASK);
return sequencer_add_mask_strip_exec(C, op);
// needs a menu
// return WM_menu_invoke(C, op, event);
@@ -575,7 +602,7 @@ static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
}
-static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
{
if (!ED_operator_sequencer_active(C)) {
@@ -587,11 +614,11 @@ static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, wmEvent
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath"))
{
- sequencer_generic_invoke_xy__internal(C, op, event, SEQPROP_NOPATHS);
+ sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_MOVIE);
return sequencer_add_movie_strip_exec(C, op);
}
- sequencer_generic_invoke_xy__internal(C, op, event, 0);
+ sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MOVIE);
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -630,7 +657,7 @@ static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op)
return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_sound_strip);
}
-static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
{
if (!ED_operator_sequencer_active(C)) {
@@ -642,11 +669,11 @@ static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, wmEvent
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath"))
{
- sequencer_generic_invoke_xy__internal(C, op, event, SEQPROP_NOPATHS);
+ sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_SOUND_RAM);
return sequencer_add_sound_strip_exec(C, op);
}
- sequencer_generic_invoke_xy__internal(C, op, event, 0);
+ sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_SOUND_RAM);
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -742,7 +769,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
{
if (!ED_operator_sequencer_active(C)) {
@@ -753,11 +780,11 @@ static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, wmEvent
/* drag drop has set the names */
if (RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) {
- sequencer_generic_invoke_xy__internal(C, op, event, SEQPROP_ENDFRAME | SEQPROP_NOPATHS);
+ sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME | SEQPROP_NOPATHS, SEQ_TYPE_IMAGE);
return sequencer_add_image_strip_exec(C, op);
}
- sequencer_generic_invoke_xy__internal(C, op, event, SEQPROP_ENDFRAME);
+ sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME, SEQ_TYPE_IMAGE);
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -894,7 +921,7 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
/* add color */
-static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
{
short is_type_set = RNA_struct_property_is_set(op->ptr, "type");
int type = -1;
@@ -917,7 +944,7 @@ static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, wmEven
}
}
- sequencer_generic_invoke_xy__internal(C, op, event, prop_flag);
+ sequencer_generic_invoke_xy__internal(C, op, prop_flag, type);
return sequencer_add_effect_strip_exec(C, op);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 249ba986fd3..396878cbfeb 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -1059,8 +1059,10 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ibuf->x, ibuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, display_buffer);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ if (sseq->flag & SEQ_USE_ALPHA) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
glBegin(GL_QUADS);
@@ -1093,7 +1095,8 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
glEnd();
glBindTexture(GL_TEXTURE_2D, last_texid);
glDisable(GL_TEXTURE_2D);
- glDisable(GL_BLEND);
+ if (sseq->flag & SEQ_USE_ALPHA)
+ glDisable(GL_BLEND);
glDeleteTextures(1, &texid);
if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index d541e1d6c07..4c6b909882c 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -120,7 +120,7 @@ static SpaceLink *sequencer_new(const bContext *C)
sseq->chanshown = 0;
sseq->view = SEQ_VIEW_SEQUENCE;
sseq->mainb = SEQ_DRAW_IMG_IMBUF;
- sseq->flag = SEQ_SHOW_GPENCIL;
+ sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA;
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for sequencer");
diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c
index a8c2de193c4..3c7897200ed 100644
--- a/source/blender/editors/space_text/text_format.c
+++ b/source/blender/editors/space_text/text_format.c
@@ -157,7 +157,7 @@ void text_format_fill(const char **str_p, char **fmt_p, const char type, const i
*fmt++ = type;
str += size;
- i += size;
+ i += 1;
}
str--;
diff --git a/source/blender/editors/space_text/text_header.c b/source/blender/editors/space_text/text_header.c
index 52253b2d5d2..605a08e587a 100644
--- a/source/blender/editors/space_text/text_header.c
+++ b/source/blender/editors/space_text/text_header.c
@@ -42,6 +42,8 @@
#include "BLI_blenlib.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_screen.h"
@@ -120,7 +122,7 @@ void TEXT_OT_properties(wmOperatorType *ot)
uiPopupMenu *pup;
if (text) {
- pup = uiPupMenuBegin(C, "Text", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Text"), ICON_NONE);
if (txt_has_sel(text)) {
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_cut");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_copy");
@@ -134,7 +136,7 @@ void TEXT_OT_properties(wmOperatorType *ot)
uiPupMenuEnd(C, pup);
}
else {
- pup = uiPupMenuBegin(C, "File", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("File"), ICON_NONE);
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open");
uiPupMenuEnd(C, pup);
@@ -146,7 +148,7 @@ void TEXT_OT_properties(wmOperatorType *ot)
uiPopupMenu *pup;
- pup = uiPupMenuBegin(C, "Edit", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Edit"), ICON_NONE);
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_cut");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_copy");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_paste");
@@ -159,7 +161,7 @@ void TEXT_OT_properties(wmOperatorType *ot)
uiPopupMenu *pup;
if (text) {
- pup = uiPupMenuBegin(C, "Text", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Text"), ICON_NONE);
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save");
@@ -168,7 +170,7 @@ void TEXT_OT_properties(wmOperatorType *ot)
uiPupMenuEnd(C, pup);
}
else {
- pup = uiPupMenuBegin(C, "File", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("File"), ICON_NONE);
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open");
uiPupMenuEnd(C, pup);
@@ -180,11 +182,14 @@ void TEXT_OT_properties(wmOperatorType *ot)
uiPopupMenu *pup;
- pup = uiPupMenuBegin(C, "Text", ICON_NONE);
- uiItemEnumO(layout, "TEXT_OT_move", "Top of File", 0, "type", FILE_TOP);
- uiItemEnumO(layout, "TEXT_OT_move", "Bottom of File", 0, "type", FILE_BOTTOM);
- uiItemEnumO(layout, "TEXT_OT_move", "Page Up", 0, "type", PREV_PAGE);
- uiItemEnumO(layout, "TEXT_OT_move", "Page Down", 0, "type", NEXT_PAGE);
+ pup = uiPupMenuBegin(C, IFACE_("Text"), ICON_NONE);
+ uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Top of File"),
+ 0, "type", FILE_TOP);
+ uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Bottom of File"),
+ 0, "type", FILE_BOTTOM);
+ uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Page Up"), 0, "type", PREV_PAGE);
+ uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Page Down"),
+ 0, "type", NEXT_PAGE);
uiPupMenuEnd(C, pup);
}
#endif
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 9b5d453d8a3..b45961bff11 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -3110,27 +3110,31 @@ static int text_resolve_conflict_invoke(bContext *C, wmOperator *op, wmEvent *UN
case 1:
if (text->flags & TXT_ISDIRTY) {
/* modified locally and externally, ahhh. offer more possibilites. */
- pup = uiPupMenuBegin(C, "File Modified Outside and Inside Blender", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("File Modified Outside and Inside Blender"), ICON_NONE);
layout = uiPupMenuLayout(pup);
- uiItemEnumO_ptr(layout, op->type, "Reload from disk (ignore local changes)", 0, "resolution", RESOLVE_RELOAD);
- uiItemEnumO_ptr(layout, op->type, "Save to disk (ignore outside changes)", 0, "resolution", RESOLVE_SAVE);
- uiItemEnumO_ptr(layout, op->type, "Make text internal (separate copy)", 0, "resolution", RESOLVE_MAKE_INTERNAL);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Reload from disk (ignore local changes)"),
+ 0, "resolution", RESOLVE_RELOAD);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Save to disk (ignore outside changes)"),
+ 0, "resolution", RESOLVE_SAVE);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Make text internal (separate copy)"),
+ 0, "resolution", RESOLVE_MAKE_INTERNAL);
uiPupMenuEnd(C, pup);
}
else {
- pup = uiPupMenuBegin(C, "File Modified Outside Blender", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("File Modified Outside Blender"), ICON_NONE);
layout = uiPupMenuLayout(pup);
- uiItemEnumO_ptr(layout, op->type, "Reload from disk", 0, "resolution", RESOLVE_RELOAD);
- uiItemEnumO_ptr(layout, op->type, "Make text internal (separate copy)", 0, "resolution", RESOLVE_MAKE_INTERNAL);
- uiItemEnumO_ptr(layout, op->type, "Ignore", 0, "resolution", RESOLVE_IGNORE);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Reload from disk"), 0, "resolution", RESOLVE_RELOAD);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Make text internal (separate copy)"),
+ 0, "resolution", RESOLVE_MAKE_INTERNAL);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Ignore"), 0, "resolution", RESOLVE_IGNORE);
uiPupMenuEnd(C, pup);
}
break;
case 2:
- pup = uiPupMenuBegin(C, "File Deleted Outside Blender", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("File Deleted Outside Blender"), ICON_NONE);
layout = uiPupMenuLayout(pup);
- uiItemEnumO_ptr(layout, op->type, "Make text internal", 0, "resolution", RESOLVE_MAKE_INTERNAL);
- uiItemEnumO_ptr(layout, op->type, "Recreate file", 0, "resolution", RESOLVE_SAVE);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Make text internal"), 0, "resolution", RESOLVE_MAKE_INTERNAL);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Recreate file"), 0, "resolution", RESOLVE_SAVE);
uiPupMenuEnd(C, pup);
break;
}
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index fc8d5d26455..32d961ab64c 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -623,16 +623,17 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
if ((dflag & DRAW_CONSTCOLOR) == 0) {
glColor3ubv(ob_wire_col);
-
- /* Calculate the outline vertex positions */
- glBegin(GL_LINE_LOOP);
- glVertex2f(ofs_x, ofs_y);
- glVertex2f(ofs_x + ima_x, ofs_y);
- glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
- glVertex2f(ofs_x, ofs_y + ima_y);
- glEnd();
}
+ /* Calculate the outline vertex positions */
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(ofs_x, ofs_y);
+ glVertex2f(ofs_x + ima_x, ofs_y);
+ glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
+ glVertex2f(ofs_x, ofs_y + ima_y);
+ glEnd();
+
+
/* Reset GL settings */
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 658196a1bd4..57755231240 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -513,20 +513,34 @@ static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUS
return 0;
}
-
static int view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
{
- if (ED_view3d_give_base_under_cursor(C, event->mval) ) {
- return 0;
+ if (event->ctrl)
+ return false;
+
+ if (!ED_view3d_give_base_under_cursor(C, event->mval)) {
+ return view3d_ima_drop_poll(C, drag, event);
}
- return view3d_ima_drop_poll(C, drag, event);
+ return 0;
}
-static int view3d_ima_ob_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
{
- if (ED_view3d_give_base_under_cursor(C, event->mval) ) {
+ Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
+
+ /* either holding and ctrl and no object, or dropping to empty */
+ if ((event->ctrl && !base) || (base && base->object->type == OB_EMPTY))
+ return view3d_ima_drop_poll(C, drag, event);
+
+ return 0;
+}
+
+static int view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+{
+ Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
+
+ if (base && base->object->type == OB_MESH)
return view3d_ima_drop_poll(C, drag, event);
- }
return 0;
}
@@ -570,7 +584,8 @@ static void view3d_dropboxes(void)
WM_dropbox_add(lb, "OBJECT_OT_add_named", view3d_ob_drop_poll, view3d_ob_drop_copy);
WM_dropbox_add(lb, "OBJECT_OT_drop_named_material", view3d_mat_drop_poll, view3d_id_drop_copy);
- WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_ob_drop_poll, view3d_id_path_drop_copy);
+ WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_mesh_drop_poll, view3d_id_path_drop_copy);
+ WM_dropbox_add(lb, "OBJECT_OT_drop_named_image", view3d_ima_empty_drop_poll, view3d_id_path_drop_copy);
WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll, view3d_id_path_drop_copy);
WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy);
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 30ed7a57f9d..5f54f0dcfc8 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -996,12 +996,12 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
/* NDOF utility functions
* (should these functions live in this file?)
*/
-float ndof_to_axis_angle(struct wmNDOFMotionData *ndof, float axis[3])
+float ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3])
{
return ndof->dt * normalize_v3_v3(axis, ndof->rvec);
}
-void ndof_to_quat(struct wmNDOFMotionData *ndof, float q[4])
+void ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4])
{
float axis[3];
float angle;
@@ -1010,6 +1010,84 @@ void ndof_to_quat(struct wmNDOFMotionData *ndof, float q[4])
axis_angle_to_quat(q, axis, angle);
}
+static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, RegionView3D *rv3d, const float view_inv[4],
+ const float rot_sensitivity, const float dt,
+ /* optional, can be NULL*/
+ ViewOpsData *vod)
+{
+ if (U.ndof_flag & NDOF_TURNTABLE) {
+
+ /* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
+ float angle, rot[4];
+ float xvec[3] = {1, 0, 0};
+
+ /* Determine the direction of the x vector (for rotating up and down) */
+ mul_qt_v3(view_inv, xvec);
+
+ /* Perform the up/down rotation */
+ angle = rot_sensitivity * dt * ndof->rx;
+ if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
+ angle = -angle;
+ rot[0] = cosf(angle);
+ mul_v3_v3fl(rot + 1, xvec, sin(angle));
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
+
+ /* Perform the orbital rotation */
+ angle = rot_sensitivity * dt * ndof->ry;
+ if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
+ angle = -angle;
+
+ /* update the onscreen doo-dad */
+ rv3d->rot_angle = angle;
+ rv3d->rot_axis[0] = 0;
+ rv3d->rot_axis[1] = 0;
+ rv3d->rot_axis[2] = 1;
+
+ rot[0] = cosf(angle);
+ rot[1] = rot[2] = 0.0;
+ rot[3] = sinf(angle);
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
+
+ }
+ else {
+ float rot[4];
+ float axis[3];
+ float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
+
+ if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS) axis[2] = -axis[2];
+ if (U.ndof_flag & NDOF_TILT_INVERT_AXIS) axis[0] = -axis[0];
+ if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS) axis[1] = -axis[1];
+
+
+ /* transform rotation axis from view to world coordinates */
+ mul_qt_v3(view_inv, axis);
+
+ /* update the onscreen doo-dad */
+ rv3d->rot_angle = angle;
+ copy_v3_v3(rv3d->rot_axis, axis);
+
+ axis_angle_to_quat(rot, axis, angle);
+
+ /* apply rotation */
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
+ }
+
+ /* rotate around custom center */
+ if (vod && vod->use_dyn_ofs) {
+ float q1[4];
+
+ /* compute the post multiplication quat, to rotate the offset correctly */
+ conjugate_qt_qt(q1, vod->oldquat);
+ mul_qt_qtqt(q1, q1, rv3d->viewquat);
+
+ conjugate_qt(q1); /* conj == inv for unit quat */
+ copy_v3_v3(rv3d->ofs, vod->ofs);
+ sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
+ mul_qt_v3(q1, rv3d->ofs);
+ add_v3_v3(rv3d->ofs, vod->dyn_ofs);
+ }
+}
+
/* -- "orbit" navigation (trackball/turntable)
* -- zooming
* -- panning in rotationally-locked views
@@ -1065,86 +1143,8 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
if (has_rotation) {
-
rv3d->view = RV3D_VIEW_USER;
-
- if (U.ndof_flag & NDOF_TURNTABLE) {
-
- /* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
- float angle, rot[4];
- float xvec[3] = {1, 0, 0};
-
- /* Determine the direction of the x vector (for rotating up and down) */
- mul_qt_v3(view_inv, xvec);
-
- /* Perform the up/down rotation */
- angle = rot_sensitivity * dt * ndof->rx;
- if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
- angle = -angle;
- rot[0] = cos(angle);
- mul_v3_v3fl(rot + 1, xvec, sin(angle));
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- /* Perform the orbital rotation */
- angle = rot_sensitivity * dt * ndof->ry;
- if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
- angle = -angle;
-
- /* update the onscreen doo-dad */
- rv3d->rot_angle = angle;
- rv3d->rot_axis[0] = 0;
- rv3d->rot_axis[1] = 0;
- rv3d->rot_axis[2] = 1;
-
- rot[0] = cos(angle);
- rot[1] = rot[2] = 0.0;
- rot[3] = sin(angle);
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- }
- else {
- float rot[4];
- float axis[3];
- float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
-
- if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS)
- axis[2] = -axis[2];
-
- if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
- axis[0] = -axis[0];
-
- if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
- axis[1] = -axis[1];
-
-
- /* transform rotation axis from view to world coordinates */
- mul_qt_v3(view_inv, axis);
-
- /* update the onscreen doo-dad */
- rv3d->rot_angle = angle;
- copy_v3_v3(rv3d->rot_axis, axis);
-
- axis_angle_to_quat(rot, axis, angle);
-
- /* apply rotation */
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- }
-
- /* rotate around custom center */
- if (vod && vod->use_dyn_ofs) {
- float q1[4];
-
- /* compute the post multiplication quat, to rotate the offset correctly */
- conjugate_qt_qt(q1, vod->oldquat);
- mul_qt_qtqt(q1, q1, rv3d->viewquat);
-
- conjugate_qt(q1); /* conj == inv for unit quat */
- copy_v3_v3(rv3d->ofs, vod->ofs);
- sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
- mul_qt_v3(q1, rv3d->ofs);
- add_v3_v3(rv3d->ofs, vod->dyn_ofs);
- }
+ view3d_ndof_orbit(ndof, rv3d, view_inv, rot_sensitivity, dt, vod);
}
}
@@ -1239,86 +1239,8 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
if (has_rotation) {
-
rv3d->view = RV3D_VIEW_USER;
-
- if (U.ndof_flag & NDOF_TURNTABLE) {
-
- /* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
- float angle, rot[4];
- float xvec[3] = {1, 0, 0};
-
- /* Determine the direction of the x vector (for rotating up and down) */
- mul_qt_v3(view_inv, xvec);
-
- /* Perform the up/down rotation */
- angle = rot_sensitivity * dt * ndof->rx;
- if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
- angle = -angle;
- rot[0] = cos(angle);
- mul_v3_v3fl(rot + 1, xvec, sin(angle));
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- /* Perform the orbital rotation */
- angle = rot_sensitivity * dt * ndof->ry;
- if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
- angle = -angle;
-
- /* update the onscreen doo-dad */
- rv3d->rot_angle = angle;
- rv3d->rot_axis[0] = 0;
- rv3d->rot_axis[1] = 0;
- rv3d->rot_axis[2] = 1;
-
- rot[0] = cos(angle);
- rot[1] = rot[2] = 0.0;
- rot[3] = sin(angle);
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- }
- else {
- float rot[4];
- float axis[3];
- float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
-
- if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS)
- axis[2] = -axis[2];
-
- if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
- axis[0] = -axis[0];
-
- if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
- axis[1] = -axis[1];
-
-
- /* transform rotation axis from view to world coordinates */
- mul_qt_v3(view_inv, axis);
-
- /* update the onscreen doo-dad */
- rv3d->rot_angle = angle;
- copy_v3_v3(rv3d->rot_axis, axis);
-
- axis_angle_to_quat(rot, axis, angle);
-
- /* apply rotation */
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- }
-
- /* rotate around custom center */
- if (vod && vod->use_dyn_ofs) {
- float q1[4];
-
- /* compute the post multiplication quat, to rotate the offset correctly */
- conjugate_qt_qt(q1, vod->oldquat);
- mul_qt_qtqt(q1, q1, rv3d->viewquat);
-
- conjugate_qt(q1); /* conj == inv for unit quat */
- copy_v3_v3(rv3d->ofs, vod->ofs);
- sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
- mul_qt_v3(q1, rv3d->ofs);
- add_v3_v3(rv3d->ofs, vod->dyn_ofs);
- }
+ view3d_ndof_orbit(ndof, rv3d, view_inv, rot_sensitivity, dt, vod);
}
}
@@ -1502,84 +1424,8 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
/* move center of view opposite of hand motion (this is camera mode, not object mode) */
sub_v3_v3(rv3d->ofs, pan_vec);
-
- if (U.ndof_flag & NDOF_TURNTABLE) {
- /* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
- float angle, rot[4];
- float xvec[3] = {1, 0, 0};
-
- /* Determine the direction of the x vector (for rotating up and down) */
- mul_qt_v3(view_inv, xvec);
-
- /* Perform the up/down rotation */
- angle = rot_sensitivity * dt * ndof->rx;
- if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
- angle = -angle;
- rot[0] = cos(angle);
- mul_v3_v3fl(rot + 1, xvec, sin(angle));
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- /* Perform the orbital rotation */
- angle = rot_sensitivity * dt * ndof->ry;
- if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
- angle = -angle;
-
- /* update the onscreen doo-dad */
- rv3d->rot_angle = angle;
- rv3d->rot_axis[0] = 0;
- rv3d->rot_axis[1] = 0;
- rv3d->rot_axis[2] = 1;
-
- rot[0] = cos(angle);
- rot[1] = rot[2] = 0.0;
- rot[3] = sin(angle);
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- }
- else {
-
- float rot[4];
- float axis[3];
- float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
-
- if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS)
- axis[2] = -axis[2];
-
- if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
- axis[0] = -axis[0];
-
- if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
- axis[1] = -axis[1];
-
- /* transform rotation axis from view to world coordinates */
- mul_qt_v3(view_inv, axis);
-
- /* update the onscreen doo-dad */
- rv3d->rot_angle = angle;
- copy_v3_v3(rv3d->rot_axis, axis);
-
- axis_angle_to_quat(rot, axis, angle);
-
- /* apply rotation */
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- }
-
- /* rotate around custom center */
- if (vod->use_dyn_ofs) {
- float q1[4];
-
- /* compute the post multiplication quat, to rotate the offset correctly */
- conjugate_qt_qt(q1, vod->oldquat);
- mul_qt_qtqt(q1, q1, rv3d->viewquat);
-
- conjugate_qt(q1); /* conj == inv for unit quat */
- copy_v3_v3(rv3d->ofs, vod->ofs);
- sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
- mul_qt_v3(q1, rv3d->ofs);
- add_v3_v3(rv3d->ofs, vod->dyn_ofs);
- }
+ view3d_ndof_orbit(ndof, rv3d, view_inv, rot_sensitivity, dt, vod);
}
viewops_data_free(C, op);
@@ -3699,7 +3545,9 @@ static int background_image_add_invoke(bContext *C, wmOperator *op, wmEvent *UNU
void VIEW3D_OT_background_image_add(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Background Image";
+ /* note: having key shortcut here is bad practice,
+ * but for now keep because this displays when dragging an image over the 3D viewport */
+ ot->name = "Add Background Image (Ctrl for Empty Object)";
ot->description = "Add a new background image";
ot->idname = "VIEW3D_OT_background_image_add";
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 2b30e4e6b81..e078fa8eda1 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -400,13 +400,13 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
block = uiLayoutGetBlock(row);
uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL,
0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
- "Vertex select - Shift-Click for multiple modes");
+ TIP_("Vertex select - Shift-Click for multiple modes"));
uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL,
0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
- "Edge select - Shift-Click for multiple modes, Ctrl-Click expands selection");
+ TIP_("Edge select - Shift-Click for multiple modes, Ctrl-Click expands selection"));
uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL,
0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
- "Face select - Shift-Click for multiple modes, Ctrl-Click expands selection");
+ TIP_("Face select - Shift-Click for multiple modes, Ctrl-Click expands selection"));
}
}
@@ -453,6 +453,13 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
if (obedit == NULL && is_paint) {
+
+ if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ /* Only for Weight Paint. makes no sense in other paint modes. */
+ row = uiLayoutRow(layout, TRUE);
+ uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ }
+
/* Manipulators aren't used in paint modes */
if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT)) {
/* masks aren't used for sculpt and particle painting */
@@ -476,7 +483,9 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
/* pose/object only however we want to allow in weight paint mode too
- * so don't be totally strict and just check not-editmode for now */
+ * so don't be totally strict and just check not-editmode for now
+ * XXX We never get here when we are in Weight Paint mode
+ */
if (obedit == NULL) {
uiItemR(row, &v3dptr, "use_pivot_point_align", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
}
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index c8f0fe44433..d4cfa9076a6 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -101,8 +101,8 @@ void VIEW3D_OT_clear_render_border(struct wmOperatorType *ot);
void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
void view3d_boxview_copy(ScrArea *sa, ARegion *ar);
-void ndof_to_quat(struct wmNDOFMotionData *ndof, float q[4]);
-float ndof_to_axis_angle(struct wmNDOFMotionData *ndof, float axis[3]);
+void ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]);
+float ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]);
/* view3d_fly.c */
void view3d_keymap(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index c428cb02236..bc1656ff7c6 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -43,6 +43,7 @@
#include "ED_view3d.h" /* own include */
#define BL_NEAR_CLIP 0.001
+#define BL_ZERO_CLIP 0.001
/* Non Clipping Projection Functions
* ********************************* */
@@ -134,18 +135,25 @@ static eV3DProjStatus ed_view3d_project__internal(ARegion *ar,
vec4[3] = 1.0;
mul_m4_v4(perspmat, vec4);
- if (((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) || (vec4[3] > (float)BL_NEAR_CLIP)) {
- const float scalar = (vec4[3] != 0.0f) ? (1.0f / vec4[3]): 0.0f;
- const float fx = ((float)ar->winx / 2.0f) * (1.0f + (vec4[0] * scalar));
- if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fx > 0.0f && fx < (float)ar->winx)) {
- const float fy = ((float)ar->winy / 2.0f) * (1.0f + (vec4[1] * scalar));
- if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fy > 0.0f && fy < (float)ar->winy)) {
- r_co[0] = floorf(fx);
- r_co[1] = floorf(fy);
-
- /* check if the point is behind the view, we need to flip in this case */
- if (UNLIKELY((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) && (vec4[3] < 0.0f)) {
- negate_v2(r_co);
+
+
+ if (((flag & V3D_PROJ_TEST_CLIP_ZERO) == 0) || (fabsf(vec4[3]) > (float)BL_ZERO_CLIP)) {
+ if (((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) || (vec4[3] > (float)BL_NEAR_CLIP)) {
+ const float scalar = (vec4[3] != 0.0f) ? (1.0f / vec4[3]): 0.0f;
+ const float fx = ((float)ar->winx / 2.0f) * (1.0f + (vec4[0] * scalar));
+ if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fx > 0.0f && fx < (float)ar->winx)) {
+ const float fy = ((float)ar->winy / 2.0f) * (1.0f + (vec4[1] * scalar));
+ if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fy > 0.0f && fy < (float)ar->winy)) {
+ r_co[0] = floorf(fx);
+ r_co[1] = floorf(fy);
+
+ /* check if the point is behind the view, we need to flip in this case */
+ if (UNLIKELY((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) && (vec4[3] < 0.0f)) {
+ negate_v2(r_co);
+ }
+ }
+ else {
+ return V3D_PROJ_RET_CLIP_WIN;
}
}
else {
@@ -153,11 +161,11 @@ static eV3DProjStatus ed_view3d_project__internal(ARegion *ar,
}
}
else {
- return V3D_PROJ_RET_CLIP_WIN;
+ return V3D_PROJ_RET_CLIP_NEAR;
}
}
else {
- return V3D_PROJ_RET_CLIP_NEAR;
+ return V3D_PROJ_RET_CLIP_ZERO;
}
return V3D_PROJ_RET_OK;
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index dac887f7f13..24260898066 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -617,7 +617,8 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const
LassoSelectUserData *data = userData;
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) {
+ BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
+ {
bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
}
}
@@ -717,7 +718,8 @@ static void do_lasso_select_mball__doSelectElem(void *userData, struct MetaElem
LassoSelectUserData *data = userData;
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX)) {
+ BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX))
+ {
if (data->select) ml->flag |= SELECT;
else ml->flag &= ~SELECT;
data->is_change = TRUE;
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index ea82ebb9234..c8874d13cac 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -239,11 +239,11 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
}
}
-void projectIntView(TransInfo *t, const float vec[3], int adr[2])
+void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag)
{
if (t->spacetype == SPACE_VIEW3D) {
if (t->ar->regiontype == RGN_TYPE_WINDOW) {
- if (ED_view3d_project_int_global(t->ar, vec, adr, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+ if (ED_view3d_project_int_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
adr[0] = (int)2140000000.0f; /* this is what was done in 2.64, perhaps we can be smarter? */
adr[1] = (int)2140000000.0f;
}
@@ -361,15 +361,19 @@ void projectIntView(TransInfo *t, const float vec[3], int adr[2])
UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], adr, adr + 1);
}
}
+void projectIntView(TransInfo *t, const float vec[3], int adr[2])
+{
+ projectIntViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
+}
-void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
+void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag)
{
switch (t->spacetype) {
case SPACE_VIEW3D:
{
if (t->ar->regiontype == RGN_TYPE_WINDOW) {
/* allow points behind the view [#33643] */
- if (ED_view3d_project_float_global(t->ar, vec, adr, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+ if (ED_view3d_project_float_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
/* XXX, 2.64 and prior did this, weak! */
adr[0] = t->ar->winx / 2.0f;
adr[1] = t->ar->winy / 2.0f;
@@ -393,6 +397,10 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
zero_v2(adr);
}
+void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
+{
+ projectFloatViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
+}
void applyAspectRatio(TransInfo *t, float vec[2])
{
@@ -1543,7 +1551,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
if (ob) mul_m4_v3(ob->obmat, vecrot);
}
- projectFloatView(t, vecrot, cent); // no overflow in extreme cases
+ projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO);
glPushMatrix();
@@ -5285,6 +5293,7 @@ static int createEdgeSlideVerts(TransInfo *t)
TransDataEdgeSlideVert *sv;
/* XXX, 'sv' will initialize multiple times, this is suspicious. see [#34024] */
+ BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
sv = sv_array + GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
sv->v = v;
sv->origvert = *v;
@@ -5307,6 +5316,7 @@ static int createEdgeSlideVerts(TransInfo *t)
e1 = e;
e = get_other_edge(v, e);
if (!e) {
+ BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
sv = sv_array + GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
sv->v = v;
sv->origvert = *v;
@@ -5331,6 +5341,12 @@ static int createEdgeSlideVerts(TransInfo *t)
l1 = get_next_loop(v, l1, e1, e, vec);
l2 = l2 ? get_next_loop(v, l2, e1, e, vec2) : NULL;
+ if (UNLIKELY(l1 == NULL && l2 != NULL)) {
+ l1 = l2;
+ l2 = NULL;
+ swap_v3_v3(vec, vec2);
+ }
+
BM_elem_flag_disable(v, BM_ELEM_TAG);
BM_elem_flag_disable(v2, BM_ELEM_TAG);
} while (e != v_first->e && l1);
@@ -5372,6 +5388,7 @@ static int createEdgeSlideVerts(TransInfo *t)
continue;
}
+ BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
j = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
if (sv_array[j].down) {
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 9c57c74a26d..dbf56f658ac 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -35,6 +35,7 @@
#include "ED_transform.h"
#include "ED_numinput.h"
+#include "ED_view3d.h"
#include "DNA_listBase.h"
@@ -481,7 +482,9 @@ int transformEnd(struct bContext *C, TransInfo *t);
void setTransformViewMatrices(TransInfo *t);
void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy);
+void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag);
void projectIntView(TransInfo *t, const float vec[3], int adr[2]);
+void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag);
void projectFloatView(TransInfo *t, const float vec[3], float adr[2]);
void applyAspectRatio(TransInfo *t, float *vec);
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 5be06188e4e..57816e7546c 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -4560,7 +4560,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
short constinv;
short skip_invert = 0;
- if (ob->rigidbody_object) {
+ if (t->mode != TFM_DUMMY && ob->rigidbody_object) {
float rot[3][3], scale[3];
/* save original object transform */
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index cd6035a232b..54fb567b8a2 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -841,37 +841,89 @@ static void manipulator_setcolor(View3D *v3d, char axis, int colcode, unsigned c
glColor4ubv(col);
}
-/* viewmatrix should have been set OK, also no shademode! */
-static void draw_manipulator_axes(View3D *v3d, RegionView3D *rv3d, int colcode, int flagx, int flagy, int flagz)
+static void axis_sort_v3(const float axis_values[3], int r_axis_order[3])
{
+ float v[3];
+ copy_v3_v3(v, axis_values);
- /* axes */
- if (flagx) {
- manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
- if (flagx & MAN_SCALE_X) glLoadName(MAN_SCALE_X);
- else if (flagx & MAN_TRANS_X) glLoadName(MAN_TRANS_X);
- glBegin(GL_LINES);
- glVertex3f(0.2f, 0.0f, 0.0f);
- glVertex3f(1.0f, 0.0f, 0.0f);
- glEnd();
+#define SWAP_AXIS(a, b) { \
+ SWAP(float, v[a], v[b]); \
+ SWAP(int, r_axis_order[a], r_axis_order[b]); \
+} (void)0
+
+ if (v[0] < v[1]) {
+ if (v[2] < v[0]) { SWAP_AXIS(0, 2); }
+ }
+ else {
+ if (v[1] < v[2]) { SWAP_AXIS(0, 1); }
+ else { SWAP_AXIS(0, 2); }
}
- if (flagy) {
- if (flagy & MAN_SCALE_Y) glLoadName(MAN_SCALE_Y);
- else if (flagy & MAN_TRANS_Y) glLoadName(MAN_TRANS_Y);
- manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.2f, 0.0f);
- glVertex3f(0.0f, 1.0f, 0.0f);
- glEnd();
+ if (v[2] < v[1]) { SWAP_AXIS(1, 2); }
+
+#undef SWAP_AXIS
+}
+static void manipulator_axis_order(RegionView3D *rv3d, int r_axis_order[3])
+{
+ float axis_values[3];
+ float vec[3];
+
+ ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], vec);
+
+ axis_values[0] = -dot_v3v3(rv3d->twmat[0], vec);
+ axis_values[1] = -dot_v3v3(rv3d->twmat[1], vec);
+ axis_values[2] = -dot_v3v3(rv3d->twmat[2], vec);
+
+ axis_sort_v3(axis_values, r_axis_order);
+}
+
+/* viewmatrix should have been set OK, also no shademode! */
+static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int colcode,
+ int flagx, int flagy, int flagz, int axis)
+{
+ switch (axis) {
+ case 0:
+ /* axes */
+ if (flagx) {
+ manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
+ if (flagx & MAN_SCALE_X) glLoadName(MAN_SCALE_X);
+ else if (flagx & MAN_TRANS_X) glLoadName(MAN_TRANS_X);
+ glBegin(GL_LINES);
+ glVertex3f(0.2f, 0.0f, 0.0f);
+ glVertex3f(1.0f, 0.0f, 0.0f);
+ glEnd();
+ }
+ break;
+ case 1:
+ if (flagy) {
+ if (flagy & MAN_SCALE_Y) glLoadName(MAN_SCALE_Y);
+ else if (flagy & MAN_TRANS_Y) glLoadName(MAN_TRANS_Y);
+ manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.2f, 0.0f);
+ glVertex3f(0.0f, 1.0f, 0.0f);
+ glEnd();
+ }
+ break;
+ case 2:
+ if (flagz) {
+ if (flagz & MAN_SCALE_Z) glLoadName(MAN_SCALE_Z);
+ else if (flagz & MAN_TRANS_Z) glLoadName(MAN_TRANS_Z);
+ manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.0f, 0.2f);
+ glVertex3f(0.0f, 0.0f, 1.0f);
+ glEnd();
+ }
+ break;
}
- if (flagz) {
- if (flagz & MAN_SCALE_Z) glLoadName(MAN_SCALE_Z);
- else if (flagz & MAN_TRANS_Z) glLoadName(MAN_TRANS_Z);
- manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.0f, 0.2f);
- glVertex3f(0.0f, 0.0f, 1.0f);
- glEnd();
+}
+static void draw_manipulator_axes(View3D *v3d, RegionView3D *rv3d, int colcode,
+ int flagx, int flagy, int flagz,
+ const int axis_order[3])
+{
+ int i;
+ for (i = 0; i < 3; i++) {
+ draw_manipulator_axes_single(v3d, rv3d, colcode, flagx, flagy, flagz, axis_order[i]);
}
}
@@ -1214,10 +1266,14 @@ static void draw_manipulator_scale(View3D *v3d, RegionView3D *rv3d, int moving,
{
float cywid = 0.25f * 0.01f * (float)U.tw_handlesize;
float cusize = cywid * 0.75f, dz;
+ int axis_order[3] = {2, 0, 1};
+ int i;
/* when called while moving in mixed mode, do not draw when... */
if ((drawflags & MAN_SCALE_C) == 0) return;
+ manipulator_axis_order(rv3d, axis_order);
+
glDisable(GL_DEPTH_TEST);
/* not in combo mode */
@@ -1255,28 +1311,41 @@ static void draw_manipulator_scale(View3D *v3d, RegionView3D *rv3d, int moving,
/* axis */
/* in combo mode, this is always drawn as first type */
- draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z);
-
- /* Z cube */
- glTranslatef(0.0, 0.0, dz);
- if (drawflags & MAN_SCALE_Z) {
- if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_Z);
- manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
- drawsolidcube(cusize);
- }
- /* X cube */
- glTranslatef(dz, 0.0, -dz);
- if (drawflags & MAN_SCALE_X) {
- if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_X);
- manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
- drawsolidcube(cusize);
- }
- /* Y cube */
- glTranslatef(-dz, dz, 0.0);
- if (drawflags & MAN_SCALE_Y) {
- if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_Y);
- manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
- drawsolidcube(cusize);
+ draw_manipulator_axes(v3d, rv3d, colcode,
+ drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z,
+ axis_order);
+
+
+ for (i = 0; i < 3; i++) {
+ switch (axis_order[i]) {
+ case 0: /* X cube */
+ if (drawflags & MAN_SCALE_X) {
+ glTranslatef(dz, 0.0, 0.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_X);
+ manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
+ drawsolidcube(cusize);
+ glTranslatef(-dz, 0.0, 0.0);
+ }
+ break;
+ case 1: /* Y cube */
+ if (drawflags & MAN_SCALE_Y) {
+ glTranslatef(0.0, dz, 0.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_Y);
+ manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
+ drawsolidcube(cusize);
+ glTranslatef(0.0, -dz, 0.0);
+ }
+ break;
+ case 2: /* Z cube */
+ if (drawflags & MAN_SCALE_Z) {
+ glTranslatef(0.0, 0.0, dz);
+ if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_Z);
+ manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
+ drawsolidcube(cusize);
+ glTranslatef(0.0, 0.0, -dz);
+ }
+ break;
+ }
}
/* if shiftkey, center point as last, for selectbuffer order */
@@ -1333,16 +1402,17 @@ static void draw_manipulator_translate(View3D *v3d, RegionView3D *rv3d, int UNUS
float cywid = 0.25f * cylen, dz, size;
float unitmat[4][4];
int shift = 0; // XXX
+ int axis_order[3] = {0, 1, 2};
+ int i;
/* when called while moving in mixed mode, do not draw when... */
if ((drawflags & MAN_TRANS_C) == 0) return;
+ manipulator_axis_order(rv3d, axis_order);
+
// XXX if (moving) glTranslatef(t->vec[0], t->vec[1], t->vec[2]);
glDisable(GL_DEPTH_TEST);
- qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_FILL);
-
/* center circle, do not add to selection when shift is pressed (planar constraint) */
if ((G.f & G_PICKSEL) && shift == 0) glLoadName(MAN_TRANS_C);
@@ -1360,8 +1430,11 @@ static void draw_manipulator_translate(View3D *v3d, RegionView3D *rv3d, int UNUS
glLoadName(-1);
// translate drawn as last, only axis when no combo with scale, or for ghosting
- if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST)
- draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z);
+ if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) {
+ draw_manipulator_axes(v3d, rv3d, colcode,
+ drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z,
+ axis_order);
+ }
/* offset in combo mode, for rotate a bit more */
@@ -1369,29 +1442,43 @@ static void draw_manipulator_translate(View3D *v3d, RegionView3D *rv3d, int UNUS
else if (combo & (V3D_MANIP_SCALE)) dz = 1.0f + 0.5f * cylen;
else dz = 1.0f;
- /* Z Cone */
- glTranslatef(0.0, 0.0, dz);
- if (drawflags & MAN_TRANS_Z) {
- if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_Z);
- manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
- draw_cone(qobj, cylen, cywid);
- }
- /* X Cone */
- glTranslatef(dz, 0.0, -dz);
- if (drawflags & MAN_TRANS_X) {
- if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_X);
- glRotatef(90.0, 0.0, 1.0, 0.0);
- manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
- draw_cone(qobj, cylen, cywid);
- glRotatef(-90.0, 0.0, 1.0, 0.0);
- }
- /* Y Cone */
- glTranslatef(-dz, dz, 0.0);
- if (drawflags & MAN_TRANS_Y) {
- if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_Y);
- glRotatef(-90.0, 1.0, 0.0, 0.0);
- manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
- draw_cone(qobj, cylen, cywid);
+ qobj = gluNewQuadric();
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+
+ for (i = 0; i < 3; i++) {
+ switch (axis_order[i]) {
+ case 0: /* Z Cone */
+ if (drawflags & MAN_TRANS_Z) {
+ glTranslatef(0.0, 0.0, dz);
+ if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_Z);
+ manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
+ draw_cone(qobj, cylen, cywid);
+ glTranslatef(0.0, 0.0, -dz);
+ }
+ break;
+ case 1: /* X Cone */
+ if (drawflags & MAN_TRANS_X) {
+ glTranslatef(dz, 0.0, 0.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_X);
+ glRotatef(90.0, 0.0, 1.0, 0.0);
+ manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
+ draw_cone(qobj, cylen, cywid);
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ glTranslatef(-dz, 0.0, 0.0);
+ }
+ break;
+ case 2: /* Y Cone */
+ if (drawflags & MAN_TRANS_Y) {
+ glTranslatef(0.0, dz, 0.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_Y);
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
+ draw_cone(qobj, cylen, cywid);
+ glRotatef(90.0, 1.0, 0.0, 0.0);
+ glTranslatef(0.0, -dz, 0.0);
+ }
+ break;
+ }
}
gluDeleteQuadric(qobj);
@@ -1407,10 +1494,13 @@ static void draw_manipulator_rotate_cyl(View3D *v3d, RegionView3D *rv3d, int mov
float size;
float cylen = 0.01f * (float)U.tw_handlesize;
float cywid = 0.25f * cylen;
-
+ int axis_order[3] = {2, 0, 1};
+ int i;
/* when called while moving in mixed mode, do not draw when... */
if ((drawflags & MAN_ROT_C) == 0) return;
+ manipulator_axis_order(rv3d, axis_order);
+
/* prepare for screen aligned draw */
glPushMatrix();
size = screen_aligned(rv3d, rv3d->twmat);
@@ -1461,36 +1551,50 @@ static void draw_manipulator_rotate_cyl(View3D *v3d, RegionView3D *rv3d, int mov
if ((G.f & G_PICKSEL) == 0) {
// only draw axis when combo didn't draw scale axes
- if ((combo & V3D_MANIP_SCALE) == 0)
- draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z);
+ if ((combo & V3D_MANIP_SCALE) == 0) {
+ draw_manipulator_axes(v3d, rv3d, colcode,
+ drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z,
+ axis_order);
+ }
/* only has to be set when not in picking */
gluQuadricDrawStyle(qobj, GLU_FILL);
}
- /* Z cyl */
- glTranslatef(0.0, 0.0, 1.0);
- if (drawflags & MAN_ROT_Z) {
- if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
- manipulator_setcolor(v3d, 'Z', colcode, 255);
- draw_cylinder(qobj, cylen, cywid);
- }
- /* X cyl */
- glTranslatef(1.0, 0.0, -1.0);
- if (drawflags & MAN_ROT_X) {
- if (G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
- glRotatef(90.0, 0.0, 1.0, 0.0);
- manipulator_setcolor(v3d, 'X', colcode, 255);
- draw_cylinder(qobj, cylen, cywid);
- glRotatef(-90.0, 0.0, 1.0, 0.0);
- }
- /* Y cylinder */
- glTranslatef(-1.0, 1.0, 0.0);
- if (drawflags & MAN_ROT_Y) {
- if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
- glRotatef(-90.0, 1.0, 0.0, 0.0);
- manipulator_setcolor(v3d, 'Y', colcode, 255);
- draw_cylinder(qobj, cylen, cywid);
+ for (i = 0; i < 3; i++) {
+ switch (axis_order[i]) {
+ case 0: /* X cylinder */
+ if (drawflags & MAN_ROT_X) {
+ glTranslatef(1.0, 0.0, 0.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
+ glRotatef(90.0, 0.0, 1.0, 0.0);
+ manipulator_setcolor(v3d, 'X', colcode, 255);
+ draw_cylinder(qobj, cylen, cywid);
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ glTranslatef(-1.0, 0.0, 0.0);
+ }
+ break;
+ case 1: /* Y cylinder */
+ if (drawflags & MAN_ROT_Y) {
+ glTranslatef(0.0, 1.0, 0.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ manipulator_setcolor(v3d, 'Y', colcode, 255);
+ draw_cylinder(qobj, cylen, cywid);
+ glRotatef(90.0, 1.0, 0.0, 0.0);
+ glTranslatef(0.0, -1.0, 0.0);
+ }
+ break;
+ case 2: /* Z cylinder */
+ if (drawflags & MAN_ROT_Z) {
+ glTranslatef(0.0, 0.0, 1.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
+ manipulator_setcolor(v3d, 'Z', colcode, 255);
+ draw_cylinder(qobj, cylen, cywid);
+ glTranslatef(0.0, 0.0, -1.0);
+ }
+ break;
+ }
}
/* restore */
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 32dc31954f2..0392c0f47a2 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -37,6 +37,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_armature.h"
@@ -169,7 +171,7 @@ static int select_orientation_invoke(bContext *C, wmOperator *UNUSED(op), wmEven
uiPopupMenu *pup;
uiLayout *layout;
- pup = uiPupMenuBegin(C, "Orientation", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Orientation"), ICON_NONE);
layout = uiPupMenuLayout(pup);
uiItemsEnumO(layout, "TRANSFORM_OT_select_orientation", "orientation");
uiPupMenuEnd(C, pup);
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 23d6b0a075e..f0f31b1e793 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -42,6 +42,8 @@
#include "BLI_blenlib.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -174,10 +176,10 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
char line[FILE_MAX + 100];
wmOperatorType *ot = WM_operatortype_find(opname, 1);
- pup = uiPupMenuBegin(C, "Unpack file", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Unpack File"), ICON_NONE);
layout = uiPupMenuLayout(pup);
- strcpy(line, "Remove Pack");
+ strcpy(line, IFACE_("Remove Pack"));
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_REMOVE);
RNA_string_set(&props_ptr, "id", id_name);
@@ -191,14 +193,14 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
if (strcmp(abs_name, local_name) != 0) {
switch (checkPackedFile(local_name, pf)) {
case PF_NOFILE:
- BLI_snprintf(line, sizeof(line), "Create %s", local_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Create %s"), local_name);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL);
RNA_string_set(&props_ptr, "id", id_name);
break;
case PF_EQUAL:
- BLI_snprintf(line, sizeof(line), "Use %s (identical)", local_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Use %s (identical)"), local_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_LOCAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL);
@@ -206,13 +208,13 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
break;
case PF_DIFFERS:
- BLI_snprintf(line, sizeof(line), "Use %s (differs)", local_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Use %s (differs)"), local_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_LOCAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL);
RNA_string_set(&props_ptr, "id", id_name);
- BLI_snprintf(line, sizeof(line), "Overwrite %s", local_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Overwrite %s"), local_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_LOCAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL);
@@ -224,27 +226,27 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
switch (checkPackedFile(abs_name, pf)) {
case PF_NOFILE:
- BLI_snprintf(line, sizeof(line), "Create %s", abs_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Create %s"), abs_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL);
RNA_string_set(&props_ptr, "id", id_name);
break;
case PF_EQUAL:
- BLI_snprintf(line, sizeof(line), "Use %s (identical)", abs_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Use %s (identical)"), abs_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_ORIGINAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL);
RNA_string_set(&props_ptr, "id", id_name);
break;
case PF_DIFFERS:
- BLI_snprintf(line, sizeof(line), "Use %s (differs)", abs_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Use %s (differs)"), abs_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_ORIGINAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL);
RNA_string_set(&props_ptr, "id", id_name);
- BLI_snprintf(line, sizeof(line), "Overwrite %s", abs_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Overwrite %s"), abs_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL);
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index 8a0ef06ef12..ac2ee21d09d 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -83,8 +83,8 @@ void ED_undo_push(bContext *C, const char *str)
Object *obact = CTX_data_active_object(C);
if (G.debug & G_DEBUG)
- printf("undo push %s\n", str);
-
+ printf("%s: %s\n", __func__, str);
+
if (obedit) {
if (U.undosteps == 0) return;
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index a17d3c20c1c..fbb6250c05b 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -113,7 +113,7 @@ static int ED_operator_uvedit_can_uv_sculpt(struct bContext *C)
return ED_space_image_show_uvedit(sima, obedit) && !(toolsettings->use_uv_sculpt);
}
-static int UNUSED_FUNCTION(ED_operator_uvmap_mesh) (bContext * C)
+static int UNUSED_FUNCTION(ED_operator_uvmap_mesh) (bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -1582,7 +1582,7 @@ static void UV_OT_align(wmOperatorType *ot)
/* api callbacks */
ot->exec = align_exec;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* properties */
RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on");
@@ -2258,7 +2258,7 @@ static void UV_OT_select(wmOperatorType *ot)
/* api callbacks */
ot->exec = select_exec;
ot->invoke = select_invoke;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* properties */
RNA_def_boolean(ot->srna, "extend", 0,
@@ -2303,7 +2303,7 @@ static void UV_OT_select_loop(wmOperatorType *ot)
/* api callbacks */
ot->exec = select_loop_exec;
ot->invoke = select_loop_invoke;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* properties */
RNA_def_boolean(ot->srna, "extend", 0,
@@ -2377,7 +2377,7 @@ static void UV_OT_select_linked(wmOperatorType *ot)
/* api callbacks */
ot->exec = select_linked_exec;
- ot->poll = ED_operator_image_active; /* requires space image */
+ ot->poll = ED_operator_uvedit; /* requires space image */
/* properties */
RNA_def_boolean(ot->srna, "extend", 0,
@@ -2405,7 +2405,7 @@ static void UV_OT_select_linked_pick(wmOperatorType *ot)
/* api callbacks */
ot->invoke = select_linked_pick_invoke;
ot->exec = select_linked_pick_exec;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* properties */
RNA_def_boolean(ot->srna, "extend", 0,
@@ -2842,7 +2842,7 @@ static void UV_OT_select_border(wmOperatorType *ot)
ot->invoke = WM_border_select_invoke;
ot->exec = border_select_exec;
ot->modal = WM_border_select_modal;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
ot->cancel = WM_border_select_cancel;
/* flags */
@@ -2966,7 +2966,7 @@ static void UV_OT_circle_select(wmOperatorType *ot)
ot->invoke = WM_gesture_circle_invoke;
ot->modal = WM_gesture_circle_modal;
ot->exec = circle_select_exec;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
ot->cancel = WM_gesture_circle_cancel;
/* flags */
@@ -3095,7 +3095,7 @@ static void UV_OT_select_lasso(wmOperatorType *ot)
ot->invoke = WM_gesture_lasso_invoke;
ot->modal = WM_gesture_lasso_modal;
ot->exec = uv_lasso_select_exec;
- ot->poll = ED_operator_image_active;
+ ot->poll = ED_operator_uvedit;
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
@@ -3170,7 +3170,7 @@ static void UV_OT_snap_cursor(wmOperatorType *ot)
/* api callbacks */
ot->exec = snap_cursor_exec;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* properties */
RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
@@ -3350,7 +3350,7 @@ static void UV_OT_snap_selected(wmOperatorType *ot)
/* api callbacks */
ot->exec = snap_selection_exec;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* properties */
RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
@@ -3769,7 +3769,7 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = set_2d_cursor_exec;
ot->invoke = set_2d_cursor_invoke;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 6abc41759e7..faeb0f721f4 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -50,6 +50,7 @@ set(SRC
intern/gpu_codegen.c
intern/gpu_draw.c
intern/gpu_extensions.c
+ intern/gpu_fixed_material.c
intern/gpu_material.c
GPU_buffers.h
@@ -59,10 +60,12 @@ set(SRC
intern/gpu_codegen.h
)
+data_to_c_simple(shaders/gpu_shader_fixed_fragment.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_fixed_vertex.glsl SRC)
data_to_c_simple(shaders/gpu_shader_material.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_vertex.glsl SRC)
data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_vertex.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vsm_store_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vsm_store_vert.glsl SRC)
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 66a7c917a55..7492304bd40 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -32,6 +32,8 @@
#ifndef __GPU_EXTENSIONS_H__
#define __GPU_EXTENSIONS_H__
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -160,17 +162,17 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
* - only for fragment shaders now
* - must call texture bind before setting a texture as uniform! */
-GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode); /*GPUShader *lib);*/
-/*GPUShader *GPU_shader_create_lib(const char *code);*/
+GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines);
void GPU_shader_free(GPUShader *shader);
void GPU_shader_bind(GPUShader *shader);
-void GPU_shader_unbind(GPUShader *shader);
+void GPU_shader_unbind(void);
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
void GPU_shader_uniform_vector(GPUShader *shader, int location, int length,
int arraysize, float *value);
void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex);
+void GPU_shader_uniform_int(GPUShader *shader, int location, int value);
int GPU_shader_get_attribute(GPUShader *shader, const char *name);
@@ -199,6 +201,30 @@ typedef struct GPUVertexAttribs {
int totlayer;
} GPUVertexAttribs;
+/* Fixed Function Materials */
+
+typedef enum GPUFixedMaterialOption {
+ GPU_FIXED_COLOR_MATERIAL = (1<<0), /* replace diffuse with glcolor */
+ GPU_FIXED_SOLID_LIGHTING = (1<<1), /* use solid lighting (only 3 directional lights) */
+ GPU_FIXED_SCENE_LIGHTING = (1<<2), /* use scene lighting (up to 8 arbitrary lights) */
+ GPU_FIXED_TWO_SIDED = (1<<3), /* flip normals towards viewer */
+ GPU_FIXED_TEXTURE_2D = (1<<4), /* use 2D texture to replace diffuse color */
+
+ GPU_FIXED_OPTIONS_NUM = 5,
+ GPU_FIXED_OPTION_COMBINATIONS = (1<<GPU_FIXED_OPTIONS_NUM)
+} GPUFixedMaterialOption;
+
+void GPU_fixed_materials_init(void);
+void GPU_fixed_materials_exit(void);
+
+void GPU_fixed_material_shader_bind(int options);
+void GPU_fixed_material_shader_unbind(void);
+
+void GPU_fixed_material_colors(const float diffuse[3], const float specular[3],
+ int shininess, float alpha);
+
+bool GPU_fixed_material_need_normals(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript
index f7db3dfeaa0..ccea40c0909 100644
--- a/source/blender/gpu/SConscript
+++ b/source/blender/gpu/SConscript
@@ -49,10 +49,12 @@ if env['WITH_BF_DDS']:
# generated data files
import os
sources.extend((
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fixed_fragment.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fixed_vertex.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_material.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_vertex.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_sep_gaussian_blur_frag.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_sep_gaussian_blur_vert.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_vertex.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_vsm_store_frag.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_vsm_store_vert.glsl.c"),
))
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index b27a4be9f21..59953659a2c 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -237,8 +237,6 @@ GPUFunction *GPU_lookup_function(const char *name)
if (!FUNCTION_HASH) {
FUNCTION_HASH = BLI_ghash_str_new("GPU_lookup_function gh");
gpu_parse_functions_string(FUNCTION_HASH, glsl_material_library);
- /*FUNCTION_PROTOTYPES = gpu_generate_function_prototyps(FUNCTION_HASH);
- FUNCTION_LIB = GPU_shader_create_lib(datatoc_gpu_shader_material_glsl);*/
}
return (GPUFunction*)BLI_ghash_lookup(FUNCTION_HASH, (void *)name);
@@ -758,7 +756,7 @@ static void GPU_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
}
}
- GPU_shader_unbind(shader);
+ GPU_shader_unbind();
}
void GPU_pass_bind(GPUPass *pass, double time, int mipmap)
@@ -820,7 +818,7 @@ void GPU_pass_unbind(GPUPass *pass)
input->tex = NULL;
}
- GPU_shader_unbind(shader);
+ GPU_shader_unbind();
}
/* Node Link Functions */
@@ -1368,7 +1366,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttri
/* generate code and compile with opengl */
fragmentcode = code_generate_fragment(nodes, outlink->output, name);
vertexcode = code_generate_vertex(nodes);
- shader = GPU_shader_create(vertexcode, fragmentcode, glsl_material_library); /*FUNCTION_LIB);*/
+ shader = GPU_shader_create(vertexcode, fragmentcode, glsl_material_library, NULL);
/* failed? */
if (!shader) {
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index e8e47013159..56aa4b222cb 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -205,12 +205,15 @@ void GPU_extensions_init(void)
#else
GG.os = GPU_OS_UNIX;
#endif
+
+ GPU_fixed_materials_init();
}
void GPU_extensions_exit(void)
{
gpu_extensions_init = 0;
GPU_codegen_exit();
+ GPU_fixed_materials_exit();
}
int GPU_glsl_support(void)
@@ -1006,7 +1009,7 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b
glTexCoord2d(0, 1); glVertex2f(1, -1);
glEnd();
- GPU_shader_unbind(blur_shader);
+ GPU_shader_unbind();
}
/* GPUOffScreen */
@@ -1124,13 +1127,11 @@ static void shader_print_errors(const char *task, char *log, const char *code)
fprintf(stderr, "%s\n", log);
}
-GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPUShader *lib,*/ const char *libcode)
+GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines)
{
GLint status;
GLcharARB log[5000];
- const char *fragsource[2];
GLsizei length = 0;
- GLint count;
GPUShader *shader;
if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
@@ -1154,8 +1155,14 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPU
}
if (vertexcode) {
+ const char *source[2];
+ int num_source = 0;
+
+ if (defines) source[num_source++] = defines;
+ if (vertexcode) source[num_source++] = vertexcode;
+
glAttachObjectARB(shader->object, shader->vertex);
- glShaderSourceARB(shader->vertex, 1, (const char**)&vertexcode, NULL);
+ glShaderSourceARB(shader->vertex, num_source, source, NULL);
glCompileShaderARB(shader->vertex);
glGetObjectParameterivARB(shader->vertex, GL_OBJECT_COMPILE_STATUS_ARB, &status);
@@ -1170,12 +1177,15 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPU
}
if (fragcode) {
- count = 0;
- if (libcode) fragsource[count++] = libcode;
- if (fragcode) fragsource[count++] = fragcode;
+ const char *source[3];
+ int num_source = 0;
+
+ if (defines) source[num_source++] = defines;
+ if (libcode) source[num_source++] = libcode;
+ if (fragcode) source[num_source++] = fragcode;
glAttachObjectARB(shader->object, shader->fragment);
- glShaderSourceARB(shader->fragment, count, fragsource, NULL);
+ glShaderSourceARB(shader->fragment, num_source, source, NULL);
glCompileShaderARB(shader->fragment);
glGetObjectParameterivARB(shader->fragment, GL_OBJECT_COMPILE_STATUS_ARB, &status);
@@ -1254,7 +1264,7 @@ void GPU_shader_bind(GPUShader *shader)
GPU_print_error("Post Shader Bind");
}
-void GPU_shader_unbind(GPUShader *UNUSED(shader))
+void GPU_shader_unbind()
{
GPU_print_error("Pre Shader Unbind");
glUseProgramObjectARB(0);
@@ -1296,6 +1306,16 @@ void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int leng
GPU_print_error("Post Uniform Vector");
}
+void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
+{
+ if (location == -1)
+ return;
+
+ GPU_print_error("Pre Uniform Int");
+ glUniform1iARB(location, value);
+ GPU_print_error("Post Uniform Int");
+}
+
void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
{
GLenum arbnumber;
@@ -1344,12 +1364,12 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
switch (shader) {
case GPU_SHADER_VSM_STORE:
if (!GG.shaders.vsm_store)
- GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL);
+ GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL, NULL);
retval = GG.shaders.vsm_store;
break;
case GPU_SHADER_SEP_GAUSSIAN_BLUR:
if (!GG.shaders.sep_gaussian_blur)
- GG.shaders.sep_gaussian_blur = GPU_shader_create(datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, NULL);
+ GG.shaders.sep_gaussian_blur = GPU_shader_create(datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, NULL, NULL);
retval = GG.shaders.sep_gaussian_blur;
break;
}
diff --git a/source/blender/gpu/intern/gpu_fixed_material.c b/source/blender/gpu/intern/gpu_fixed_material.c
new file mode 100644
index 00000000000..d5a04c88e89
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_fixed_material.c
@@ -0,0 +1,191 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_fixed_material.c
+ * \ingroup gpu
+ */
+
+/* GLSL shaders to replace fixed function OpenGL materials and lighting. These
+ * are deprecated in newer OpenGL versions and missing in OpenGL ES 2.0. Also,
+ * two sided lighting is no longer natively supported on NVidia cards which
+ * results in slow software fallback.
+ *
+ * Todo:
+ * - Replace glLight and glMaterial functions entirely with GLSL uniforms, to
+ * make OpenGL ES 2.0 work.
+ * - Replace glTexCoord and glColor with generic attributes.
+ * - Optimize for case where fewer than 3 or 8 lights are used.
+ * - Optimize for case where specular is not used.
+ * - Optimize for case where no texture matrix is used.
+ */
+
+#include "GL/glew.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+
+#include "GPU_extensions.h"
+
+/* Fixed function material types */
+
+static struct {
+ GPUShader *cached_shaders[GPU_FIXED_OPTION_COMBINATIONS];
+ bool failed_shaders[GPU_FIXED_OPTION_COMBINATIONS];
+
+ bool need_normals;
+} GPU_MATERIAL_STATE;
+
+/* Init / exit */
+
+void GPU_fixed_materials_init()
+{
+ memset(&GPU_MATERIAL_STATE, 0, sizeof(GPU_MATERIAL_STATE));
+}
+
+void GPU_fixed_materials_exit()
+{
+ int i;
+
+ for (i = 0; i < GPU_FIXED_OPTION_COMBINATIONS; i++)
+ if (GPU_MATERIAL_STATE.cached_shaders[i])
+ GPU_shader_free(GPU_MATERIAL_STATE.cached_shaders[i]);
+}
+
+/* Shader lookup / create */
+
+static GPUShader *gpu_fixed_material_shader(int options)
+{
+ /* glsl code */
+ extern char datatoc_gpu_shader_fixed_vertex_glsl[];
+ extern char datatoc_gpu_shader_fixed_fragment_glsl[];
+
+ /* cached shaders */
+ GPUShader *shader = GPU_MATERIAL_STATE.cached_shaders[options];
+
+ if (!shader && !GPU_MATERIAL_STATE.failed_shaders[options]) {
+ /* create shader if it doesn't exist yet */
+ char defines[64*GPU_FIXED_OPTIONS_NUM] = "";
+
+ if (options & GPU_FIXED_COLOR_MATERIAL)
+ strcat(defines, "#define USE_COLOR\n");
+ if (options & GPU_FIXED_TWO_SIDED)
+ strcat(defines, "#define USE_TWO_SIDED\n");
+ if (options & GPU_FIXED_SOLID_LIGHTING)
+ strcat(defines, "#define USE_SOLID_LIGHTING\n");
+ if (options & GPU_FIXED_SCENE_LIGHTING)
+ strcat(defines, "#define USE_SCENE_LIGHTING\n");
+ if (options & GPU_FIXED_TEXTURE_2D)
+ strcat(defines, "#define USE_TEXTURE\n");
+
+ shader = GPU_shader_create(
+ datatoc_gpu_shader_fixed_vertex_glsl,
+ datatoc_gpu_shader_fixed_fragment_glsl,
+ NULL, defines);
+
+ if (shader) {
+ /* set texture map to first texture unit */
+ if (options & GPU_FIXED_TEXTURE_2D)
+ glUniform1i(GPU_shader_get_uniform(shader, "texture_map"), 0);
+
+ GPU_MATERIAL_STATE.cached_shaders[options] = shader;
+ }
+ else
+ GPU_MATERIAL_STATE.failed_shaders[options] = true;
+ }
+
+ return shader;
+}
+
+/* Bind / unbind */
+
+void GPU_fixed_material_shader_bind(int options)
+{
+ if (GPU_glsl_support()) {
+ GPUShader *shader = gpu_fixed_material_shader(options);
+
+ if (shader)
+ GPU_shader_bind(shader);
+ }
+ else {
+ if (options & (GPU_FIXED_SOLID_LIGHTING|GPU_FIXED_SCENE_LIGHTING))
+ glEnable(GL_LIGHTING);
+
+ if (options & GPU_FIXED_TWO_SIDED)
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
+
+ if (options & GPU_FIXED_COLOR_MATERIAL) {
+ glEnable(GL_COLOR_MATERIAL);
+ glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+ }
+
+ if (options & GPU_FIXED_TEXTURE_2D)
+ glEnable(GL_TEXTURE_2D);
+ }
+
+ /* temporary hack, should be solved outside of this file */
+ GPU_MATERIAL_STATE.need_normals = (options & (GPU_FIXED_SOLID_LIGHTING|GPU_FIXED_SCENE_LIGHTING));
+}
+
+void GPU_fixed_material_shader_unbind()
+{
+ if (GPU_glsl_support()) {
+ GPU_shader_unbind();
+ }
+ else {
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ glDisable(GL_TEXTURE_2D);
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
+ }
+}
+
+/* Material Colors */
+
+void GPU_fixed_material_colors(const float diffuse[3], const float specular[3],
+ int shininess, float alpha)
+{
+ float gl_diffuse[4], gl_specular[4];
+
+ copy_v3_v3(gl_diffuse, diffuse);
+ gl_diffuse[3] = alpha;
+
+ copy_v3_v3(gl_specular, specular);
+ gl_specular[3] = 1.0f;
+
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
+ glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, CLAMPIS(shininess, 1, 128));
+}
+
+bool GPU_fixed_material_need_normals()
+{
+ return GPU_MATERIAL_STATE.need_normals;
+}
+
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index b5ef27a338d..d7ac6febfb7 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -1919,7 +1919,7 @@ void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsiz
void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp)
{
if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) {
- GPU_shader_unbind(GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE));
+ GPU_shader_unbind();
GPU_framebuffer_blur(lamp->fb, lamp->tex, lamp->blurfb, lamp->blurtex);
}
diff --git a/source/blender/gpu/shaders/gpu_shader_fixed_fragment.glsl b/source/blender/gpu/shaders/gpu_shader_fixed_fragment.glsl
new file mode 100644
index 00000000000..9610e0cf5aa
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fixed_fragment.glsl
@@ -0,0 +1,169 @@
+
+/* Options:
+ *
+ * USE_COLOR: use glColor for diffuse colors
+ * USE_TEXTURE: use texture for diffuse colors
+ * USE_SCENE_LIGHTING: use lights (up to 8)
+ * USE_SOLID_LIGHTING: assume 3 directional lights for solid draw mode
+ * USE_TWO_SIDED: flip normal towards viewer
+ * NO_SPECULAR: use specular component
+ */
+
+#define NUM_SOLID_LIGHTS 3
+#define NUM_SCENE_LIGHTS 8
+
+#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+varying vec3 varying_normal;
+
+#ifndef USE_SOLID_LIGHTING
+varying vec3 varying_position;
+#endif
+#endif
+
+#ifdef USE_COLOR
+varying vec4 varying_vertex_color;
+#endif
+
+#ifdef USE_TEXTURE
+varying vec2 varying_texture_coord;
+uniform sampler2D texture_map;
+#endif
+
+void main()
+{
+#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+ /* compute normal */
+ vec3 N = normalize(varying_normal);
+
+#ifdef USE_TWO_SIDED
+ if (!gl_FrontFacing)
+ N = -N;
+#endif
+
+ /* compute diffuse and specular lighting */
+ vec3 L_diffuse = vec3(0.0);
+#ifndef NO_SPECULAR
+ vec3 L_specular = vec3(0.0);
+#endif
+
+#ifdef USE_SOLID_LIGHTING
+ /* assume 3 directional lights */
+ for (int i = 0; i < NUM_SOLID_LIGHTS; i++) {
+ vec3 light_direction = gl_LightSource[i].position.xyz;
+
+ /* diffuse light */
+ vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
+ float diffuse_bsdf = max(dot(N, light_direction), 0.0);
+ L_diffuse += light_diffuse*diffuse_bsdf;
+
+#ifndef NO_SPECULAR
+ /* specular light */
+ vec3 light_specular = gl_LightSource[i].specular.rgb;
+ vec3 H = gl_LightSource[i].halfVector.xyz;
+
+ float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);
+ L_specular += light_specular*specular_bsdf;
+#endif
+ }
+#else
+ /* all 8 lights, makes no assumptions, potentially slow */
+
+#ifndef NO_SPECULAR
+ /* view vector computation, depends on orthographics or perspective */
+ vec3 V = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(varying_position): vec3(0.0, 0.0, -1.0);
+#endif
+
+ for (int i = 0; i < NUM_SCENE_LIGHTS; i++) {
+ /* todo: this is a slow check for disabled lights */
+ if (gl_LightSource[i].specular.a == 0.0)
+ continue;
+
+ float intensity = 1.0;
+ vec3 light_direction;
+
+ if (gl_LightSource[i].position.w == 0.0) {
+ /* directional light */
+ light_direction = gl_LightSource[i].position.xyz;
+ }
+ else {
+ /* point light */
+ vec3 d = gl_LightSource[i].position.xyz - varying_position;
+ light_direction = normalize(d);
+
+ /* spot light cone */
+ if (gl_LightSource[i].spotCutoff < 90.0) {
+ float cosine = max(dot(light_direction, -gl_LightSource[i].spotDirection), 0.0);
+ intensity = pow(cosine, gl_LightSource[i].spotExponent);
+ intensity *= step(gl_LightSource[i].spotCosCutoff, cosine);
+ }
+
+ /* falloff */
+ float distance = length(d);
+
+ intensity /= gl_LightSource[i].constantAttenuation +
+ gl_LightSource[i].linearAttenuation * distance +
+ gl_LightSource[i].quadraticAttenuation * distance * distance;
+ }
+
+ /* diffuse light */
+ vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
+ float diffuse_bsdf = max(dot(N, light_direction), 0.0);
+ L_diffuse += light_diffuse*diffuse_bsdf*intensity;
+
+#ifndef NO_SPECULAR
+ /* specular light */
+ vec3 light_specular = gl_LightSource[i].specular.rgb;
+ vec3 H = normalize(light_direction - V);
+
+ float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);
+ L_specular += light_specular*specular_bsdf*intensity;
+#endif
+ }
+#endif
+
+ /* compute diffuse color, possibly from texture or vertex colors */
+ float alpha;
+
+#if defined(USE_TEXTURE) && defined(USE_COLOR)
+ vec4 texture_color = texture2D(texture_map, varying_texture_coord);
+
+ L_diffuse *= texture_color.rgb * varying_vertex_color.rgb;
+ alpha = texture_color.a * varying_vertex_color.a;
+#elif defined(USE_TEXTURE)
+ vec4 texture_color = texture2D(texture_map, varying_texture_coord);
+
+ L_diffuse *= texture_color.rgb;
+ alpha = texture_color.a;
+#elif defined(USE_COLOR)
+ L_diffuse *= varying_vertex_color.rgb;
+ alpha = varying_vertex_color.a;
+#else
+ L_diffuse *= gl_FrontMaterial.diffuse.rgb;
+ alpha = gl_FrontMaterial.diffuse.a;
+#endif
+
+ /* sum lighting */
+ vec3 L = gl_FrontLightModelProduct.sceneColor.rgb + L_diffuse;
+
+#ifndef NO_SPECULAR
+ L += L_specular*gl_FrontMaterial.specular.rgb;
+#endif
+
+ /* write out fragment color */
+ gl_FragColor = vec4(L, alpha);
+#else
+
+ /* no lighting */
+#if defined(USE_TEXTURE) && defined(USE_COLOR)
+ gl_FragColor = texture2D(texture_map, varying_texture_coord) * varying_vertex_color;
+#elif defined(USE_TEXTURE)
+ gl_FragColor = texture2D(texture_map, varying_texture_coord);
+#elif defined(USE_COLOR)
+ gl_FragColor = varying_vertex_color;
+#else
+ gl_FragColor = gl_FrontMaterial.diffuse;
+#endif
+
+#endif
+}
+
diff --git a/source/blender/gpu/shaders/gpu_shader_fixed_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_fixed_vertex.glsl
new file mode 100644
index 00000000000..612f9cff6aa
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fixed_vertex.glsl
@@ -0,0 +1,48 @@
+
+#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+varying vec3 varying_normal;
+
+#ifndef USE_SOLID_LIGHTING
+varying vec3 varying_position;
+#endif
+#endif
+
+#ifdef USE_COLOR
+varying vec4 varying_vertex_color;
+#endif
+
+#ifdef USE_TEXTURE
+varying vec2 varying_texture_coord;
+#endif
+
+void main()
+{
+ vec4 co = gl_ModelViewMatrix * gl_Vertex;
+
+#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+ varying_normal = normalize(gl_NormalMatrix * gl_Normal);
+
+#ifndef USE_SOLID_LIGHTING
+ varying_position = co.xyz;
+#endif
+#endif
+
+ gl_Position = gl_ProjectionMatrix * co;
+
+#ifdef __GLSL_CG_DATA_TYPES
+ // Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA graphic cards.
+ // gl_ClipVertex works only on NVIDIA graphic cards so we have to check with
+ // __GLSL_CG_DATA_TYPES if a NVIDIA graphic card is used (Cg support).
+ // gl_ClipVerte is supported up to GLSL 1.20.
+ gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
+#endif
+
+#ifdef USE_COLOR
+ varying_vertex_color = gl_Color;
+#endif
+
+#ifdef USE_TEXTURE
+ varying_texture_coord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).st;
+#endif
+}
+
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
index 574455e42b3..9e0db44ed31 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
@@ -14,7 +14,7 @@ void main()
// gl_ClipVertex works only on NVIDIA graphic cards so we have to check with
// __GLSL_CG_DATA_TYPES if a NVIDIA graphic card is used (Cg support).
// gl_ClipVerte is supported up to GLSL 1.20.
- #ifdef __GLSL_CG_DATA_TYPES
- gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
- #endif
+#ifdef __GLSL_CG_DATA_TYPES
+ gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
+#endif
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index e1ef7d92bd0..96bdb6c9bdd 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -1519,7 +1519,8 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan, f
if (!ret ||
!scene->addCache(ikscene->cache) ||
!scene->addSolver(ikscene->solver) ||
- !scene->initialize()) {
+ !scene->initialize())
+ {
delete ikscene;
ikscene = NULL;
}
@@ -1566,7 +1567,8 @@ static int init_scene(Object *ob)
if (ob->pose->ikdata) {
for (scene = ((IK_Data *)ob->pose->ikdata)->first;
scene != NULL;
- scene = scene->next) {
+ scene = scene->next)
+ {
if (fabs(scene->blScale - scale) > KDL::epsilon)
return 1;
scene->channels[0].pchan->flag |= POSE_IKTREE;
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index ff297d70cc3..cfeacff7f4a 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -1702,13 +1702,11 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, int save_as_render, int
int do_colormanagement;
int is_movie = BKE_imtype_is_movie(image_format_data->imtype);
int requires_linear_float = BKE_imtype_requires_linear_float(image_format_data->imtype);
+ int do_alpha_under = image_format_data->planes != R_IMF_PLANES_RGBA;
do_colormanagement = save_as_render && (is_movie || !requires_linear_float);
- if (do_colormanagement) {
- int make_byte = FALSE;
- ImFileType *type;
-
+ if (do_colormanagement || do_alpha_under) {
if (allocate_result) {
colormanaged_ibuf = IMB_dupImBuf(ibuf);
}
@@ -1727,6 +1725,41 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, int save_as_render, int
ibuf->mall |= IB_rectfloat;
}
}
+ }
+
+ /* If we're saving from RGBA to RGB buffer then it's not
+ * so much useful to just ignore alpha -- it leads to bad
+ * artifacts especially when saving byte images.
+ *
+ * What we do here is we're overing our image on top of
+ * background color (which is currently black).
+ *
+ * This is quite much the same as what Gimp does and it
+ * seems to be what artists expects from saving.
+ *
+ * Do a conversion here, so image format writers could
+ * happily assume all the alpha tricks were made already.
+ * helps keep things locally here, not spreading it to
+ * all possible image writers we've got.
+ */
+ if (do_alpha_under) {
+ float color[3] = {0, 0, 0};
+
+ if (colormanaged_ibuf->rect_float && colormanaged_ibuf->channels == 4) {
+ IMB_alpha_under_color_float(colormanaged_ibuf->rect_float, colormanaged_ibuf->x,
+ colormanaged_ibuf->y, color);
+ }
+
+ if (colormanaged_ibuf->rect) {
+ IMB_alpha_under_color_byte((unsigned char *)colormanaged_ibuf->rect,
+ colormanaged_ibuf->x, colormanaged_ibuf->y,
+ color);
+ }
+ }
+
+ if (do_colormanagement) {
+ int make_byte = FALSE;
+ ImFileType *type;
/* for proper check whether byte buffer is required by a format or not
* should be pretty safe since this image buffer is supposed to be used for
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index 5c2dc0c7df9..37070c7e2bf 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -26,6 +26,9 @@
#include <stddef.h>
+
+#include "BLI_utildefines.h"
+
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_filetype.h"
@@ -56,7 +59,7 @@ static int imb_ftype_iris(ImFileType *type, ImBuf *ibuf)
return (ibuf->ftype == IMAGIC);
}
#ifdef WITH_QUICKTIME
-static int imb_ftype_quicktime(ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_quicktime(ImFileType *UNUSED(type), ImBuf *UNUSED(ibuf))
{
return 0; /* XXX */
}
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 59282c9d207..26dd0f2977a 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -367,9 +367,9 @@ void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, float backcol
else {
int mul = 255 - cp[3];
- cp[0] += mul * backcol[0] / 255;
- cp[1] += mul * backcol[1] / 255;
- cp[2] += mul * backcol[2] / 255;
+ cp[0] = (cp[0] * cp[3] >> 8) + mul * backcol[0] / 255;
+ cp[1] = (cp[1] * cp[3] >> 8) + mul * backcol[1] / 255;
+ cp[2] = (cp[2] * cp[3] >> 8) + mul * backcol[2] / 255;
}
cp[3] = 255;
diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c
index 3d04b8ee184..f4ac4322747 100644
--- a/source/blender/imbuf/intern/jp2.c
+++ b/source/blender/imbuf/intern/jp2.c
@@ -803,7 +803,7 @@ static opj_image_t *ibuftoimage(ImBuf *ibuf, opj_cparameters_t *parameters)
case 16:
if (numcomps == 4) {
- if (channels_in_float == 4){
+ if (channels_in_float == 4) {
PIXEL_LOOPER_BEGIN(rect_float)
{
premul_to_straight_v4_v4(from_straight, rect_float);
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 3f6e6c59137..392c92148b4 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -27,6 +27,10 @@
/** \file DNA_action_types.h
* \ingroup DNA
+ *
+ * Define actions data-block for the animation system.
+ * A collection of animation curves and drivers to be assigned to data-blocks
+ * or sequenced in the non-linear-editor (NLA).
*/
#ifndef __DNA_ACTION_TYPES_H__
@@ -692,4 +696,4 @@ typedef enum ACHAN_FLAG {
ACHAN_MOVED = (1 << 31)
} ACHAN_FLAG;
-#endif
+#endif /* __DNA_ACTION_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h
index 7c4772f24e8..1495ba1b1a5 100644
--- a/source/blender/makesdna/DNA_actuator_types.h
+++ b/source/blender/makesdna/DNA_actuator_types.h
@@ -27,6 +27,8 @@
/** \file DNA_actuator_types.h
* \ingroup DNA
+ *
+ * #bActuator type is specifically for use by Object logic-bricks in the game-engine.
*/
#ifndef __DNA_ACTUATOR_TYPES_H__
@@ -535,6 +537,4 @@ typedef struct bActuator {
#define ACT_STEERING_AUTOMATICFACING 4
#define ACT_STEERING_NORMALUP 8
-#endif
-
-
+#endif /* __DNA_ACTUATOR_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 1ac6e6db94b..73e2a9f433b 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -284,15 +284,18 @@ typedef enum eDriverTarget_Flag {
/* used for targets that use the pchan_name instead of RNA path
* (i.e. rotation difference)
*/
- DTAR_FLAG_STRUCT_REF = (1<<0),
+ DTAR_FLAG_STRUCT_REF = (1 << 0),
/* idtype can only be 'Object' */
- DTAR_FLAG_ID_OB_ONLY = (1<<1),
+ DTAR_FLAG_ID_OB_ONLY = (1 << 1),
/* "localspace" flags */
/* base flag - basically "pre parent+constraints" */
- DTAR_FLAG_LOCALSPACE = (1<<2),
+ DTAR_FLAG_LOCALSPACE = (1 << 2),
/* include constraints transformed to space including parents */
- DTAR_FLAG_LOCAL_CONSTS = (1<<3),
+ DTAR_FLAG_LOCAL_CONSTS = (1 << 3),
+
+ /* error flags */
+ DTAR_FLAG_INVALID = (1 << 4),
} eDriverTarget_Flag;
/* Transform Channels for Driver Targets */
diff --git a/source/blender/makesdna/DNA_controller_types.h b/source/blender/makesdna/DNA_controller_types.h
index bdfedb5b4d1..0c1aaf5fd20 100644
--- a/source/blender/makesdna/DNA_controller_types.h
+++ b/source/blender/makesdna/DNA_controller_types.h
@@ -27,6 +27,8 @@
/** \file DNA_controller_types.h
* \ingroup DNA
+ *
+ * #bController type is specifically for use by Object logic-bricks in the game-engine.
*/
#ifndef __DNA_CONTROLLER_TYPES_H__
@@ -89,5 +91,4 @@ typedef struct bController {
#define CONT_PY_SCRIPT 0
#define CONT_PY_MODULE 1
-#endif
-
+#endif /* __DNA_CONTROLLER_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index e28b8780250..4a3debe756b 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -27,6 +27,8 @@
/** \file DNA_customdata_types.h
* \ingroup DNA
+ *
+ * Used for custom mesh data types (stored per vert/edge/loop/face)
*/
#ifndef __DNA_CUSTOMDATA_TYPES_H__
@@ -177,4 +179,4 @@ typedef struct CustomData {
}
#endif
-#endif
+#endif /* __DNA_CUSTOMDATA_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_defs.h b/source/blender/makesdna/DNA_defs.h
index 774fbcf081a..ffe4fc970b1 100644
--- a/source/blender/makesdna/DNA_defs.h
+++ b/source/blender/makesdna/DNA_defs.h
@@ -22,6 +22,8 @@
/** \file DNA_defs.h
* \ingroup DNA
+ *
+ * Group generic defines for all DNA headers may use in this file.
*/
#ifndef __DNA_DEFS_H__
diff --git a/source/blender/makesdna/DNA_group_types.h b/source/blender/makesdna/DNA_group_types.h
index a084bee1c2d..2740281b4c0 100644
--- a/source/blender/makesdna/DNA_group_types.h
+++ b/source/blender/makesdna/DNA_group_types.h
@@ -27,6 +27,8 @@
/** \file DNA_group_types.h
* \ingroup DNA
+ *
+ * \brief Object groups, one object can be in many groups at once.
*/
#ifndef __DNA_GROUP_TYPES_H__
@@ -58,4 +60,4 @@ typedef struct Group {
float dupli_ofs[3];
} Group;
-#endif
+#endif /* __DNA_GROUP_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 682f54481fc..54ec07c1855 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -101,10 +101,12 @@ typedef struct Image {
float lastupdate;
int lastused;
short animspeed;
+ short pad2;
/* for generated images */
- short gen_x, gen_y;
+ int gen_x, gen_y;
char gen_type, gen_flag;
+ char gen_pad[2];
/* display aspect - for UV editing images resized for faster openGL display */
float aspx, aspy;
diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h
index 6e5861043c1..4783247420c 100644
--- a/source/blender/makesdna/DNA_key_types.h
+++ b/source/blender/makesdna/DNA_key_types.h
@@ -29,6 +29,10 @@
/** \file DNA_key_types.h
* \ingroup DNA
+ *
+ * This file defines structures for Shape-Keys (not animation keyframes),
+ * attached to Mesh, Curve and Lattice Data. Even though Key's are ID blocks they
+ * aren't intended to be shared between multiple data blocks as with other ID types.
*/
#include "DNA_defs.h"
diff --git a/source/blender/makesdna/DNA_mask_types.h b/source/blender/makesdna/DNA_mask_types.h
index 5b25d1a072c..1b6b802f2de 100644
--- a/source/blender/makesdna/DNA_mask_types.h
+++ b/source/blender/makesdna/DNA_mask_types.h
@@ -30,6 +30,9 @@
* \ingroup DNA
* \since march-2012
* \author Sergey Sharybin
+ *
+ * Mask data-blocks are collections of 2D curves to be used
+ * for image masking in the compositor and sequencer.
*/
#ifndef __DNA_MASK_TYPES_H__
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 5aaf46a541f..62c997b72c6 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -854,4 +854,7 @@ typedef struct NodeShaderNormalMap {
#define CMP_NODE_MASK_MBLUR_SAMPLES_MAX 64
+/* image */
+#define CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT 1
+
#endif
diff --git a/source/blender/makesdna/DNA_property_types.h b/source/blender/makesdna/DNA_property_types.h
index c1b810cd42b..c8275a41404 100644
--- a/source/blender/makesdna/DNA_property_types.h
+++ b/source/blender/makesdna/DNA_property_types.h
@@ -31,6 +31,8 @@
* \author nzc
* \attention Renderrecipe and scene decription. The fact that there is a
* hierarchy here is a bit strange, and not desirable.
+ *
+ * #bProperty type is specifically for use by Objects game-logic.
*/
#ifndef __DNA_PROPERTY_TYPES_H__
@@ -60,5 +62,4 @@ typedef struct bProperty {
#define MAX_PROPSTRING 128
-#endif
-
+#endif /* __DNA_PROPERTY_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h
index c144bc4e588..4a96c324f04 100644
--- a/source/blender/makesdna/DNA_rigidbody_types.h
+++ b/source/blender/makesdna/DNA_rigidbody_types.h
@@ -80,9 +80,7 @@ typedef enum eRigidBodyWorld_Flag {
/* sim data needs to be rebuilt */
RBW_FLAG_NEEDS_REBUILD = (1 << 1),
/* usse split impulse when stepping the simulation */
- RBW_FLAG_USE_SPLIT_IMPULSE = (1 << 2),
- /* need to step simulation after frame update */
- RBW_FLAG_FRAME_UPDATE = (1 << 3)
+ RBW_FLAG_USE_SPLIT_IMPULSE = (1 << 2)
} eRigidBodyWorld_Flag;
/* ******************************** */
diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h
index 05927e3a486..d8cf80d047b 100644
--- a/source/blender/makesdna/DNA_sensor_types.h
+++ b/source/blender/makesdna/DNA_sensor_types.h
@@ -29,6 +29,8 @@
* \ingroup DNA
* \since mar-2001
* \author nzc
+ *
+ * #bSensor type is specifically for use by Object logic-bricks in the game-engine.
*/
#ifndef __DNA_SENSOR_TYPES_H__
@@ -324,5 +326,5 @@ typedef struct bJoystickSensor {
#define SENS_DELAY_REPEAT 1
// should match JOYINDEX_MAX in SCA_JoystickDefines.h */
#define SENS_JOY_MAXINDEX 8
-#endif
+#endif /* __DNA_SENSOR_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 0aa466f7245..455350d8310 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -28,6 +28,14 @@
* \ingroup DNA
* \since mar-2001
* \author nzc
+ *
+ * Structs for use by the 'Sequencer' (Video Editor)
+ *
+ * Note on terminology
+ * - #Sequence: video/effect/audio data you can select and manipulate in the sequencer.
+ * - #Sequence.machine: Strange name for the channel.
+ * - #Strip: The data referenced by the #Sequence
+ * - Meta Strip (SEQ_TYPE_META): Support for nesting Sequences.
*/
#ifndef __DNA_SEQUENCE_TYPES_H__
@@ -441,4 +449,4 @@ enum {
SEQUENCE_MASK_INPUT_ID = 1
};
-#endif
+#endif /* __DNA_SEQUENCE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 4c1d2c638b9..4587ed948cf 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -28,6 +28,8 @@
* \ingroup DNA
* \since mar-2001
* \author nzc
+ *
+ * Structs for each of space type in the user interface.
*/
#ifndef __DNA_SPACE_TYPES_H__
@@ -498,6 +500,7 @@ typedef enum eSpaceSeq_Flag {
SEQ_DRAW_SAFE_MARGINS = (1 << 3),
SEQ_SHOW_GPENCIL = (1 << 4),
SEQ_NO_DRAW_CFRANUM = (1 << 5),
+ SEQ_USE_ALPHA = (1 << 6), /* use RGBA display mode for preview */
} eSpaceSeq_Flag;
/* sseq->view */
@@ -1004,8 +1007,8 @@ typedef struct SpaceUserPref {
ListBase regionbase; /* storage of regions for inactive spaces */
int spacetype;
- int pad;
-
+ char pad[3];
+ char filter_type;
char filter[64]; /* search term for filtering in the UI */
} SpaceUserPref;
@@ -1133,4 +1136,4 @@ typedef enum eSpace_Type {
#define IMG_SIZE_FALLBACK 256
-#endif
+#endif /* __DNA_SPACE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h
index 3194adba3a0..8b18ecd7253 100644
--- a/source/blender/makesdna/DNA_text_types.h
+++ b/source/blender/makesdna/DNA_text_types.h
@@ -28,6 +28,9 @@
* \ingroup DNA
* \since mar-2001
* \author nzc
+ *
+ * Text blocks used for Python-Scripts, OpenShadingLanguage
+ * and arbitrary text data to store in blend files.
*/
#ifndef __DNA_TEXT_TYPES_H__
@@ -75,4 +78,4 @@ typedef struct Text {
#define TXT_FOLLOW 0x0200 /* always follow cursor (console) */
#define TXT_TABSTOSPACES 0x0400 /* use space instead of tabs */
-#endif
+#endif /* __DNA_TEXT_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index 8789a17a7f7..73cda070fd2 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -30,6 +30,8 @@
* \ingroup DNA
* \since may-2011
* \author Sergey Sharybin
+ *
+ * Structs used for camera tracking and the movie-clip editor.
*/
#ifndef __DNA_TRACKING_TYPES_H__
@@ -431,4 +433,4 @@ enum {
TRACKING_COVERAGE_OK = 2
};
-#endif
+#endif /* __DNA_TRACKING_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_vfont_types.h b/source/blender/makesdna/DNA_vfont_types.h
index 7aaeaf23db2..416c5f594a3 100644
--- a/source/blender/makesdna/DNA_vfont_types.h
+++ b/source/blender/makesdna/DNA_vfont_types.h
@@ -29,6 +29,9 @@
* \ingroup DNA
* \since mar-2001
* \author nzc
+ *
+ * Vector Fonts used for text in the 3D view-port
+ * (unrelated to text used to render the GUI).
*/
#ifndef __DNA_VFONT_TYPES_H__
@@ -63,5 +66,5 @@ typedef struct VFont {
#define FO_SELCHANGE 10
#define FO_BUILTIN_NAME "<builtin>"
-#endif
+#endif /* __DNA_VFONT_TYPES_H__ */
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 585e08ea706..44792951cad 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -290,6 +290,9 @@ add_executable(makesrna ${SRC} ${SRC_RNA_INC} ${SRC_DNA_INC})
target_link_libraries(makesrna bf_dna)
target_link_libraries(makesrna bf_dna_blenlib)
+# too many warnings with clang
+remove_cc_flag("-Wmissing-prototypes")
+
# Output rna_*_gen.c
# note (linux only): with crashes try add this after COMMAND: valgrind --leak-check=full --track-origins=yes
add_custom_command(
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index adfb096b25f..6035326e0ae 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -3196,18 +3196,16 @@ static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *pro
return 0;
}
+ /* check item array */
+ itemlen = RNA_property_array_length(&itemptr, itemprop);
+
/* dynamic array? need to get length per item */
if (itemprop->getlength) {
itemprop = NULL;
}
/* try to access as raw array */
else if (RNA_property_collection_raw_array(ptr, prop, itemprop, &out)) {
- int arraylen;
-
- /* check item array */
- itemlen = RNA_property_array_length(&itemptr, itemprop);
-
- arraylen = (itemlen == 0) ? 1 : itemlen;
+ int arraylen = (itemlen == 0) ? 1 : itemlen;
if (in.len != arraylen * out.len) {
BKE_reportf(reports, RPT_ERROR, "Array length mismatch (expected %d, got %d)",
out.len * arraylen, in.len);
@@ -4866,7 +4864,7 @@ static char *rna_pointer_as_string__bldata(PointerRNA *ptr)
}
}
-char *RNA_pointer_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop_ptr, PointerRNA *ptr_prop)
+char *RNA_pointer_as_string(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *prop_ptr, PointerRNA *ptr_prop)
{
if (RNA_property_flag(prop_ptr) & PROP_IDPROPERTY) {
return rna_pointer_as_string__idprop(C, ptr_prop);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 1fff567f25c..73fe5f3a48d 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -2412,7 +2412,12 @@ static void def_cmp_image(StructRNA *srna)
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Image", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
+
+ prop = RNA_def_property(srna, "use_straight_alpha_output", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT);
+ RNA_def_property_ui_text(prop, "Straight Alpha Output", "Put Node output buffer to straight alpha instead of premultiplied");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
/* NB: image user properties used in the UI are redefined in def_node_image_user,
* to trigger correct updates of the node editor. RNA design problem that prevents
* updates from nested structs ...
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index d6f3f594395..4bf5de03b05 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -2892,7 +2892,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_float_funcs(prop, "rna_PartSetting_linelentail_get", "rna_PartSetting_linelentail_set", NULL);
RNA_def_property_range(prop, 0.0f, 100000.0f);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1, 3);
- RNA_def_property_ui_text(prop, "Back", "Length of the line's tail");
+ RNA_def_property_ui_text(prop, "Tail", "Length of the line's tail");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "line_length_head", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 5931440b422..e2e373d8beb 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -299,19 +299,19 @@ static void rna_def_render_engine(BlenderRNA *brna)
/* final render callbacks */
func = RNA_def_function(srna, "update", NULL);
RNA_def_function_ui_description(func, "Export scene data for render");
- RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
RNA_def_pointer(func, "data", "BlendData", "", "");
RNA_def_pointer(func, "scene", "Scene", "", "");
func = RNA_def_function(srna, "render", NULL);
RNA_def_function_ui_description(func, "Render scene into an image");
- RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
RNA_def_pointer(func, "scene", "Scene", "", "");
/* viewport render callbacks */
func = RNA_def_function(srna, "view_update", NULL);
RNA_def_function_ui_description(func, "Update on data changes for viewport render");
- RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
RNA_def_pointer(func, "context", "Context", "", "");
func = RNA_def_function(srna, "view_draw", NULL);
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index f5cf247b5a1..171bc702bc5 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -234,6 +234,20 @@ static void rna_RigidBodyOb_collision_margin_set(PointerRNA *ptr, float value)
#endif
}
+static void rna_RigidBodyOb_collision_groups_set(PointerRNA *ptr, const int *values)
+{
+ RigidBodyOb *rbo = (RigidBodyOb *)ptr->data;
+ int i;
+
+ for (i = 0; i < 20; i++) {
+ if (values[i])
+ rbo->col_groups |= (1 << i);
+ else
+ rbo->col_groups &= ~(1 << i);
+ }
+ rbo->flag |= RBO_FLAG_NEEDS_VALIDATE;
+}
+
static void rna_RigidBodyOb_kinematic_state_set(PointerRNA *ptr, int value)
{
RigidBodyOb *rbo = (RigidBodyOb *)ptr->data;
@@ -812,6 +826,7 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "collision_groups", PROP_BOOLEAN, PROP_LAYER_MEMBER);
RNA_def_property_boolean_sdna(prop, NULL, "col_groups", 1);
RNA_def_property_array(prop, 20);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyOb_collision_groups_set");
RNA_def_property_ui_text(prop, "Collision Groups", "Collision Groups Rigid Body belongs to");
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
@@ -949,13 +964,13 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_motor_lin", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_MOTOR_LIN);
RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyCon_use_motor_lin_set");
- RNA_def_property_ui_text(prop, "Linear Motor", "Enables linear motor");
+ RNA_def_property_ui_text(prop, "Linear Motor", "Enable linear motor");
RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
prop = RNA_def_property(srna, "use_motor_ang", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_MOTOR_ANG);
RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyCon_use_motor_ang_set");
- RNA_def_property_ui_text(prop, "Angular Motor", "Enables angular motor");
+ RNA_def_property_ui_text(prop, "Angular Motor", "Enable angular motor");
RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
prop = RNA_def_property(srna, "limit_lin_x_lower", PROP_FLOAT, PROP_UNIT_LENGTH);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 20269005b3f..906c8853179 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -916,16 +916,13 @@ static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_codecType_itemf(bCon
EnumPropertyItem tmp = {0, "", 0, "", ""};
QuicktimeCodecTypeDesc *codecTypeDesc;
int i = 1, totitem = 0;
- char id[5];
-
+
for (i = 0; i < quicktime_get_num_videocodecs(); i++) {
codecTypeDesc = quicktime_get_videocodecType_desc(i);
if (!codecTypeDesc) break;
-
+
tmp.value = codecTypeDesc->rnatmpvalue;
- *((int *)id) = codecTypeDesc->codecType;
- id[4] = 0;
- tmp.identifier = id;
+ tmp.identifier = codecTypeDesc->codecName;
tmp.name = codecTypeDesc->codecName;
RNA_enum_item_add(&item, &totitem, &tmp);
}
@@ -1586,8 +1583,8 @@ static void rna_def_tool_settings(BlenderRNA *brna)
static EnumPropertyItem draw_groupuser_items[] = {
{OB_DRAW_GROUPUSER_NONE, "NONE", 0, "None", ""},
- {OB_DRAW_GROUPUSER_ACTIVE, "ACTIVE", 0, "Active", "Show vertices with no weights in the actuve group"},
- {OB_DRAW_GROUPUSER_ALL, "ALL", 0, "All", "Show vertices with no weights in the any group"},
+ {OB_DRAW_GROUPUSER_ACTIVE, "ACTIVE", 0, "Active", "Show vertices with no weights in the active group"},
+ {OB_DRAW_GROUPUSER_ALL, "ALL", 0, "All", "Show vertices with no weights in any group"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index b0df27b957b..b3619330e7a 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -111,6 +111,7 @@ static void rna_Scene_collada_export(
int include_material_textures,
int use_texture_copies,
+ int use_ngons,
int use_object_instantiation,
int sort_by_name,
int second_life)
@@ -118,7 +119,7 @@ static void rna_Scene_collada_export(
collada_export(scene, filepath, apply_modifiers, export_mesh_type, selected,
include_children, include_armatures, include_shapekeys, deform_bones_only,
active_uv_only, include_uv_textures, include_material_textures,
- use_texture_copies, use_object_instantiation, sort_by_name, second_life);
+ use_texture_copies, use_ngons, use_object_instantiation, sort_by_name, second_life);
}
#endif
@@ -160,6 +161,7 @@ void RNA_api_scene(StructRNA *srna)
parm = RNA_def_boolean(func, "include_material_textures", 0, "Include Material Textures", "Export textures assigned to the object Materials");
parm = RNA_def_boolean(func, "use_texture_copies", 0, "copy", "Copy textures to same folder where the .dae file is exported");
+ parm = RNA_def_boolean(func, "use_ngons", 1, "Use NGons", "Keep NGons in Export");
parm = RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances", "Instantiate multiple Objects from same Data");
parm = RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name", "Sort exported data by Object name");
parm = RNA_def_boolean(func, "second_life", 0, "Export for Second Life", "Compatibility mode for Second Life");
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 7dc2dbf3d03..f1f4c13731f 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -2249,6 +2249,13 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem preview_channels_items[] = {
+ {SEQ_USE_ALPHA, "COLOR_ALPHA", ICON_IMAGE_RGB_ALPHA, "Color and Alpha",
+ "Draw image with RGB colors and alpha transparency"},
+ {0, "COLOR", ICON_IMAGE_RGB, "Color", "Draw image with RGB colors"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "SpaceSequenceEditor", "Space");
RNA_def_struct_sdna(srna, "SpaceSeq");
RNA_def_struct_ui_text(srna, "Space Sequence Editor", "Sequence editor space data");
@@ -2266,7 +2273,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_enum_items(prop, display_mode_items);
RNA_def_property_ui_text(prop, "Display Mode", "View mode to use for displaying sequencer output");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
/* flags */
prop = RNA_def_property(srna, "show_frame_indicator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SEQ_NO_DRAW_CFRANUM);
@@ -2311,7 +2318,13 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
"The channel number shown in the image preview. 0 is the result of all strips combined");
RNA_def_property_range(prop, -5, MAXSEQ);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
+ prop = RNA_def_property(srna, "preview_channels", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, preview_channels_items);
+ RNA_def_property_ui_text(prop, "Draw Channels", "Channels of the preview to draw");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
prop = RNA_def_property(srna, "draw_overexposed", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "zebra");
RNA_def_property_ui_text(prop, "Show Overexposed", "Show overexposed areas with zebra stripes");
@@ -3042,13 +3055,24 @@ static void rna_def_space_info(BlenderRNA *brna)
static void rna_def_space_userpref(BlenderRNA *brna)
{
+ static EnumPropertyItem filter_type_items[] = {
+ {0, "NAME", 0, "Name", "Filter based on the operator name"},
+ {1, "KEY", 0, "Key-Binding", "Filter based on key bindings"},
+ {0, NULL, 0, NULL, NULL}};
+
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "SpaceUserPreferences", "Space");
RNA_def_struct_sdna(srna, "SpaceUserPref");
RNA_def_struct_ui_text(srna, "Space User Preferences", "User preferences space data");
-
+
+ prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "filter_type");
+ RNA_def_property_enum_items(prop, filter_type_items);
+ RNA_def_property_ui_text(prop, "Filter Type", "Filter method");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+
prop = RNA_def_property(srna, "filter_text", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "filter");
RNA_def_property_ui_text(prop, "Filter", "Search term for filtering in the UI");
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index cd646f4849c..798395b9fef 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -579,6 +579,9 @@ static void rna_def_trackingSettings(BlenderRNA *brna)
{REFINE_FOCAL_LENGTH |
REFINE_PRINCIPAL_POINT, "FOCAL_LENGTH_PRINCIPAL_POINT", 0, "Focal Length, Optical Center",
"Refine focal length and optical center"},
+ {REFINE_RADIAL_DISTORTION_K1 |
+ REFINE_RADIAL_DISTORTION_K2, "RADIAL_K1_K2", 0, "K1, K2",
+ "Refine radial distortion K1 and K2"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 2530a230e0a..d5620f91d6e 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -137,13 +137,13 @@ static void sphere_do(
int i, defgrp_index;
int has_radius = 0;
short flag, type;
- float fac, facm, len = 0.0f;
+ float len = 0.0f;
+ float fac = cmd->fac;
+ float facm = 1.0f - fac;
+ const float fac_orig = fac;
float vec[3], center[3] = {0.0f, 0.0f, 0.0f};
float mat[4][4], imat[4][4];
- fac = cmd->fac;
- facm = 1.0f - fac;
-
flag = cmd->flag;
type = cmd->type; /* projection type: sphere or cylinder */
@@ -193,67 +193,6 @@ static void sphere_do(
if (len == 0.0f) len = 10.0f;
}
- /* ready to apply the effect, one vertex at a time;
- * tiny optimization: the code is separated (with parts repeated)
- * in two possible cases:
- * with or w/o a vgroup. With lots of if's in the code below,
- * further optimization's are possible, if needed */
- if (dvert) { /* with a vgroup */
- MDeformVert *dv = dvert;
- float fac_orig = fac;
- for (i = 0; i < numVerts; i++, dv++) {
- float tmp_co[3];
- float weight;
-
- copy_v3_v3(tmp_co, vertexCos[i]);
- if (ctrl_ob) {
- if (flag & MOD_CAST_USE_OB_TRANSFORM) {
- mul_m4_v3(mat, tmp_co);
- }
- else {
- sub_v3_v3(tmp_co, center);
- }
- }
-
- copy_v3_v3(vec, tmp_co);
-
- if (type == MOD_CAST_TYPE_CYLINDER)
- vec[2] = 0.0f;
-
- if (has_radius) {
- if (len_v3(vec) > cmd->radius) continue;
- }
-
- weight = defvert_find_weight(dv, defgrp_index);
- if (weight <= 0.0f) continue;
-
- fac = fac_orig * weight;
- facm = 1.0f - fac;
-
- normalize_v3(vec);
-
- if (flag & MOD_CAST_X)
- tmp_co[0] = fac * vec[0] * len + facm * tmp_co[0];
- if (flag & MOD_CAST_Y)
- tmp_co[1] = fac * vec[1] * len + facm * tmp_co[1];
- if (flag & MOD_CAST_Z)
- tmp_co[2] = fac * vec[2] * len + facm * tmp_co[2];
-
- if (ctrl_ob) {
- if (flag & MOD_CAST_USE_OB_TRANSFORM) {
- mul_m4_v3(imat, tmp_co);
- }
- else {
- add_v3_v3(tmp_co, center);
- }
- }
-
- copy_v3_v3(vertexCos[i], tmp_co);
- }
- return;
- }
-
- /* no vgroup */
for (i = 0; i < numVerts; i++) {
float tmp_co[3];
@@ -276,6 +215,16 @@ static void sphere_do(
if (len_v3(vec) > cmd->radius) continue;
}
+ if (dvert) {
+ const float weight = defvert_find_weight(&dvert[i], defgrp_index);
+ if (weight == 0.0f) {
+ continue;
+ }
+
+ fac = fac_orig * weight;
+ facm = 1.0f - fac;
+ }
+
normalize_v3(vec);
if (flag & MOD_CAST_X)
@@ -308,14 +257,13 @@ static void cuboid_do(
int i, defgrp_index;
int has_radius = 0;
short flag;
- float fac, facm;
+ float fac = cmd->fac;
+ float facm = 1.0f - fac;
+ const float fac_orig = fac;
float min[3], max[3], bb[8][3];
float center[3] = {0.0f, 0.0f, 0.0f};
float mat[4][4], imat[4][4];
- fac = cmd->fac;
- facm = 1.0f - fac;
-
flag = cmd->flag;
ctrl_ob = cmd->object;
@@ -397,118 +345,10 @@ static void cuboid_do(
bb[0][2] = bb[1][2] = bb[2][2] = bb[3][2] = min[2];
bb[4][2] = bb[5][2] = bb[6][2] = bb[7][2] = max[2];
- /* ready to apply the effect, one vertex at a time;
- * tiny optimization: the code is separated (with parts repeated)
- * in two possible cases:
- * with or w/o a vgroup. With lots of if's in the code below,
- * further optimization's are possible, if needed */
- if (dvert) { /* with a vgroup */
- float fac_orig = fac;
- for (i = 0; i < numVerts; i++) {
- MDeformWeight *dw = NULL;
- int j, octant, coord;
- float d[3], dmax, apex[3], fbb;
- float tmp_co[3];
-
- copy_v3_v3(tmp_co, vertexCos[i]);
- if (ctrl_ob) {
- if (flag & MOD_CAST_USE_OB_TRANSFORM) {
- mul_m4_v3(mat, tmp_co);
- }
- else {
- sub_v3_v3(tmp_co, center);
- }
- }
-
- if (has_radius) {
- if (fabsf(tmp_co[0]) > cmd->radius ||
- fabsf(tmp_co[1]) > cmd->radius ||
- fabsf(tmp_co[2]) > cmd->radius)
- {
- continue;
- }
- }
-
- for (j = 0; j < dvert[i].totweight; ++j) {
- if (dvert[i].dw[j].def_nr == defgrp_index) {
- dw = &dvert[i].dw[j];
- break;
- }
- }
- if (!dw) continue;
-
- fac = fac_orig * dw->weight;
- facm = 1.0f - fac;
-
- /* The algo used to project the vertices to their
- * bounding box (bb) is pretty simple:
- * for each vertex v:
- * 1) find in which octant v is in;
- * 2) find which outer "wall" of that octant is closer to v;
- * 3) calculate factor (var fbb) to project v to that wall;
- * 4) project. */
-
- /* find in which octant this vertex is in */
- octant = 0;
- if (tmp_co[0] > 0.0f) octant += 1;
- if (tmp_co[1] > 0.0f) octant += 2;
- if (tmp_co[2] > 0.0f) octant += 4;
-
- /* apex is the bb's vertex at the chosen octant */
- copy_v3_v3(apex, bb[octant]);
-
- /* find which bb plane is closest to this vertex ... */
- d[0] = tmp_co[0] / apex[0];
- d[1] = tmp_co[1] / apex[1];
- d[2] = tmp_co[2] / apex[2];
-
- /* ... (the closest has the higher (closer to 1) d value) */
- dmax = d[0];
- coord = 0;
- if (d[1] > dmax) {
- dmax = d[1];
- coord = 1;
- }
- if (d[2] > dmax) {
- /* dmax = d[2]; */ /* commented, we don't need it */
- coord = 2;
- }
-
- /* ok, now we know which coordinate of the vertex to use */
-
- if (fabsf(tmp_co[coord]) < FLT_EPSILON) /* avoid division by zero */
- continue;
-
- /* finally, this is the factor we wanted, to project the vertex
- * to its bounding box (bb) */
- fbb = apex[coord] / tmp_co[coord];
-
- /* calculate the new vertex position */
- if (flag & MOD_CAST_X)
- tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb;
- if (flag & MOD_CAST_Y)
- tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb;
- if (flag & MOD_CAST_Z)
- tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb;
-
- if (ctrl_ob) {
- if (flag & MOD_CAST_USE_OB_TRANSFORM) {
- mul_m4_v3(imat, tmp_co);
- }
- else {
- add_v3_v3(tmp_co, center);
- }
- }
-
- copy_v3_v3(vertexCos[i], tmp_co);
- }
- return;
- }
-
- /* no vgroup (check previous case for comments about the code) */
+ /* ready to apply the effect, one vertex at a time */
for (i = 0; i < numVerts; i++) {
int octant, coord;
- float d[3], dmax, fbb, apex[3];
+ float d[3], dmax, apex[3], fbb;
float tmp_co[3];
copy_v3_v3(tmp_co, vertexCos[i]);
@@ -530,17 +370,39 @@ static void cuboid_do(
}
}
+ if (dvert) {
+ const float weight = defvert_find_weight(&dvert[i], defgrp_index);
+ if (weight == 0.0f) {
+ continue;
+ }
+
+ fac = fac_orig * weight;
+ facm = 1.0f - fac;
+ }
+
+ /* The algo used to project the vertices to their
+ * bounding box (bb) is pretty simple:
+ * for each vertex v:
+ * 1) find in which octant v is in;
+ * 2) find which outer "wall" of that octant is closer to v;
+ * 3) calculate factor (var fbb) to project v to that wall;
+ * 4) project. */
+
+ /* find in which octant this vertex is in */
octant = 0;
if (tmp_co[0] > 0.0f) octant += 1;
if (tmp_co[1] > 0.0f) octant += 2;
if (tmp_co[2] > 0.0f) octant += 4;
+ /* apex is the bb's vertex at the chosen octant */
copy_v3_v3(apex, bb[octant]);
+ /* find which bb plane is closest to this vertex ... */
d[0] = tmp_co[0] / apex[0];
d[1] = tmp_co[1] / apex[1];
d[2] = tmp_co[2] / apex[2];
+ /* ... (the closest has the higher (closer to 1) d value) */
dmax = d[0];
coord = 0;
if (d[1] > dmax) {
@@ -552,11 +414,16 @@ static void cuboid_do(
coord = 2;
}
- if (fabsf(tmp_co[coord]) < FLT_EPSILON)
+ /* ok, now we know which coordinate of the vertex to use */
+
+ if (fabsf(tmp_co[coord]) < FLT_EPSILON) /* avoid division by zero */
continue;
+ /* finally, this is the factor we wanted, to project the vertex
+ * to its bounding box (bb) */
fbb = apex[coord] / tmp_co[coord];
+ /* calculate the new vertex position */
if (flag & MOD_CAST_X)
tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb;
if (flag & MOD_CAST_Y)
diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c
index 5e702a4eabc..be7bfae22fb 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -251,7 +251,7 @@ static void meshcache_do(
/* -------------------------------------------------------------------- */
/* Apply the transformation matrix (if needed) */
if (UNLIKELY(err_str)) {
- modifier_setError(&mcmd->modifier, err_str);
+ modifier_setError(&mcmd->modifier, "%s", err_str);
}
else if (ok) {
bool use_matrix = false;
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 038fb4913ec..a198eaf8ca9 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -29,6 +29,7 @@
* \ingroup modifiers
*/
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "MEM_guardedalloc.h"
@@ -598,6 +599,10 @@ static DerivedMesh *applyModifier(
int *orig_ed;
int j;
+ if (crease_rim || crease_outer || crease_inner) {
+ result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
+ }
+
/* add faces & edges */
origindex_edge = result->getEdgeDataArray(result, CD_ORIGINDEX);
ed = &medge[numEdges * 2];
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index c0d46b14aa8..c48682b877e 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -107,6 +107,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
subsurf_flags |= SUBSURF_IN_EDIT_MODE;
result = subsurf_make_derived_from_derived(derivedData, smd, NULL, subsurf_flags);
+ result->cd_flag = derivedData->cd_flag;
if (useRenderParams || !isFinalCalc) {
DerivedMesh *cddm = CDDM_copy(result);
diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c
index 7a8b8c940c9..8cf7cc7a1ea 100644
--- a/source/blender/nodes/intern/node_exec.c
+++ b/source/blender/nodes/intern/node_exec.c
@@ -248,8 +248,9 @@ void ntree_exec_end(bNodeTreeExec *exec)
MEM_freeN(exec->stack);
for (n=0, nodeexec= exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
- if (nodeexec->node->typeinfo->freeexecfunc)
- nodeexec->node->typeinfo->freeexecfunc(nodeexec->node, nodeexec->data);
+ if (nodeexec->node->typeinfo)
+ if (nodeexec->node->typeinfo->freeexecfunc)
+ nodeexec->node->typeinfo->freeexecfunc(nodeexec->node, nodeexec->data);
}
if (exec->nodeexec)
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 19ec35ae357..cef4e23242d 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -4257,11 +4257,12 @@ static PyObject *pyrna_prop_collection_find(BPy_PropertyRNA *self, PyObject *key
return PyLong_FromLong(index);
}
-static void foreach_attr_type(BPy_PropertyRNA *self, const char *attr,
+static bool foreach_attr_type(BPy_PropertyRNA *self, const char *attr,
/* values to assign */
RawPropertyType *raw_type, int *attr_tot, bool *attr_signed)
{
PropertyRNA *prop;
+ bool attr_ok = true;
*raw_type = PROP_RAW_UNSET;
*attr_tot = 0;
*attr_signed = false;
@@ -4270,12 +4271,19 @@ static void foreach_attr_type(BPy_PropertyRNA *self, const char *attr,
RNA_PROP_BEGIN (&self->ptr, itemptr, self->prop)
{
prop = RNA_struct_find_property(&itemptr, attr);
- *raw_type = RNA_property_raw_type(prop);
- *attr_tot = RNA_property_array_length(&itemptr, prop);
- *attr_signed = (RNA_property_subtype(prop) == PROP_UNSIGNED) ? false : true;
+ if (prop) {
+ *raw_type = RNA_property_raw_type(prop);
+ *attr_tot = RNA_property_array_length(&itemptr, prop);
+ *attr_signed = (RNA_property_subtype(prop) != PROP_UNSIGNED);
+ }
+ else {
+ attr_ok = false;
+ }
break;
}
RNA_PROP_END;
+
+ return attr_ok;
}
/* pyrna_prop_collection_foreach_get/set both use this */
@@ -4295,15 +4303,26 @@ static int foreach_parse_args(BPy_PropertyRNA *self, PyObject *args,
*attr_signed = false;
*raw_type = PROP_RAW_UNSET;
- if (!PyArg_ParseTuple(args, "sO", attr, seq) || (!PySequence_Check(*seq) && PyObject_CheckBuffer(*seq))) {
- PyErr_SetString(PyExc_TypeError, "foreach_get(attr, sequence) expects a string and a sequence");
+ if (!PyArg_ParseTuple(args, "sO:foreach_get/set", attr, seq)) {
+ return -1;
+ }
+
+ if (!PySequence_Check(*seq) && PyObject_CheckBuffer(*seq)) {
+ PyErr_Format(PyExc_TypeError,
+ "foreach_get/set expected second argument to be a sequence or buffer, not a %.200s",
+ Py_TYPE(seq)->tp_name);
return -1;
}
*tot = PySequence_Size(*seq); /* TODO - buffer may not be a sequence! array.array() is tho. */
if (*tot > 0) {
- foreach_attr_type(self, *attr, raw_type, attr_tot, attr_signed);
+ if (!foreach_attr_type(self, *attr, raw_type, attr_tot, attr_signed)) {
+ PyErr_Format(PyExc_AttributeError,
+ "foreach_get/set '%.200s.%200s[...]' elements have no attribute '%.200s'",
+ RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop), *attr);
+ return -1;
+ }
*size = RNA_raw_type_sizeof(*raw_type);
#if 0 /* works fine but not strictly needed, we could allow RNA_property_collection_raw_* to do the checks */
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index a19f8e2d8ed..b61ed55da06 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -156,7 +156,8 @@ static int pyrna_struct_keyframe_parse(
/* note, parse_str MUST start with 's|ifsO!' */
if (!PyArg_ParseTupleAndKeywords(args, kw, parse_str, (char **)kwlist, &path, index, cfra, group_name,
- &PySet_Type, &pyoptions)) {
+ &PySet_Type, &pyoptions))
+ {
return -1;
}
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index effc564fdc9..12d36ccfdd2 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -166,7 +166,8 @@ if(WITH_GAMEENGINE)
endif()
if(APPLE)
- if(CMAKE_OSX_ARCHITECTURES MATCHES "i386" OR CMAKE_OSX_ARCHITECTURES MATCHES "x86_64")
+ # SSE math is enabled by default on x86_64
+ if(CMAKE_OSX_ARCHITECTURES MATCHES "i386")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mfpmath=sse")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mfpmath=sse")
endif()
diff --git a/source/blender/render/intern/raytrace/reorganize.h b/source/blender/render/intern/raytrace/reorganize.h
index 9d9711eee56..5624df25267 100644
--- a/source/blender/render/intern/raytrace/reorganize.h
+++ b/source/blender/render/intern/raytrace/reorganize.h
@@ -80,7 +80,6 @@ void reorganize_find_fittest_parent(Node *tree, Node *node, std::pair<float, Nod
}
}
-static int tot_moves = 0;
template<class Node>
void reorganize(Node *root)
{
@@ -109,8 +108,6 @@ void reorganize(Node *root)
tmp->sibling = best.second->child;
best.second->child = tmp;
-
- tot_moves++;
}
diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c
index 747362a7974..1c594ef7db2 100644
--- a/source/blender/render/intern/source/occlusion.c
+++ b/source/blender/render/intern/source/occlusion.c
@@ -763,414 +763,6 @@ static float occ_solid_angle(OccNode *node, const float v[3], float d2, float in
return ((node->area * dotemit * dotreceive) / (d2 + node->area * INVPI)) * INVPI;
}
-static void vec_add_dir(float r[3], const float v1[3], const float v2[3], const float fac)
-{
- r[0] = v1[0] + fac * (v2[0] - v1[0]);
- r[1] = v1[1] + fac * (v2[1] - v1[1]);
- r[2] = v1[2] + fac * (v2[2] - v1[2]);
-}
-
-/* TODO: exact duplicate of ff_visible_quad() in math_geom.c
- * why not de-duplicate? (also above helper func) */
-static int occ_visible_quad(const float p[3], const float n[3],
- const float v0[3], const float v1[3], const float v2[3],
- float q0[3], float q1[3], float q2[3], float q3[3])
-{
- static const float epsilon = 1e-6f;
- float c, sd[3];
-
- c = dot_v3v3(n, p);
-
- /* signed distances from the vertices to the plane. */
- sd[0] = dot_v3v3(n, v0) - c;
- sd[1] = dot_v3v3(n, v1) - c;
- sd[2] = dot_v3v3(n, v2) - c;
-
- if (fabsf(sd[0]) < epsilon) sd[0] = 0.0f;
- if (fabsf(sd[1]) < epsilon) sd[1] = 0.0f;
- if (fabsf(sd[2]) < epsilon) sd[2] = 0.0f;
-
- if (sd[0] > 0) {
- if (sd[1] > 0) {
- if (sd[2] > 0) {
- /* +++ */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* ++- */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- vec_add_dir(q2, v1, v2, (sd[1] / (sd[1] - sd[2])));
- vec_add_dir(q3, v0, v2, (sd[0] / (sd[0] - sd[2])));
- }
- else {
- /* ++0 */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- }
- else if (sd[1] < 0) {
- if (sd[2] > 0) {
- /* +-+ */
- copy_v3_v3(q0, v0);
- vec_add_dir(q1, v0, v1, (sd[0] / (sd[0] - sd[1])));
- vec_add_dir(q2, v1, v2, (sd[1] / (sd[1] - sd[2])));
- copy_v3_v3(q3, v2);
- }
- else if (sd[2] < 0) {
- /* +-- */
- copy_v3_v3(q0, v0);
- vec_add_dir(q1, v0, v1, (sd[0] / (sd[0] - sd[1])));
- vec_add_dir(q2, v0, v2, (sd[0] / (sd[0] - sd[2])));
- copy_v3_v3(q3, q2);
- }
- else {
- /* +-0 */
- copy_v3_v3(q0, v0);
- vec_add_dir(q1, v0, v1, (sd[0] / (sd[0] - sd[1])));
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- }
- else {
- if (sd[2] > 0) {
- /* +0+ */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* +0- */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- vec_add_dir(q2, v0, v2, (sd[0] / (sd[0] - sd[2])));
- copy_v3_v3(q3, q2);
- }
- else {
- /* +00 */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- }
- }
- else if (sd[0] < 0) {
- if (sd[1] > 0) {
- if (sd[2] > 0) {
- /* -++ */
- vec_add_dir(q0, v0, v1, (sd[0] / (sd[0] - sd[1])));
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- vec_add_dir(q3, v0, v2, (sd[0] / (sd[0] - sd[2])));
- }
- else if (sd[2] < 0) {
- /* -+- */
- vec_add_dir(q0, v0, v1, (sd[0] / (sd[0] - sd[1])));
- copy_v3_v3(q1, v1);
- vec_add_dir(q2, v1, v2, (sd[1] / (sd[1] - sd[2])));
- copy_v3_v3(q3, q2);
- }
- else {
- /* -+0 */
- vec_add_dir(q0, v0, v1, (sd[0] / (sd[0] - sd[1])));
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- }
- else if (sd[1] < 0) {
- if (sd[2] > 0) {
- /* --+ */
- vec_add_dir(q0, v0, v2, (sd[0] / (sd[0] - sd[2])));
- vec_add_dir(q1, v1, v2, (sd[1] / (sd[1] - sd[2])));
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* --- */
- return 0;
- }
- else {
- /* --0 */
- return 0;
- }
- }
- else {
- if (sd[2] > 0) {
- /* -0+ */
- vec_add_dir(q0, v0, v2, (sd[0] / (sd[0] - sd[2])));
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* -0- */
- return 0;
- }
- else {
- /* -00 */
- return 0;
- }
- }
- }
- else {
- if (sd[1] > 0) {
- if (sd[2] > 0) {
- /* 0++ */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* 0+- */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- vec_add_dir(q2, v1, v2, (sd[1] / (sd[1] - sd[2])));
- copy_v3_v3(q3, q2);
- }
- else {
- /* 0+0 */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- }
- else if (sd[1] < 0) {
- if (sd[2] > 0) {
- /* 0-+ */
- copy_v3_v3(q0, v0);
- vec_add_dir(q1, v1, v2, (sd[1] / (sd[1] - sd[2])));
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* 0-- */
- return 0;
- }
- else {
- /* 0-0 */
- return 0;
- }
- }
- else {
- if (sd[2] > 0) {
- /* 00+ */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* 00- */
- return 0;
- }
- else {
- /* 000 */
- return 0;
- }
- }
- }
-
- return 1;
-}
-
-/* altivec optimization, this works, but is unused */
-
-#if 0
-#include <Accelerate/Accelerate.h>
-
-typedef union {
- vFloat v;
- float f[4];
-} vFloatResult;
-
-static vFloat vec_splat_float(float val)
-{
- return (vFloat) {val, val, val, val};
-}
-
-static float occ_quad_form_factor(float *p, float *n, float *q0, float *q1, float *q2, float *q3)
-{
- vFloat vcos, rlen, vrx, vry, vrz, vsrx, vsry, vsrz, gx, gy, gz, vangle;
- vUInt8 rotate = (vUInt8) {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3};
- vFloatResult vresult;
- float result;
-
- /* compute r* */
- vrx = (vFloat) {q0[0], q1[0], q2[0], q3[0]} -vec_splat_float(p[0]);
- vry = (vFloat) {q0[1], q1[1], q2[1], q3[1]} -vec_splat_float(p[1]);
- vrz = (vFloat) {q0[2], q1[2], q2[2], q3[2]} -vec_splat_float(p[2]);
-
- /* normalize r* */
- rlen = vec_rsqrte(vrx * vrx + vry * vry + vrz * vrz + vec_splat_float(1e-16f));
- vrx = vrx * rlen;
- vry = vry * rlen;
- vrz = vrz * rlen;
-
- /* rotate r* for cross and dot */
- vsrx = vec_perm(vrx, vrx, rotate);
- vsry = vec_perm(vry, vry, rotate);
- vsrz = vec_perm(vrz, vrz, rotate);
-
- /* cross product */
- gx = vsry * vrz - vsrz * vry;
- gy = vsrz * vrx - vsrx * vrz;
- gz = vsrx * vry - vsry * vrx;
-
- /* normalize */
- rlen = vec_rsqrte(gx * gx + gy * gy + gz * gz + vec_splat_float(1e-16f));
- gx = gx * rlen;
- gy = gy * rlen;
- gz = gz * rlen;
-
- /* angle */
- vcos = vrx * vsrx + vry * vsry + vrz * vsrz;
- vcos = vec_max(vec_min(vcos, vec_splat_float(1.0f)), vec_splat_float(-1.0f));
- vangle = vacosf(vcos);
-
- /* dot */
- vresult.v = (vec_splat_float(n[0]) * gx +
- vec_splat_float(n[1]) * gy +
- vec_splat_float(n[2]) * gz) * vangle;
-
- result = (vresult.f[0] + vresult.f[1] + vresult.f[2] + vresult.f[3]) * (0.5f / (float)M_PI);
- result = MAX2(result, 0.0f);
-
- return result;
-}
-
-#endif
-
-/* SSE optimization, acos code doesn't work */
-
-#if 0
-
-#include <xmmintrin.h>
-
-static __m128 sse_approx_acos(__m128 x)
-{
- /* needs a better approximation than taylor expansion of acos, since that
- * gives big erros for near 1.0 values, sqrt(2*x)*acos(1-x) should work
- * better, see http://www.tom.womack.net/projects/sse-fast-arctrig.html */
-
- return _mm_set_ps1(1.0f);
-}
-
-static float occ_quad_form_factor(float *p, float *n, float *q0, float *q1, float *q2, float *q3)
-{
- float r0[3], r1[3], r2[3], r3[3], g0[3], g1[3], g2[3], g3[3];
- float a1, a2, a3, a4, dot1, dot2, dot3, dot4, result;
- float fresult[4] __attribute__((aligned(16)));
- __m128 qx, qy, qz, rx, ry, rz, rlen, srx, sry, srz, gx, gy, gz, glen, rcos, angle, aresult;
-
- /* compute r */
- qx = _mm_set_ps(q3[0], q2[0], q1[0], q0[0]);
- qy = _mm_set_ps(q3[1], q2[1], q1[1], q0[1]);
- qz = _mm_set_ps(q3[2], q2[2], q1[2], q0[2]);
-
- rx = qx - _mm_set_ps1(p[0]);
- ry = qy - _mm_set_ps1(p[1]);
- rz = qz - _mm_set_ps1(p[2]);
-
- /* normalize r */
- rlen = _mm_rsqrt_ps(rx * rx + ry * ry + rz * rz + _mm_set_ps1(1e-16f));
- rx = rx * rlen;
- ry = ry * rlen;
- rz = rz * rlen;
-
- /* cross product */
- srx = _mm_shuffle_ps(rx, rx, _MM_SHUFFLE(0, 3, 2, 1));
- sry = _mm_shuffle_ps(ry, ry, _MM_SHUFFLE(0, 3, 2, 1));
- srz = _mm_shuffle_ps(rz, rz, _MM_SHUFFLE(0, 3, 2, 1));
-
- gx = sry * rz - srz * ry;
- gy = srz * rx - srx * rz;
- gz = srx * ry - sry * rx;
-
- /* normalize g */
- glen = _mm_rsqrt_ps(gx * gx + gy * gy + gz * gz + _mm_set_ps1(1e-16f));
- gx = gx * glen;
- gy = gy * glen;
- gz = gz * glen;
-
- /* compute angle */
- rcos = rx * srx + ry * sry + rz * srz;
- rcos = _mm_max_ps(_mm_min_ps(rcos, _mm_set_ps1(1.0f)), _mm_set_ps1(-1.0f));
-
- angle = sse_approx_cos(rcos);
- aresult = (_mm_set_ps1(n[0]) * gx + _mm_set_ps1(n[1]) * gy + _mm_set_ps1(n[2]) * gz) * angle;
-
- /* sum together */
- result = (fresult[0] + fresult[1] + fresult[2] + fresult[3]) * (0.5f / (float)M_PI);
- result = MAX2(result, 0.0f);
-
- return result;
-}
-
-#endif
-
-static void normalizef(float *n)
-{
- float d;
-
- d = dot_v3v3(n, n);
-
- if (d > 1.0e-35F) {
- d = 1.0f / sqrtf(d);
-
- n[0] *= d;
- n[1] *= d;
- n[2] *= d;
- }
-}
-
-/* TODO: exact duplicate of ff_quad_form_factor() in math_geom.c
- * why not de-duplicate? (also above helper func) */
-static float occ_quad_form_factor(const float p[3], const float n[3], const float q0[3], const float q1[3], const float q2[3], const float q3[3])
-{
- float r0[3], r1[3], r2[3], r3[3], g0[3], g1[3], g2[3], g3[3];
- float a1, a2, a3, a4, dot1, dot2, dot3, dot4, result;
-
- sub_v3_v3v3(r0, q0, p);
- sub_v3_v3v3(r1, q1, p);
- sub_v3_v3v3(r2, q2, p);
- sub_v3_v3v3(r3, q3, p);
-
- normalizef(r0);
- normalizef(r1);
- normalizef(r2);
- normalizef(r3);
-
- cross_v3_v3v3(g0, r1, r0); normalizef(g0);
- cross_v3_v3v3(g1, r2, r1); normalizef(g1);
- cross_v3_v3v3(g2, r3, r2); normalizef(g2);
- cross_v3_v3v3(g3, r0, r3); normalizef(g3);
-
- a1 = saacosf(dot_v3v3(r0, r1));
- a2 = saacosf(dot_v3v3(r1, r2));
- a3 = saacosf(dot_v3v3(r2, r3));
- a4 = saacosf(dot_v3v3(r3, r0));
-
- dot1 = dot_v3v3(n, g0);
- dot2 = dot_v3v3(n, g1);
- dot3 = dot_v3v3(n, g2);
- dot4 = dot_v3v3(n, g3);
-
- result = (a1 * dot1 + a2 * dot2 + a3 * dot3 + a4 * dot4) * 0.5f / (float)M_PI;
- result = MAX2(result, 0.0f);
-
- return result;
-}
-
static float occ_form_factor(OccFace *face, float *p, float *n)
{
ObjectInstanceRen *obi;
@@ -1190,16 +782,16 @@ static float occ_form_factor(OccFace *face, float *p, float *n)
mul_m4_v3(obi->mat, v3);
}
- if (occ_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3))
- contrib += occ_quad_form_factor(p, n, q0, q1, q2, q3);
+ if (form_factor_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3))
+ contrib += form_factor_quad(p, n, q0, q1, q2, q3);
if (vlr->v4) {
copy_v3_v3(v4, vlr->v4->co);
if (obi->flag & R_TRANSFORMED)
mul_m4_v3(obi->mat, v4);
- if (occ_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3))
- contrib += occ_quad_form_factor(p, n, q0, q1, q2, q3);
+ if (form_factor_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3))
+ contrib += form_factor_quad(p, n, q0, q1, q2, q3);
}
return contrib;
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 076bdaeaea7..ce18723b8c0 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -1457,7 +1457,7 @@ static void tag_scenes_for_render(Render *re)
Scene *scene = (Scene*) node->id;
if (scene->r.alphamode != R_ALPHAPREMUL) {
- BKE_reportf(re->reports, RPT_WARNING, "Setting scene %s alpha mode to Premul\n", scene->id.name + 2);
+ BKE_reportf(re->reports, RPT_WARNING, "Setting scene %s alpha mode to Premul", scene->id.name + 2);
/* also print, so feedback is immediate */
printf("2.66 versioning fix: setting scene %s alpha mode to Premul\n", scene->id.name + 2);
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index a1437b70090..57fe518dd46 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -308,7 +308,7 @@ void WM_gestures_remove(struct bContext *C);
void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op);
void WM_event_fileselect_event(struct bContext *C, void *ophandle, int eventval);
#ifndef NDEBUG
-void WM_event_print(struct wmEvent *event);
+void WM_event_print(const struct wmEvent *event);
#endif
void WM_operator_region_active_win_set(struct bContext *C);
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 6044e3fb771..173a8237c02 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -796,15 +796,18 @@ void wm_draw_update(bContext *C)
GPU_free_unused_buffers();
for (win = wm->windows.first; win; win = win->next) {
- int state = GHOST_GetWindowState(win->ghostwin);
-
- if (state == GHOST_kWindowStateMinimized) {
- /* do not update minimized windows, it gives issues on intel drivers (see [#33223])
- * anyway, it seems logical to skip update for invisible windows
- */
- continue;
+#ifdef WIN32
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin);
+
+ if (state == GHOST_kWindowStateMinimized) {
+ /* do not update minimized windows, it gives issues on intel drivers (see [#33223])
+ * anyway, it seems logical to skip update for invisible windows
+ */
+ continue;
+ }
}
-
+#endif
if (win->drawmethod != U.wmdrawmethod) {
wm_draw_window_clear(win);
win->drawmethod = U.wmdrawmethod;
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 206297d2c95..4e181ec930b 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -472,7 +472,7 @@ void WM_operator_region_active_win_set(bContext *C)
/* for debugging only, getting inspecting events manually is tedious */
#ifndef NDEBUG
-void WM_event_print(wmEvent *event)
+void WM_event_print(const wmEvent *event)
{
if (event) {
const char *unknown = "UNKNOWN";
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 79257479529..678c77d0d88 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -110,6 +110,8 @@
static GHash *global_ops_hash = NULL;
+#define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)")
+
/* ************ operator API, exported ********** */
@@ -163,7 +165,7 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
}
/* XXX All ops should have a description but for now allow them not to. */
- RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : N_("(undocumented operator)"));
+ RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
RNA_def_struct_identifier(ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
@@ -178,7 +180,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
opfunc(ot, userdata);
- RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : N_("(undocumented operator)"));
+ RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
RNA_def_struct_identifier(ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
@@ -375,7 +377,7 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam
ot->poll = NULL;
if (!ot->description) /* XXX All ops should have a description but for now allow them not to. */
- ot->description = N_("(undocumented operator)");
+ ot->description = UNDOCUMENTED_OPERATOR_TIP;
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
RNA_def_struct_identifier(ot->srna, ot->idname);
@@ -401,7 +403,7 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *),
ot->poll = NULL;
if (!ot->description)
- ot->description = N_("(undocumented operator)");
+ ot->description = UNDOCUMENTED_OPERATOR_TIP;
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
@@ -1846,6 +1848,7 @@ static void WM_OT_call_menu(wmOperatorType *ot)
{
ot->name = "Call Menu";
ot->idname = "WM_OT_call_menu";
+ ot->description = "Call (draw) a pre-defined menu";
ot->exec = wm_call_menu_exec;
ot->poll = WM_operator_winactive;
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index fd44f4a7169..b510956dbc1 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -252,8 +252,15 @@ static void playanim_toscreen(PlayAnimPict *picture, struct ImBuf *ibuf, int fon
glRasterPos2f(0.0f, 0.0f);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ fdrawcheckerboard(0.0f, 0.0f, ibuf->x, ibuf->y);
+
glDrawPixels(ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ glDisable(GL_BLEND);
+
pupdate_time();
if (picture && (g_WS.qual & (WS_QUAL_SHIFT | WS_QUAL_LMOUSE)) && (fontid != -1)) {